\r\n
\r\n {renderCart()}\r\n
\r\n \r\n ) : (\r\n
\r\n {renderCart()}\r\n
\r\n )\r\n ) : (\r\n
\r\n
\r\n \r\n \r\n \r\n {localization.text(\"history\",\"tobaccoReturn\")}\r\n
\r\n \r\n \r\n \r\n
\r\n );\r\n }\r\n}\r\n\r\nTobaccoReturnCart.propTypes = {\r\n localization: Localization.propTypes.isRequired,\r\n height: PropTypes.number.isRequired,\r\n deviceType: PropTypes.string.isRequired,\r\n tobacco: PropTypes.object.isRequired,\r\n addRemoveProductToTobaccoBag: PropTypes.func.isRequired,\r\n addTobaccoBag: PropTypes.func.isRequired,\r\n clearAll: PropTypes.func.isRequired,\r\n submitTobaccoReturn: PropTypes.func.isRequired,\r\n saveTobaccoReturn: PropTypes.func.isRequired,\r\n editTobacco: PropTypes.func.isRequired,\r\n edditSupplierBag: PropTypes.func.isRequired,\r\n validateBagNumber: PropTypes.func.isRequired,\r\n setModal: PropTypes.func.isRequired,\r\n pickupTobaccoDefault: PropTypes.bool.isRequired,\r\n freightChargePickupTobacco: PropTypes.number,\r\n width: PropTypes.number,\r\n};\r\n\r\nexport default TobaccoReturnCart;","import \"../../../../styles/historyDocumentsComponent.scss\";\r\n\r\nimport {Localization} from \"../../../common/util/localization.jsx\";\r\nimport PropTypes from \"prop-types\";\r\nimport React from \"react\";\r\nimport SearchBar from \"../order/SearchBar.jsx\";\r\nimport TobaccoDisplayCard from \"../product/TobaccoDisplayCard\";\r\nimport TobaccoReturnCart from \"./TobaccoReturnCart\";\r\nimport {scssVariables} from \"../../../common/util/config.jsx\";\r\n\r\nexport default class HistoryTobakComponent extends React.PureComponent {\r\n constructor(props) {\r\n super(props);\r\n\r\n this.filterSettings = {\r\n ReturnTobacco: true,\r\n OnlyCampaigns: false,\r\n OnlyNews: false,\r\n OnlyLastSold: false,\r\n };\r\n\r\n this.onEditFilter = this.onEditFilter.bind(this);\r\n this.loadMoreSearchResaults = this.loadMoreSearchResaults.bind(this);\r\n this.calculateCartHeight = this.calculateCartHeight.bind(this);\r\n this.calculateProductDisplayHeight = this.calculateProductDisplayHeight.bind(this);\r\n this.calculateProductDisplayWidth = this.calculateProductDisplayWidth.bind(this);\r\n }\r\n UNSAFE_componentWillMount() {\r\n const {\r\n clearQuery,\r\n getTobaccoSuppliers,\r\n prepareQueryOptions,\r\n getBoughtProducts,\r\n getNewProducts,\r\n productQuery,\r\n getSavedTobaccoReturn,\r\n } = this.props;\r\n clearQuery();\r\n getTobaccoSuppliers();\r\n prepareQueryOptions(true);\r\n getBoughtProducts();\r\n getNewProducts();\r\n getSavedTobaccoReturn();\r\n //\r\n this.onEditFilter({\r\n ...productQuery.filter,\r\n ProductGroupId: null,\r\n SupplierId: null,\r\n SortingColumn: null,\r\n ...this.filterSettings,\r\n searchString: \"\",\r\n });\r\n }\r\n onEditFilter(...args) {\r\n const {\r\n editQueryFilter,\r\n flowControl,\r\n } = this.props;\r\n flowControl(async () => {\r\n await editQueryFilter(...args);\r\n });\r\n }\r\n loadMoreSearchResaults() {\r\n const {\r\n deviceType,\r\n loadMoreSearchedProducts,\r\n } = this.props;\r\n const productDisplayHeight = this.calculateProductDisplayHeight();\r\n const rowsToLoad = (Math.floor(productDisplayHeight/parseInt(scssVariables.productItemHeight))+2);\r\n // rowsToLoad * itemsPerRow\r\n switch(deviceType){\r\n case \"xs\":\r\n case \"sm\":\r\n loadMoreSearchedProducts( rowsToLoad*2 );\r\n break;\r\n case \"md\":\r\n loadMoreSearchedProducts( rowsToLoad*4 );\r\n break;\r\n case \"lg\":\r\n loadMoreSearchedProducts( rowsToLoad*6 );\r\n break;\r\n default:\r\n loadMoreSearchedProducts( rowsToLoad*8 );\r\n break;\r\n }\r\n }\r\n\r\n calculateCartHeight() {\r\n const {\r\n deviceType,\r\n height,\r\n } = this.props;\r\n let productDisplayHeight = height;\r\n \r\n //page padding\r\n productDisplayHeight -= parseInt(scssVariables[`${deviceType}ContentPadding`])*2;\r\n //product display margin\r\n productDisplayHeight -= parseInt(scssVariables.cardMargin)*2;\r\n\r\n return productDisplayHeight;\r\n }\r\n\r\n calculateProductDisplayHeight() {\r\n const {\r\n deviceType,\r\n height,\r\n } = this.props;\r\n let productDisplayHeight = height;\r\n \r\n //page padding\r\n productDisplayHeight -= parseInt(scssVariables[`${deviceType}ContentPadding`])*2;\r\n\r\n if( deviceType===\"xs\" ) {\r\n //shopping cart in menu form\r\n productDisplayHeight -= parseInt(scssVariables.menuHeightWithBorder);\r\n } else {\r\n //title tab height\r\n productDisplayHeight -= parseInt(scssVariables.cardMargin)*2;\r\n productDisplayHeight -= parseInt(scssVariables.titleTabHeight);\r\n //searchbar height\r\n productDisplayHeight -= parseInt(scssVariables.cardMargin)*2;\r\n productDisplayHeight -= parseInt(scssVariables.menuHeightWithBorder);\r\n }\r\n //product display padding\r\n productDisplayHeight -= parseInt(scssVariables.cardMargin)*2;\r\n\r\n return productDisplayHeight;\r\n }\r\n\r\n calculateProductDisplayWidth() {\r\n const {\r\n deviceType,\r\n width,\r\n } = this.props;\r\n\r\n const isTinyDevice = deviceType==\"xs\" || deviceType==\"sm\";\r\n\r\n let productDisplayWidth = width;\r\n if( deviceType===\"xs\" ) {\r\n //page padding\r\n productDisplayWidth -= parseInt(scssVariables[`${deviceType}ContentPadding`])*2;\r\n //product display padding\r\n productDisplayWidth -= parseInt(scssVariables.cardMargin)*2;\r\n } else {\r\n //page padding\r\n productDisplayWidth -= parseInt(scssVariables[`${deviceType}ContentPadding`]);//no padding on the right side(Attached to it)\r\n //page padding\r\n productDisplayWidth -= parseInt(isTinyDevice ? scssVariables.shoppingCartWidthTiny : scssVariables.shoppingCartWidth);\r\n //product display padding\r\n productDisplayWidth -= parseInt(scssVariables.cardMargin)*2;\r\n }\r\n\r\n return productDisplayWidth;\r\n }\r\n\r\n render() {\r\n const {\r\n deviceType,\r\n localization,\r\n width,\r\n height,\r\n addRemoveProductToTobaccoBag,\r\n addTobaccoBag,\r\n clearAll,\r\n submitTobaccoReturn,\r\n editQueryFilter,\r\n productQuery,\r\n tobacco,\r\n editTobacco,\r\n edditSupplierBag,\r\n validateBagNumber,\r\n setModal,\r\n setDropDown,\r\n clearQuery,\r\n pickupTobaccoDefault,\r\n freightChargePickupTobacco,\r\n saveTobaccoReturn,\r\n } = this.props;\r\n\r\n const isTinyDevice = deviceType==\"xs\" || deviceType==\"sm\";\r\n const cartHeight = this.calculateCartHeight();\r\n const shiftCartUp = `-${parseInt(scssVariables.cardMargin)*2 + parseInt(scssVariables.titleTabHeight)}px`;\r\n const productDisplayHeight = this.calculateProductDisplayHeight();\r\n const productDisplayWidth = this.calculateProductDisplayWidth();\r\n const shiftCartToRight = scssVariables[`${deviceType}ContentPadding`];\r\n\r\n /* eslint-disable react/jsx-no-bind */\r\n return deviceType===\"xs\" ? (\r\n
\r\n ) : (\r\n
\r\n
\r\n \r\n \r\n
\r\n
\r\n \r\n
\r\n
\r\n );\r\n /* eslint-enable react/jsx-no-bind */\r\n }\r\n}\r\n\r\nHistoryTobakComponent.propTypes = {\r\n deviceType: PropTypes.string.isRequired,\r\n flowControl: PropTypes.func.isRequired,\r\n height: PropTypes.number.isRequired,\r\n width: PropTypes.number.isRequired,\r\n localization: Localization.propTypes.isRequired,\r\n signedInAs: PropTypes.string.isRequired,\r\n addRemoveProductToTobaccoBag: PropTypes.func.isRequired,\r\n addTobaccoBag: PropTypes.func.isRequired,\r\n clearAll: PropTypes.func.isRequired,\r\n submitTobaccoReturn: PropTypes.func.isRequired,\r\n saveTobaccoReturn: PropTypes.func.isRequired,\r\n editQueryFilter: PropTypes.func.isRequired,\r\n loadMoreSearchedProducts: PropTypes.func.isRequired,\r\n productQuery: PropTypes.object.isRequired,\r\n tobacco: PropTypes.object.isRequired,\r\n editTobacco: PropTypes.func.isRequired,\r\n edditSupplierBag: PropTypes.func.isRequired,\r\n validateBagNumber: PropTypes.func.isRequired,\r\n setModal: PropTypes.func.isRequired,\r\n setDropDown: PropTypes.func.isRequired,\r\n getTobaccoSuppliers: PropTypes.func.isRequired,\r\n getSavedTobaccoReturn: PropTypes.func.isRequired,\r\n prepareQueryOptions: PropTypes.func.isRequired,\r\n getBoughtProducts: PropTypes.func.isRequired,\r\n getNewProducts: PropTypes.func.isRequired,\r\n clearQuery: PropTypes.func.isRequired,\r\n pickupTobaccoDefault: PropTypes.bool.isRequired,\r\n freightChargePickupTobacco: PropTypes.number,\r\n};","import {addRemoveProductToTobaccoBag, addTobaccoBag, clearAll, edditSupplierBag, editTobacco, getSavedTobaccoReturn, getTobaccoSuppliers, saveTobaccoReturn, submitTobaccoReturn, validateBagNumber} from \"../../actions/history.js\";\r\nimport {clearQuery, editQueryFilter, loadMoreSearchedProducts, prepareQueryOptions} from \"../../actions/productQuery.js\";\r\nimport {getBoughtProducts, getNewProducts} from \"../../actions/productLists.js\";\r\nimport {setDropDown, setModal} from \"../../../common/actions/modal.js\";\r\n\r\nimport HistoryTobakComponent from \"../../components/history/HistoryTobakComponent.jsx\";\r\nimport {connect} from \"react-redux\";\r\nimport {createBoundFunction} from \"../../../common/util/reselect.js\";\r\nimport {createFlowControl} from \"../../../common/util/flowControl\";\r\nimport {createLocalization} from \"../../../common/util/localization.jsx\";\r\nimport {scssVariables} from \"../../../common/util/config.jsx\";\r\n\r\nconst mapStateToProps = () => {\r\n const flowControl = createFlowControl();\r\n\r\n return state => ({\r\n token: state.authentication.token,\r\n pickupTobaccoDefault: state.authentication.pickupTobaccoDefault,\r\n freightChargePickupTobacco: state.authentication.freightChargePickupTobacco,\r\n deviceType: state.view.deviceType,\r\n productQuery: state.productQuery,\r\n productImage: state.productImage,\r\n flowControl: flowControl,\r\n height: state.view.innerHeight-parseInt(scssVariables.menuHeight),\r\n width: state.view.innerWidth,\r\n localization: createLocalization(state),\r\n signedInAs: state.authentication.signedInAs,\r\n tobacco: state.history.tobacco,\r\n });\r\n};\r\n\r\nconst mapDispatchToProps = {\r\n addRemoveProductToTobaccoBag,\r\n loadMoreSearchedProducts,\r\n editQueryFilter,\r\n editTobacco,\r\n edditSupplierBag,\r\n validateBagNumber,\r\n addTobaccoBag,\r\n clearAll,\r\n submitTobaccoReturn,\r\n saveTobaccoReturn,\r\n setModal,\r\n setDropDown,\r\n getTobaccoSuppliers,\r\n prepareQueryOptions,\r\n getBoughtProducts,\r\n getNewProducts,\r\n clearQuery,\r\n getSavedTobaccoReturn,\r\n};\r\n\r\nconst myAddRemoveProductToTobaccoBag = createBoundFunction();\r\nconst myLoadMoreSearchedProducts = createBoundFunction();\r\nconst myEditQueryFilter = createBoundFunction();\r\nconst mySubmitTobaccoReturn = createBoundFunction();\r\n\r\nconst mergeProps = (stateProps, dispatchProps, ownProps) => ({\r\n ...stateProps,\r\n ...dispatchProps,\r\n ...ownProps,\r\n addRemoveProductToTobaccoBag: myAddRemoveProductToTobaccoBag((product, qty) => dispatchProps.addRemoveProductToTobaccoBag(product, qty)),\r\n loadMoreSearchedProducts: myLoadMoreSearchedProducts((noOfProducts) => dispatchProps.loadMoreSearchedProducts(stateProps.productQuery, stateProps.productImage, noOfProducts)),\r\n editQueryFilter: myEditQueryFilter( (change) => dispatchProps.editQueryFilter(stateProps.productQuery, stateProps.productImage, change, \r\n myLoadMoreSearchedProducts(() => dispatchProps.loadMoreSearchedProducts(stateProps.productQuery, stateProps.productImage, 50))\r\n )),\r\n submitTobaccoReturn: mySubmitTobaccoReturn( (callbackOnSuccess) => dispatchProps.submitTobaccoReturn(stateProps.token, callbackOnSuccess)),\r\n //saveTobaccoReturn: mySaveTobaccoReturn(() => dispatchProps.saveTobaccoReturn())\r\n});\r\n\r\nexport default connect(mapStateToProps, mapDispatchToProps, mergeProps)(HistoryTobakComponent);","import {Redirect, Route, Switch} from \"react-router-dom\";\r\nimport {TitleTab, TitleTabs} from \"../../../common/components/TitleTabs.jsx\";\r\n\r\nimport ContentWrapper from \"../../../common/components/ContentWrapper.jsx\";\r\nimport HistoryDocumentsContainer from \"../../containers/history/HistoryDocumentsContainer.jsx\";\r\nimport HistoryTobakContainer from \"../../containers/history/HistoryTobakContainer.jsx\";\r\nimport {Localization} from \"../../../common/util/localization.jsx\";\r\nimport PropTypes from \"prop-types\";\r\nimport React from \"react\";\r\n\r\nexport default class HistoryTabsComponent extends React.PureComponent {\r\n constructor(props) {\r\n super(props);\r\n\r\n this.extraStyles = {\r\n display: \"flex\",\r\n flexDirection: \"column\",\r\n overflowY: \"hidden\",\r\n };\r\n }\r\n\r\n render() {\r\n const {\r\n deviceType,\r\n height,\r\n localization,\r\n webEditOnlyTobacco\r\n } = this.props;\r\n\r\n var dummyclick = () => {};\r\n const isTinyDevice = deviceType==\"xs\";\r\n\r\n return (\r\n
\r\n {!isTinyDevice && (\r\n \r\n
\r\n { webEditOnlyTobacco ? : (\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n )}\r\n
\r\n
\r\n )}\r\n \r\n \r\n \r\n \r\n \r\n \r\n );\r\n }\r\n}\r\n\r\nHistoryTabsComponent.propTypes = {\r\n deviceType: PropTypes.string.isRequired,\r\n height: PropTypes.number.isRequired,\r\n webEditOnlyTobacco: PropTypes.bool.isRequired,\r\n localization: Localization.propTypes.isRequired\r\n};","import HistoryTabsComponent from \"../../components/history/HistoryTabsComponent.jsx\";\r\nimport {connect} from \"react-redux\";\r\nimport {createLocalization} from \"../../../common/util/localization.jsx\";\r\nimport {scssVariables} from \"../../../common/util/config.jsx\";\r\n\r\nconst mapStateToProps = state => ({\r\n deviceType: state.view.deviceType,\r\n height: state.view.innerHeight-parseInt(scssVariables.menuHeight),\r\n localization: createLocalization(state),\r\n webEditOnlyTobacco : state.authentication.webEditOnlyTobacco,\r\n});\r\n\r\nconst mapDispatchToProps = {\r\n};\r\n\r\nexport default connect(mapStateToProps, mapDispatchToProps)(HistoryTabsComponent);","import { downloadBlob, getBlob, postApi } from \"../../common/actions/net\";\r\nimport { messageType, pushSystemMessage } from \"../../common/actions/systemMessage.js\";\r\n\r\nimport { ContentTypes } from \"../../common/net/httpClient\";\r\nimport Logger from \"../../common/util/Logger.js\";\r\nimport { getApi } from \"../../common/actions/net.js\";\r\n\r\nexport const SET_HUB_OVERVIEW = \"SET_HUB_OVERVIEW\";\r\nexport const SORT_HUB_PRODUCTS = \"SORT_HUB_PRODUCTS\";\r\nexport const SORT_HUB_CUSTOMERS = \"SORT_HUB_CUSTOMERS\";\r\nexport const SET_SORTING_PRODUCTS = \"SET_SORTING_PRODUCTS\";\r\nexport const SET_SORTING_CUSTOMERS = \"SET_SORTING_CUSTOMERS\";\r\n\r\n\r\n/**\r\n * Gets hub overview\r\n * @param {number} hubId\r\n * @returns {func}\r\n */\r\nexport function getHubOverview(hubId) {\r\n return async dispatch => {\r\n try {\r\n // Call webApi to get a list of invoice groups\r\n const { payload } = await dispatch(\r\n getApi(\"FreshFoodHub/GetHubOverViewQuery\",\r\n {\r\n hubId : hubId,\r\n }));\r\n\r\n dispatch({\r\n type: SET_HUB_OVERVIEW,\r\n payload: payload\r\n });\r\n } catch (error) {\r\n dispatch(pushSystemMessage(error && error.message || \"Lasting av oversikt mislyktes\", messageType.error));\r\n Logger.error(error);\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Creates a pdf with overview of the selected date\r\n * @param {object} productionDate\r\n * @returns {func}\r\n */\r\nexport function showOverviewPdf(productionDate){\r\n return async (dispatch, getState) => {\r\n try {\r\n const state = getState();\r\n\r\n const blob = await getBlob(\"FreshFoodHub/GenerateOverviewPdf\", \r\n {\r\n hubId : state.authentication.hubId,\r\n productionDate : productionDate, \r\n }\r\n , state.authentication.token, ContentTypes.JSON, ContentTypes.PDF, false);\r\n downloadBlob(blob, `${productionDate}.pdf`, ContentTypes.PDF);\r\n\r\n } catch (error) {\r\n dispatch( pushSystemMessage(error.message || \"Fil ikke funnet\", messageType.error) );\r\n Logger.error(error);\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Creates a Excel file with overview of the selected date\r\n * @param {object} productionDate\r\n * @returns {func}\r\n */\r\nexport function showOverviewExcel(productionDate){\r\n return async (dispatch, getState) => {\r\n try {\r\n const state = getState();\r\n\r\n const blob = await getBlob(\"FreshFoodHub/GenerateOverviewExcel\", \r\n {\r\n hubId : state.authentication.hubId,\r\n productionDate : productionDate, \r\n }\r\n , state.authentication.token, ContentTypes.JSON, ContentTypes.EXCEL, false);\r\n downloadBlob(blob, `${productionDate}.xlsx`, ContentTypes.EXCEL);\r\n\r\n } catch (error) {\r\n dispatch( pushSystemMessage(error.message || \"Fil ikke funnet\", messageType.error) );\r\n Logger.error(error);\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Sets the sorting mode\r\n * @param {boolean} sorting \r\n * @returns {func}\r\n */\r\nexport function setProductsSortingMode(sorting){\r\n return async (dispatch) => {\r\n try {\r\n await dispatch({\r\n type: SET_SORTING_PRODUCTS,\r\n sorting : sorting,\r\n });\r\n } catch (error) {\r\n Logger.error(error);\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Sets the sorting mode\r\n * @param {boolean} sorting \r\n * @returns {func}\r\n */\r\nexport function setCustomersSortingMode(sorting){\r\n return async (dispatch) => {\r\n try {\r\n await dispatch({\r\n type: SET_SORTING_CUSTOMERS,\r\n sorting : sorting,\r\n });\r\n } catch (error) {\r\n Logger.error(error);\r\n }\r\n };\r\n}\r\n\r\n\r\n/**\r\n * Updates the sort order of the products\r\n * @param {number} index1 \r\n * @param {number} index2\r\n * @param {number} dateIndex\r\n * @param {boolean} thisWeek\r\n * @returns {func}\r\n */\r\nexport function updateHubProductSortOrder(index1, index2, dateIndex, thisWeek){\r\n return async (dispatch, getState) => {\r\n try {\r\n\r\n // Peform immediate update of state\r\n dispatch({\r\n type: SORT_HUB_PRODUCTS,\r\n index1: index1,\r\n index2: index2,\r\n dateIndex: dateIndex,\r\n thisWeek: thisWeek,\r\n });\r\n\r\n const state = getState();\r\n var products = thisWeek ?\r\n state.freshFoodHub.overview.currentWeekProductionDates[dateIndex].plannedProductsForDate :\r\n state.freshFoodHub.overview.nextWeekProductionDates[dateIndex].plannedProductsForDate;\r\n\r\n const sortCmd = {\r\n hubId: state.authentication.hubId,\r\n sortedProducts: products.map((p, index) => { return {productId: p.productId, newSortOrder: index }; })\r\n };\r\n\r\n // Call API to set new sort order\r\n await dispatch(postApi(\"FreshFoodHub/UpdateHubProductsSortOrder\", sortCmd)); \r\n\r\n } catch (error) {\r\n dispatch(pushSystemMessage(error && error.message || \"Sortering av varer for smørehub mislyktes\", messageType.error));\r\n Logger.error(error);\r\n } \r\n };\r\n}\r\n\r\n/**\r\n * Updates the sort order of the customers\r\n * @param {number} index1 \r\n * @param {number} index2\r\n * @param {number} dateIndex\r\n * @param {boolean} thisWeek\r\n * @returns {func}\r\n */\r\nexport function updateHubCustomerSortOrder(index1, index2, dateIndex, thisWeek){\r\n return async (dispatch, getState) => {\r\n try {\r\n\r\n // Peform immediate update of state\r\n dispatch({\r\n type: SORT_HUB_CUSTOMERS,\r\n index1: index1,\r\n index2: index2,\r\n dateIndex: dateIndex,\r\n thisWeek: thisWeek,\r\n });\r\n\r\n const state = getState();\r\n var customers = thisWeek ?\r\n state.freshFoodHub.overview.currentWeekProductionDates[dateIndex].customers :\r\n state.freshFoodHub.overview.nextWeekProductionDates[dateIndex].customers;\r\n\r\n const sortCmd = {\r\n hubId: state.authentication.hubId,\r\n sortedCustomers: customers.map((c, index) => { return {customerId: c.customerId, newSortOrder: index }; })\r\n };\r\n\r\n // Call API to set new sort order\r\n await dispatch(postApi(\"FreshFoodHub/UpdateHubCustomersSortOrder\", sortCmd)); \r\n\r\n } catch (error) {\r\n dispatch(pushSystemMessage(error && error.message || \"Sortering av kunnder for smørehub mislyktes\", messageType.error));\r\n Logger.error(error);\r\n } \r\n };\r\n}\r\n\r\n","import \"../../../styles/kjedeweb/chainScroll.scss\";\r\n\r\nimport PropTypes from \"prop-types\";\r\nimport React from \"react\";\r\nimport { scssVariables } from \"../../common/util/config\";\r\n\r\n/**\r\n * Returnerar Icon node med icon kod inkluderad\r\n * \r\n * @param {object} props\r\n * @returns {node}\r\n */\r\nclass Scroll extends React.Component {\r\n constructor(props) {\r\n super(props);\r\n\r\n this.state = {\r\n topShadow: false,\r\n bottomShadow: false,\r\n leftShadow: false,\r\n rightShadow: false,\r\n\r\n lastCloseToBottomScrollTop: -1,\r\n };\r\n\r\n this.listenToScroll = this.listenToScroll.bind(this);\r\n this.setRef = this.setRef.bind(this);\r\n }\r\n\r\n componentDidMount() {\r\n this.listenToScroll();\r\n }\r\n\r\n UNSAFE_componentWillReceiveProps() {\r\n this.listenToScroll();\r\n }\r\n\r\n listenToScroll() {\r\n const {\r\n shadowX,\r\n shadowY,\r\n style,\r\n onCloseToBottom,\r\n } = this.props;\r\n const element = this.element;\r\n //test what needs a shadow\r\n const needTopShadow = element.offsetHeight < element.scrollHeight && shadowY && element.scrollTop > 0;\r\n const needBottomShadow = element.offsetHeight < element.scrollHeight && shadowY && element.scrollTop + element.offsetHeight !== element.scrollHeight;\r\n const needleftShadow = element.offsetWidth < element.scrollWidth && shadowX && element.scrollLeft > 0;\r\n const needRightShadow = element.offsetWidth < element.scrollWidth && shadowX && element.scrollLeft + element.offsetWidth !== element.scrollWidth;\r\n let lastCloseToBottomScrollTop = this.state.lastCloseToBottomScrollTop;\r\n //If we are close to the bottom, do the callback(onCloseToBottom)\r\n if (onCloseToBottom && style && element.scrollTop !== this.state.lastCloseToBottomScrollTop && element.scrollHeight - element.scrollTop < (parseInt(style.height) * 1.5)) {\r\n //position is used to protect against unecesary callbacks on UNSAFE_componentWillReceiveProps()\r\n lastCloseToBottomScrollTop = element.scrollTop;\r\n\r\n //
Will be called multiple times on a single scroll\r\n clearTimeout(this.onScroll);\r\n this.onScroll = setTimeout(function () {\r\n onCloseToBottom();\r\n }, 50);\r\n }\r\n //update only if anything changed\r\n if (this.state.topShadow !== needTopShadow || this.state.bottomShadow !== needBottomShadow || this.state.leftShadow !== needleftShadow || this.state.rightShadow !== needRightShadow ||\r\n this.state.lastCloseToBottomScrollTop !== lastCloseToBottomScrollTop) {\r\n this.setState({\r\n topShadow: needTopShadow,\r\n bottomShadow: needBottomShadow,\r\n leftShadow: needleftShadow,\r\n rightShadow: needRightShadow,\r\n lastCloseToBottomScrollTop: lastCloseToBottomScrollTop,\r\n });\r\n }\r\n\r\n if (this.props.onScroll) {\r\n this.props.onScroll(element.scrollLeft, element.scrollTop);\r\n }\r\n }\r\n\r\n setRef(element) {\r\n this.element = element;\r\n }\r\n\r\n render() {\r\n const {\r\n children,\r\n style,\r\n className,\r\n shadowStyle,\r\n } = this.props;\r\n const {\r\n topShadow,\r\n bottomShadow,\r\n leftShadow,\r\n rightShadow,\r\n } = this.state;\r\n\r\n return (\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n {children}\r\n
\r\n
\r\n );\r\n }\r\n\r\n}\r\n\r\nScroll.propTypes = {\r\n children: PropTypes.node.isRequired,\r\n style: PropTypes.object,\r\n className: PropTypes.string,\r\n //If shadow should be used when overflowing on X\r\n shadowX: PropTypes.bool,\r\n //If shadow should be used when overflowing on Y\r\n shadowY: PropTypes.bool,\r\n //Style used by shadows\r\n shadowStyle: PropTypes.object,\r\n //Called when half the height is left on the scroll\r\n onCloseToBottom: PropTypes.func,\r\n onScroll: PropTypes.func\r\n};\r\n\r\nScroll.defaultProps = {\r\n shadowX: true,\r\n shadowY: true,\r\n};\r\n\r\nexport default Scroll;","import \"../../../styles/input.scss\";\r\n\r\nimport React, { Component } from \"react\";\r\n\r\nimport HubScroll from \"./HubScroll\";\r\nimport PropTypes from \"prop-types\";\r\n\r\nexport class HubTabList extends Component {\r\n constructor(props) {\r\n super(props);\r\n\r\n this.setElement = this.setElement.bind(this);\r\n }\r\n\r\n setElement(element) {\r\n this.element = element;\r\n }\r\n\r\n render() {\r\n const {\r\n tabIndexSelected,\r\n firstTabSelected,\r\n onTabClick\r\n } = this.props;\r\n const tabChildrenWithProps = [];\r\n const otherChildren = [];\r\n\r\n React.Children.forEach(this.props.children, function (child, index) {\r\n if (child) {\r\n if (child.type === HubTab) {\r\n tabChildrenWithProps.push(React.cloneElement(child, {\r\n tabSelected: (tabIndexSelected === index && firstTabSelected === undefined) || firstTabSelected === index,\r\n index: index,\r\n onTabClick: onTabClick,\r\n key: index\r\n }));\r\n } else {\r\n otherChildren.push(React.cloneElement(child, {\r\n key: index\r\n }));\r\n }\r\n }\r\n });\r\n return (\r\n
\r\n \r\n {tabChildrenWithProps}\r\n \r\n {otherChildren}\r\n
\r\n );\r\n }\r\n}\r\nHubTabList.propTypes = {\r\n children: PropTypes.node.isRequired,\r\n tabIndexSelected: PropTypes.number,\r\n firstTabSelected: PropTypes.number,\r\n // Private: Tabs will use this\r\n onTabClick: PropTypes.func,\r\n};\r\n\r\n\r\nexport class HubTab extends Component {\r\n constructor(props) {\r\n super(props);\r\n\r\n this.onTabClick = this.onTabClick.bind(this);\r\n }\r\n\r\n onTabClick(e) {\r\n const {\r\n onTabClick,\r\n onClick,\r\n index,\r\n disabled\r\n } = this.props;\r\n if (onTabClick && !disabled) {\r\n onTabClick(e, index);\r\n }\r\n if (onClick && !disabled) {\r\n onClick(index);\r\n }\r\n }\r\n\r\n render() {\r\n const {\r\n tabSelected,\r\n label,\r\n logoUrl,\r\n disabled,\r\n } = this.props;\r\n return (\r\n
\r\n
\r\n {logoUrl && (\r\n
\r\n

\r\n
\r\n )}\r\n {label}\r\n
\r\n
\r\n );\r\n }\r\n}\r\nHubTab.propTypes = {\r\n tabSelected: PropTypes.bool,\r\n disabled: PropTypes.bool,\r\n label: PropTypes.string.isRequired,\r\n // Private: TabList will use this\r\n onTabClick: PropTypes.func,\r\n // Use this if you want a callback when tab is clicked\r\n onClick: PropTypes.func,\r\n index: PropTypes.number,\r\n id: PropTypes.string,\r\n logoUrl: PropTypes.string\r\n};\r\nHubTab.defaultProps = {\r\n tabSelected: false\r\n};\r\n\r\nexport class HubTabPanel extends Component {\r\n render() {\r\n const {\r\n children,\r\n overflowHidden,\r\n onScroll\r\n } = this.props;\r\n\r\n return (\r\n
\r\n {children}\r\n
\r\n );\r\n }\r\n}\r\nHubTabPanel.propTypes = {\r\n children: PropTypes.node.isRequired,\r\n onScroll: PropTypes.func,\r\n overflowHidden: PropTypes.bool\r\n};\r\n\r\nexport class HubTabs extends Component {\r\n constructor(props) {\r\n super(props);\r\n\r\n let selectIndex = 0;\r\n let count = 0;\r\n if (props.startTabId) {\r\n React.Children.forEach(props.children, child => {\r\n if (child.type === HubTabList) {\r\n const tabs = child.props.children;\r\n for (let i = 0; i < tabs.length; i++) {\r\n if (tabs[i].props && tabs[i].props.id === props.startTabId.toString()) {\r\n selectIndex = count;\r\n }\r\n count += tabs[i].type === HubTab ? 1 : 0;\r\n }\r\n }\r\n });\r\n }\r\n this.state = {\r\n firstTabSelected: props.startTabId,\r\n tabIndexSelected: selectIndex,\r\n };\r\n\r\n this.onTabClick = this.onTabClick.bind(this);\r\n }\r\n\r\n onTabClick(e, index) {\r\n const {\r\n tabClick,\r\n } = this.props;\r\n e.stopPropagation();\r\n \r\n this.setState({\r\n tabIndexSelected: index,\r\n firstTabSelected: undefined,\r\n });\r\n\r\n if (tabClick){\r\n tabClick(e, index);\r\n }\r\n }\r\n\r\n\r\n render() {\r\n const childrenWithProps = [];\r\n let count = 0;\r\n //prepare the children with needed props\r\n React.Children.forEach(this.props.children, child => {\r\n //if the child is a TabList button on the otop\r\n if (child.type === HubTabList) {\r\n childrenWithProps[childrenWithProps.length] = React.cloneElement(child, {\r\n tabIndexSelected: this.state.tabIndexSelected,\r\n firstTabSelected: this.state.firstTabSelected,\r\n onTabClick: this.onTabClick,\r\n key: -1\r\n });\r\n }\r\n //if it is a panel with all the content\r\n else {\r\n if (this.state.tabIndexSelected === count) {\r\n childrenWithProps[childrenWithProps.length] = React.cloneElement(child, {\r\n key: count\r\n });\r\n }\r\n count++;\r\n }\r\n });\r\n return (\r\n
\r\n {childrenWithProps}\r\n
\r\n );\r\n }\r\n}\r\n\r\nHubTabs.propTypes = {\r\n children: PropTypes.node.isRequired,\r\n startTabId: PropTypes.number,\r\n tabClick: PropTypes.func,\r\n};\r\n\r\nHubTabs.defaultProps = {\r\n};\r\n","import \"../../../styles/kjedeweb/singleChainProductListItem.scss\";\r\n\r\nimport { Localization } from \"../../common/util/localization.jsx\";\r\nimport PropTypes from \"prop-types\";\r\nimport React from \"react\";\r\nimport ResponsiveColumn from \"../../common/components/ResponsiveColumn\";\r\nimport ResponsiveRows from \"../../common/components/ResponsiveRows\";\r\n\r\nexport class HubOverviewListHeader extends React.PureComponent {\r\n render() {\r\n const {\r\n localization,\r\n customers,\r\n } = this.props;\r\n\r\n return (\r\n
\r\n
\r\n
\r\n
\r\n
\r\n \r\n \r\n {localization.text(\"hub\", \"overview\", \"description\")}\r\n
\r\n \r\n \r\n \r\n {localization.text(\"hub\", \"overview\", \"plannedQty\")}\r\n
\r\n \r\n \r\n
\r\n
\r\n {customers.map((cus,idx) => ( \r\n
\r\n {cus.departmentStoreNo}\r\n
\r\n ))}\r\n
\r\n \r\n
\r\n
\r\n
\r\n );\r\n }\r\n}\r\n\r\nHubOverviewListHeader.propTypes = {\r\n localization: Localization.propTypes.isRequired,\r\n customers: PropTypes.array.isRequired,\r\n};\r\n\r\nexport class HubOverviewListItem extends React.PureComponent {\r\n constructor(props) {\r\n super(props);\r\n\r\n }\r\n\r\n render() {\r\n const {\r\n product,\r\n style,\r\n } = this.props;\r\n\r\n return (\r\n
\r\n
\r\n
\r\n
\r\n
\r\n \r\n \r\n
\r\n {product.productName}\r\n
\r\n
\r\n \r\n \r\n \r\n
\r\n {product.qtyToBeProduced}\r\n
\r\n
\r\n \r\n \r\n
\r\n
\r\n {product.customers.map((cus,idx) => ( \r\n
\r\n {cus.qtyToBeProduced}\r\n
\r\n ))} \r\n
\r\n
\r\n
\r\n
\r\n );\r\n }\r\n}\r\n\r\nHubOverviewListItem.propTypes = {\r\n localization: Localization.propTypes.isRequired,\r\n product: PropTypes.object,\r\n style: PropTypes.object,\r\n};\r\n\r\nHubOverviewListItem.defaultProps = {\r\n};","import \"../../../styles/hubweb/hubProductView.scss\";\r\nimport \"../../../styles/page/shoppingCart.scss\";\r\n\r\nimport { DragDropContext, Draggable, Droppable } from \"react-beautiful-dnd\";\r\n\r\nimport { Localization } from \"../../common/util/localization.jsx\";\r\nimport PropTypes from \"prop-types\";\r\nimport React from \"react\";\r\nimport ResponsiveColumn from \"../../common/components/ResponsiveColumn\";\r\nimport ResponsiveRows from \"../../common/components/ResponsiveRows\";\r\n\r\nexport class HubCustomerListHeader extends React.PureComponent {\r\n render() {\r\n const {\r\n localization,\r\n } = this.props;\r\n\r\n return (\r\n
\r\n
\r\n
\r\n
\r\n
\r\n \r\n \r\n {localization.text(\"hub\", \"production\", \"departmentStoreNo\")}\r\n
\r\n \r\n \r\n \r\n {localization.text(\"hub\", \"production\", \"customerName\")}\r\n
\r\n \r\n \r\n
\r\n
\r\n
\r\n
\r\n );\r\n }\r\n}\r\n\r\nHubCustomerListHeader.propTypes = {\r\n localization: Localization.propTypes.isRequired,\r\n};\r\n\r\nclass HubCustomerListItem extends React.PureComponent {\r\n constructor(props) {\r\n super(props);\r\n }\r\n\r\n render() {\r\n const {\r\n customer,\r\n style,\r\n } = this.props;\r\n\r\n return (\r\n
\r\n
\r\n
\r\n
\r\n
\r\n \r\n \r\n
\r\n {customer.departmentStoreNo}\r\n
\r\n
\r\n \r\n \r\n \r\n
\r\n {customer.customerName}\r\n
\r\n
\r\n \r\n \r\n
\r\n
\r\n
\r\n
\r\n );\r\n }\r\n}\r\nHubCustomerListItem.propTypes = {\r\n customer: PropTypes.object,\r\n style: PropTypes.object,\r\n};\r\n\r\n\r\n\r\nclass HubCustomerSortingList extends React.PureComponent {\r\n constructor(props) {\r\n super(props);\r\n this.createDraggableCustomers = this.createDraggableCustomers.bind(this);\r\n this.prepareDraggableItems = this.prepareDraggableItems.bind(this);\r\n this.onDragEnd = this.onDragEnd.bind(this);\r\n }\r\n\r\n onDragEnd(result) {\r\n const {\r\n updateHubCustomerSortOrder,\r\n dateIndex,\r\n thisWeek,\r\n } = this.props;\r\n\r\n // dropped outside the list\r\n if (!result.destination) {\r\n return;\r\n }\r\n\r\n //swap places\r\n updateHubCustomerSortOrder(result.source.index, result.destination.index, dateIndex, thisWeek);\r\n }\r\n\r\n prepareDraggableItems() {\r\n const drag = (\r\n
\r\n \r\n {(provided) => (\r\n \r\n {\r\n this.createDraggableCustomers()\r\n }\r\n {provided.placeholder}\r\n
\r\n )}\r\n \r\n );\r\n return drag;\r\n }\r\n\r\n createDraggableCustomers() {\r\n const {\r\n customers,\r\n } = this.props;\r\n\r\n const retNodes = [];\r\n\r\n for (let i = 0; i < customers.length; i++) {\r\n const customerId = customers[i].customerId;\r\n\r\n retNodes[retNodes.length] = (\r\n
\r\n {(provided, snapshot) => (\r\n \r\n \r\n
\r\n )}\r\n \r\n );\r\n }\r\n return retNodes;\r\n }\r\n\r\n\r\n render() {\r\n const {\r\n localization,\r\n height,\r\n } = this.props;\r\n\r\n const nodes = this.prepareDraggableItems();\r\n\r\n return (\r\n
\r\n \r\n \r\n
\r\n \r\n {nodes}\r\n
\r\n \r\n \r\n );\r\n }\r\n}\r\nHubCustomerSortingList.propTypes = {\r\n localization: Localization.propTypes.isRequired,\r\n customers: PropTypes.array.isRequired,\r\n updateHubCustomerSortOrder: PropTypes.func.isRequired,\r\n dateIndex: PropTypes.number.isRequired,\r\n thisWeek: PropTypes.bool.isRequired,\r\n height: PropTypes.number,\r\n};\r\n\r\nexport default HubCustomerSortingList;","import \"../../../styles/productView.scss\";\r\nimport \"../../../styles/productViewListItem.scss\";\r\n\r\nimport { DragDropContext, Draggable, Droppable } from \"react-beautiful-dnd\";\r\nimport { HubOverviewListHeader, HubOverviewListItem } from \"./HubOverviewListItem.jsx\";\r\nimport Icon, { iconTypes } from \"../../common/components/Icon\";\r\n\r\nimport HubCustomerSortingList from \"./HubCustomerSortingList\";\r\nimport { Localization } from \"../../common/util/localization.jsx\";\r\nimport PropTypes from \"prop-types\";\r\nimport React from \"react\";\r\n\r\nclass HubOverviewList extends React.PureComponent {\r\n constructor(props) {\r\n super(props);\r\n\r\n this.state = {\r\n width: null,\r\n };\r\n this.containerNode = null;\r\n\r\n this.createDraggableProducts = this.createDraggableProducts.bind(this);\r\n this.prepareItems = this.prepareItems.bind(this);\r\n this.prepareDraggableItems = this.prepareDraggableItems.bind(this);\r\n this.onDragEnd = this.onDragEnd.bind(this);\r\n this.sortProducts = this.sortProducts.bind(this);\r\n this.sortCustomers = this.sortCustomers.bind(this);\r\n }\r\n\r\n onDragEnd(result) {\r\n const {\r\n updateHubProductSortOrder,\r\n dateIndex,\r\n thisWeek,\r\n } = this.props;\r\n\r\n // dropped outside the list\r\n if (!result.destination) {\r\n return;\r\n }\r\n\r\n //swap places\r\n updateHubProductSortOrder(result.source.index, result.destination.index, dateIndex, thisWeek);\r\n }\r\n\r\n prepareDraggableItems() {\r\n const drag = (\r\n
\r\n \r\n {(provided) => (\r\n \r\n {\r\n this.createDraggableProducts()\r\n }\r\n {provided.placeholder}\r\n
\r\n )}\r\n \r\n );\r\n return drag;\r\n }\r\n\r\n createDraggableProducts() {\r\n const {\r\n list,\r\n localization,\r\n setModal,\r\n } = this.props;\r\n\r\n const retNodes = [];\r\n\r\n for (let i = 0; i < list.length; i++) {\r\n const productId = list[i].productId;\r\n\r\n retNodes[retNodes.length] = (\r\n
\r\n {(provided, snapshot) => (\r\n \r\n \r\n
\r\n )}\r\n \r\n );\r\n }\r\n return retNodes;\r\n }\r\n\r\n prepareItems() {\r\n const {\r\n list,\r\n localization,\r\n setModal,\r\n } = this.props;\r\n\r\n const retNodes = [];\r\n\r\n for (let i = 0; i < list.length; i++) {\r\n retNodes[retNodes.length] = (\r\n
);\r\n }\r\n return retNodes;\r\n }\r\n\r\n sortProducts(){\r\n this.props.setProductsSortingMode(!this.props.sortProducts);\r\n }\r\n\r\n sortCustomers() {\r\n this.props.setCustomersSortingMode(!this.props.sortCustomers);\r\n }\r\n\r\n\r\n render() {\r\n const {\r\n localization,\r\n height,\r\n customers,\r\n sortProducts,\r\n sortCustomers,\r\n updateHubCustomerSortOrder,\r\n dateIndex,\r\n thisWeek,\r\n } = this.props;\r\n\r\n const nodes = sortProducts ? this.prepareDraggableItems() : this.prepareItems();\r\n\r\n return (\r\n
\r\n { sortCustomers ? (\r\n \r\n ) : (\r\n \r\n
\r\n \r\n
\r\n
\r\n {nodes}\r\n
\r\n
\r\n )}\r\n \r\n \r\n \r\n
\r\n );\r\n }\r\n}\r\n\r\nHubOverviewList.propTypes = {\r\n height: PropTypes.number,\r\n width: PropTypes.number,\r\n // If true a loading icon will be displayed\r\n isLoading: PropTypes.bool,\r\n // An array of products to be displayed\r\n list: PropTypes.array.isRequired,\r\n customers: PropTypes.array.isRequired,\r\n localization: Localization.propTypes.isRequired,\r\n setModal: PropTypes.func.isRequired,\r\n style: PropTypes.object,\r\n updateHubProductSortOrder: PropTypes.func.isRequired,\r\n updateHubCustomerSortOrder: PropTypes.func.isRequired,\r\n sortProducts: PropTypes.bool.isRequired,\r\n sortCustomers: PropTypes.bool.isRequired,\r\n setProductsSortingMode: PropTypes.func.isRequired,\r\n setCustomersSortingMode : PropTypes.func.isRequired,\r\n dateIndex: PropTypes.number,\r\n thisWeek: PropTypes.bool,\r\n};\r\n\r\nexport default HubOverviewList;\r\n","import \"../../../styles/hubweb/overview.scss\";\r\n\r\nimport { HubTab, HubTabList, HubTabPanel, HubTabs } from \"./HubTabs.jsx\";\r\nimport Icon, { iconTypes } from \"../../common/components/Icon.jsx\";\r\n\r\nimport HubOverviewList from \"./HubOverviewList.jsx\";\r\nimport { Localization } from \"../../common/util/localization.jsx\";\r\nimport PropTypes from \"prop-types\";\r\nimport React from \"react\";\r\nimport moment from \"moment\";\r\nimport { scssVariables } from \"../../common/util/config.jsx\";\r\nimport { withRouter } from \"react-router-dom\";\r\n\r\nclass HubOverviewCard extends React.PureComponent {\r\n constructor(props) {\r\n super(props);\r\n\r\n this.swallowOnClick = this.swallowOnClick.bind(this);\r\n this.onShowPreviousWeek = this.onShowPreviousWeek.bind(this);\r\n this.onShowNextWeek = this.onShowNextWeek.bind(this);\r\n this.calculateInternalPanelHeight = this.calculateInternalPanelHeight.bind(this);\r\n this.onClickShowPdf = this.onClickShowPdf.bind(this);\r\n this.onClickShowExcel = this.onClickShowExcel.bind(this);\r\n this.shouldComponentRender = this.shouldComponentRender.bind(this);\r\n \r\n this.state = { thisWeekSelected: true, start: true, tabIndexSelected: 0 };\r\n this.tabClick = this.tabClick.bind(this);\r\n }\r\n\r\n UNSAFE_componentWillReceiveProps(nextProps) {\r\n var firstTab = nextProps.overview.currentWeekProductionDates.findIndex((date) => date.isCurrentDate);\r\n\r\n if (firstTab >= 0 && this.state.start)\r\n {\r\n this.setState({ tabIndexSelected: firstTab, start: false });\r\n } \r\n }\r\n\r\n swallowOnClick(event) {\r\n event.stopPropagation();\r\n event.preventDefault();\r\n }\r\n\r\n onShowPreviousWeek()\r\n {\r\n this.setState({ thisWeekSelected: true });\r\n }\r\n\r\n onShowNextWeek()\r\n {\r\n this.setState({ thisWeekSelected: false });\r\n }\r\n\r\n calculateInternalPanelHeight() {\r\n let tabPanelHeight = this.props.height;\r\n\r\n // Remove height of tab panel\r\n tabPanelHeight -= parseInt(scssVariables.menuHeightWithBorder) + 45;\r\n return tabPanelHeight;\r\n }\r\n\r\n shouldComponentRender = () => this.props.overview.currentWeekNo;\r\n\r\n tabClick(e, index) {\r\n e.stopPropagation();\r\n \r\n this.setState({\r\n tabIndexSelected: index,\r\n });\r\n\r\n }\r\n\r\n onClickShowPdf() {\r\n const {\r\n overview,\r\n showOverviewPdf,\r\n } = this.props;\r\n\r\n const selectedDates = this.state.thisWeekSelected ? overview.currentWeekProductionDates : overview.nextWeekProductionDates;\r\n const selectedDate = selectedDates[this.state.tabIndexSelected].productionDate;\r\n\r\n showOverviewPdf(selectedDate);\r\n }\r\n\r\n onClickShowExcel() {\r\n const {\r\n overview,\r\n showOverviewExcel,\r\n } = this.props;\r\n\r\n const selectedDates = this.state.thisWeekSelected ? overview.currentWeekProductionDates : overview.nextWeekProductionDates;\r\n const selectedDate = selectedDates[this.state.tabIndexSelected].productionDate;\r\n\r\n showOverviewExcel(selectedDate);\r\n }\r\n\r\n render() {\r\n const {\r\n height,\r\n localization,\r\n setModal,\r\n width,\r\n overview,\r\n updateHubProductSortOrder,\r\n updateHubCustomerSortOrder,\r\n setProductsSortingMode,\r\n setCustomersSortingMode,\r\n sortProducts,\r\n sortCustomers,\r\n } = this.props;\r\n\r\n // Check if data has been loaded, if not just return empty component\r\n if (!this.shouldComponentRender()) return
;\r\n\r\n const tabPanelHeight = this.calculateInternalPanelHeight();\r\n\r\n const selectedDates = this.state.thisWeekSelected ? overview.currentWeekProductionDates : overview.nextWeekProductionDates;\r\n const selectedWeekNo = this.state.thisWeekSelected ? overview.currentWeekNo : overview.nextWeekNo;\r\n\r\n if(selectedDates.length > 0)\r\n {\r\n var firstTab = selectedDates.findIndex((date) => date.isCurrentDate);\r\n \r\n var firstDateOfWeek = moment(selectedDates[0].productionDate).format(\"DD.MM.YYYY\");\r\n var lastDateOfWeek = moment(selectedDates[selectedDates.length-1].productionDate).format(\"DD.MM.YYYY\");\r\n }\r\n\r\n return (\r\n
\r\n
\r\n
\r\n
{`Uke${selectedWeekNo} : ${firstDateOfWeek} - ${lastDateOfWeek} `}
\r\n
\r\n
\r\n \r\n \r\n
\r\n
\r\n
\r\n \r\n {selectedDates.map((date, idx) => (\r\n \r\n ))}\r\n \r\n \r\n {selectedDates.map((date, idx) => (\r\n \r\n \r\n \r\n ))}\r\n \r\n \r\n
\r\n );\r\n }\r\n}\r\n\r\nHubOverviewCard.propTypes = {\r\n deviceType: PropTypes.string.isRequired,\r\n height: PropTypes.number.isRequired,\r\n history: PropTypes.object.isRequired,\r\n localization: Localization.propTypes.isRequired,\r\n location: PropTypes.object.isRequired,\r\n setModal: PropTypes.func.isRequired,\r\n width: PropTypes.number.isRequired,\r\n overview: PropTypes.object.isRequired,\r\n showOverviewPdf: PropTypes.func.isRequired,\r\n showOverviewExcel: PropTypes.func.isRequired,\r\n updateHubProductSortOrder: PropTypes.func.isRequired,\r\n updateHubCustomerSortOrder: PropTypes.func.isRequired,\r\n setProductsSortingMode:PropTypes.func.isRequired,\r\n setCustomersSortingMode:PropTypes.func.isRequired,\r\n sortProducts: PropTypes.bool.isRequired,\r\n sortCustomers : PropTypes.bool.isRequired,\r\n};\r\n\r\nHubOverviewCard.defaultProps = {\r\n currentView: \"all\",\r\n};\r\nexport default withRouter(HubOverviewCard);\r\n","import \"../../../styles/page/order.scss\";\r\n\r\nimport { TitleTab, TitleTabs } from \"../../common/components/TitleTabs.jsx\";\r\n\r\nimport ContentWrapper from \"../../common/components/ContentWrapper\";\r\nimport HubOverviewCard from \"./HubOverviewCard.jsx\";\r\nimport { Localization } from \"../../common/util/localization.jsx\";\r\nimport PropTypes from \"prop-types\";\r\nimport React from \"react\";\r\nimport { scssVariables } from \"../../common/util/config.jsx\";\r\nimport { withRouter } from \"react-router-dom\";\r\n\r\nclass HubOverviewPage extends React.PureComponent {\r\n constructor(props) {\r\n super(props);\r\n\r\n this.calculateProductDisplayHeight = this.calculateProductDisplayHeight.bind(this);\r\n this.calculateProductDisplayWidth = this.calculateProductDisplayWidth.bind(this);\r\n //this.loadMoreSearchResults = this.loadMoreSearchResults.bind(this);\r\n }\r\n\r\n UNSAFE_componentWillMount() {\r\n const {\r\n getHubOverview,\r\n } = this.props;\r\n getHubOverview();\r\n }\r\n\r\n calculateProductDisplayHeight() {\r\n const {\r\n deviceType,\r\n height,\r\n } = this.props;\r\n let productDisplayHeight = height;\r\n\r\n // Page padding\r\n productDisplayHeight -= parseInt(scssVariables[`${deviceType}ContentPadding`]) * 2;\r\n\r\n if (deviceType === \"xs\") {\r\n productDisplayHeight -= parseInt(scssVariables.menuHeightWithBorder);\r\n } else {\r\n // Title tab height\r\n productDisplayHeight -= parseInt(scssVariables.cardMargin) * 2;\r\n productDisplayHeight -= parseInt(scssVariables.titleTabHeight);\r\n\r\n // Search bar height\r\n productDisplayHeight -= parseInt(scssVariables.cardMargin) * 2;\r\n productDisplayHeight -= parseInt(scssVariables.menuHeightWithBorder);\r\n }\r\n\r\n // Product display padding\r\n productDisplayHeight -= parseInt(scssVariables.cardMargin) * 2;\r\n\r\n return productDisplayHeight;\r\n }\r\n\r\n calculateProductDisplayWidth() {\r\n const {\r\n deviceType,\r\n width,\r\n } = this.props;\r\n\r\n let productDisplayWidth = width;\r\n if (deviceType === \"xs\") {\r\n // Page padding\r\n productDisplayWidth -= parseInt(scssVariables[`${deviceType}ContentPadding`]) * 2;\r\n\r\n // Product display padding\r\n productDisplayWidth -= parseInt(scssVariables.cardMargin) * 2;\r\n } else {\r\n // Page padding\r\n productDisplayWidth -= parseInt(scssVariables[`${deviceType}ContentPadding`]); // No padding on the right side(Attached to it)\r\n\r\n // Product display padding\r\n productDisplayWidth -= parseInt(scssVariables.cardMargin) * 2;\r\n }\r\n\r\n return productDisplayWidth;\r\n }\r\n\r\n\r\n render() {\r\n const {\r\n deviceType,\r\n height,\r\n localization,\r\n setModal,\r\n overview,\r\n showOverviewPdf,\r\n showOverviewExcel,\r\n updateHubProductSortOrder,\r\n updateHubCustomerSortOrder,\r\n setProductsSortingMode,\r\n setCustomersSortingMode,\r\n sortProducts,\r\n sortCustomers,\r\n } = this.props;\r\n\r\n const productDisplayHeight = this.calculateProductDisplayHeight();\r\n const productDisplayWidth = this.calculateProductDisplayWidth();\r\n\r\n return (\r\n
\r\n \r\n
\r\n \r\n \r\n \r\n \r\n \r\n
\r\n
\r\n );\r\n }\r\n}\r\n\r\nHubOverviewPage.propTypes = {\r\n deviceType: PropTypes.string.isRequired,\r\n height: PropTypes.number.isRequired,\r\n localization: Localization.propTypes.isRequired,\r\n setModal: PropTypes.func.isRequired,\r\n setDropDown: PropTypes.func.isRequired,\r\n startView: PropTypes.string.isRequired,\r\n width: PropTypes.number.isRequired,\r\n getHubOverview: PropTypes.func.isRequired,\r\n overview: PropTypes.object.isRequired,\r\n showOverviewPdf: PropTypes.func.isRequired,\r\n showOverviewExcel: PropTypes.func.isRequired,\r\n updateHubProductSortOrder: PropTypes.func.isRequired,\r\n updateHubCustomerSortOrder: PropTypes.func.isRequired,\r\n setProductsSortingMode: PropTypes.func.isRequired,\r\n setCustomersSortingMode: PropTypes.func.isRequired,\r\n sortProducts : PropTypes.bool.isRequired,\r\n sortCustomers : PropTypes.bool.isRequired,\r\n};\r\n\r\nexport default withRouter(HubOverviewPage);\r\n","import { getHubOverview, setCustomersSortingMode, setProductsSortingMode, showOverviewExcel, showOverviewPdf, updateHubCustomerSortOrder, updateHubProductSortOrder } from \"../actions/hubOverview.js\";\r\nimport { setDropDown, setModal } from \"../../common/actions/modal\";\r\n\r\nimport HubOverviewPage from \"../components/HubOverviewPage.jsx\";\r\nimport { connect } from \"react-redux\";\r\nimport { createBoundFunction } from \"../../common/util/reselect.js\";\r\nimport { createFlowControl } from \"../../common/util/flowControl\";\r\nimport { createLocalization } from \"../../common/util/localization.jsx\";\r\nimport { scssVariables } from \"../../common/util/config.jsx\";\r\n\r\nconst mapStateToProps = () => {\r\n const flowControl = createFlowControl();\r\n const flowControlCounter = createFlowControl();\r\n\r\n return (state, ownProps) => ({\r\n deviceType: state.view.deviceType,\r\n flowControl: flowControl,\r\n flowControlCounter: flowControlCounter,\r\n height: state.view.innerHeight - parseInt(scssVariables.menuHeight),\r\n localization: createLocalization(state),\r\n startView: ownProps.match.params.view || \"all\",\r\n width: state.view.innerWidth,\r\n hubId : state.authentication.hubId,\r\n overview: state.freshFoodHub.overview,\r\n sortProducts: state.freshFoodHub.productsSorting,\r\n sortCustomers: state.freshFoodHub.customersSorting,\r\n });\r\n};\r\n\r\nconst mapDispatchToProps = {\r\n getHubOverview,\r\n setModal,\r\n setDropDown,\r\n showOverviewPdf,\r\n showOverviewExcel,\r\n updateHubProductSortOrder,\r\n updateHubCustomerSortOrder,\r\n setProductsSortingMode,\r\n setCustomersSortingMode,\r\n};\r\n\r\nconst myGetHubOverView = createBoundFunction();\r\n\r\nconst mergeProps = (stateProps, dispatchProps, ownProps) => ({\r\n ...stateProps,\r\n ...dispatchProps,\r\n ...ownProps,\r\n getHubOverview: myGetHubOverView(() => dispatchProps.getHubOverview(stateProps.hubId)), \r\n});\r\n\r\nexport default connect(mapStateToProps, mapDispatchToProps, mergeProps)(HubOverviewPage);\r\n","import { downloadBlob, getBlob } from \"../../common/actions/net\";\r\nimport { getApi, postApi } from \"../../common/actions/net.js\";\r\nimport { messageType, pushSystemMessage } from \"../../common/actions/systemMessage.js\";\r\n\r\nimport { ContentTypes } from \"../../common/net/httpClient\";\r\nimport Logger from \"../../common/util/Logger.js\";\r\n\r\nexport const SET_HUB_PRODUCTION = \"SET_HUB_PRODUCTION\";\r\nexport const SET_HUB_PRODUCTS = \"SET_HUB_PRODUCTS\";\r\nexport const SET_HUB_PRODUCTION_NEWQTY = \"SET_HUB_PRODUCTION_NEWQTY\";\r\nexport const CLEAR_HUB_PRODUCTION_NEWQTY = \"CLEAR_HUB_PRODUCTION_NEWQTY\";\r\nexport const SET_HUB_PRODUCTION_NEW_CUSTOMER = \"SET_HUB_PRODUCTION_NEW_CUSTOMER\";\r\nexport const SET_HUB_PRODUCTION_NEW_PRODUCT = \"SET_HUB_PRODUCTION_NEW_PRODUCT\";\r\n\r\n\r\n/**\r\n * Gets hub overview\r\n * @param {number} hubId\r\n * @returns {func}\r\n */\r\nexport function getHubProduction(hubId) {\r\n return async dispatch => {\r\n try {\r\n // Call webApi to get a list of invoice groups\r\n const { payload } = await dispatch(\r\n getApi(\"FreshFoodHub/GetHubProductionQuery\",\r\n {\r\n hubId : hubId,\r\n }));\r\n\r\n dispatch({\r\n type: SET_HUB_PRODUCTION,\r\n payload: payload\r\n });\r\n } catch (error) {\r\n dispatch(pushSystemMessage(error && error.message || \"Lasting av produksjonsliste mislyktes\", messageType.error));\r\n Logger.error(error);\r\n }\r\n };\r\n}\r\n\r\n\r\n/**\r\n * Gets hub overview\r\n * @param {number} hubId\r\n * @returns {func}\r\n */\r\nexport function getHubProducts(hubId) {\r\n return async dispatch => {\r\n try {\r\n // Call webApi to get a list of invoice groups\r\n const { payload } = await dispatch(\r\n getApi(\"FreshFoodHub/GetHubProductsQuery\",\r\n {\r\n hubId : hubId,\r\n }));\r\n\r\n dispatch({\r\n type: SET_HUB_PRODUCTS,\r\n payload: payload\r\n });\r\n } catch (error) {\r\n dispatch(pushSystemMessage(error && error.message || \"Lasting av varer for ub mislyktes\", messageType.error));\r\n Logger.error(error);\r\n }\r\n };\r\n}\r\n\r\n\r\n/**\r\n * Adds a qty to the produced qty\r\n * @param {string} customerId\r\n * @param {string} productId\r\n * @param {int} value\r\n * @returns {func}\r\n */\r\nexport function addProducedQty(customerId, productId, value) {\r\n return async (dispatch, getState) => {\r\n try {\r\n\r\n const state = getState();\r\n\r\n // Clear any previous edited customer, which was not submitted\r\n if(state.freshFoodHub.editedCustomer.customerId != customerId)\r\n {\r\n dispatch({\r\n type: SET_HUB_PRODUCTION_NEW_CUSTOMER,\r\n customerId: customerId,\r\n });\r\n } \r\n\r\n dispatch({\r\n type: SET_HUB_PRODUCTION_NEWQTY,\r\n customerId: customerId,\r\n product: { \r\n productId: productId,\r\n producedQty: value\r\n }\r\n \r\n });\r\n } catch (error) {\r\n dispatch(pushSystemMessage(error && error.message || \"Oppdatering av produsert antal feilet.\", messageType.error));\r\n Logger.error(error);\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Adds a new product\r\n * @param {string} customerId\r\n * @param {string} productId\r\n * @param {string} epdNo\r\n * @param {string} productName\r\n * @returns {func}\r\n * \r\n */\r\nexport function addNewProductToRegister(customerId, productId, epdNo, productName) {\r\n return async (dispatch) => {\r\n try {\r\n dispatch({\r\n type: SET_HUB_PRODUCTION_NEW_PRODUCT,\r\n customerId: customerId,\r\n product: { \r\n productId: productId,\r\n epdNo: epdNo,\r\n productName: productName,\r\n qtyToBeProduced: 0,\r\n qtyProduced: 0,\r\n registeredQty: 0,\r\n producedQty: 0\r\n }\r\n }); \r\n } catch (error) {\r\n dispatch(pushSystemMessage(error && error.message || \"Oppdatering av produsert antal feilet.\", messageType.error));\r\n Logger.error(error);\r\n }\r\n };\r\n}\r\n\r\n\r\n/**\r\n * Submits edited qty\r\n * @returns {func}\r\n */\r\nexport function submitEditedProducts() {\r\n return async (dispatch, getState) => {\r\n try {\r\n\r\n const state = getState();\r\n\r\n // Clear any previous edited customer, which was not submitted\r\n if(state.freshFoodHub.editedCustomer.products.length > 0)\r\n {\r\n //debugger;\r\n // Call webApi to updated produced qty in DB.\r\n const payload = await dispatch(\r\n postApi(\"FreshFoodHub/ProduceProductsCommand\",\r\n {\r\n hubId : state.authentication.hubId,\r\n customerId : state.freshFoodHub.editedCustomer.customerId,\r\n products: state.freshFoodHub.editedCustomer.products\r\n }));\r\n \r\n if( payload.message === \"OK\") {\r\n dispatch({\r\n type: CLEAR_HUB_PRODUCTION_NEWQTY,\r\n });\r\n\r\n dispatch(pushSystemMessage(\"Varer ble oppdatert!\", messageType.message));\r\n // refresh display\r\n await dispatch(getHubProduction(state.authentication.hubId));\r\n }\r\n } \r\n\r\n } catch (error) {\r\n dispatch(pushSystemMessage(error && error.message || \"Oppdatering av produsert antal feilet.\", messageType.error));\r\n Logger.error(error);\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Downloads a pdf\r\n * @param {object} productionData\r\n * @param {string} token\r\n * @returns {func}\r\n */\r\nexport function showProductionListPdf(productionData, token){\r\n return async (dispatch, getState) => {\r\n try {\r\n const state = getState();\r\n\r\n const blob = await getBlob(\"FreshFoodHub/GenerateProductionListPdf\", \r\n {\r\n hubId : state.authentication.hubId,\r\n customerId: productionData.customerId,\r\n productionDate : productionData.productionDate, \r\n }\r\n , token, ContentTypes.JSON, ContentTypes.PDF, false);\r\n downloadBlob(blob, `${productionData.productionDate}.pdf`, ContentTypes.PDF);\r\n\r\n } catch (error) {\r\n dispatch( pushSystemMessage(error.message || \"Fil ikke funnet\", messageType.error) );\r\n Logger.error(error);\r\n }\r\n };\r\n}\r\n\r\n","import \"../../../styles/hubweb/hubProductView.scss\";\r\nimport \"../../../styles/page/shoppingCart.scss\";\r\n\r\nimport Icon, { iconColor, iconTypes } from \"../../common/components/Icon\";\r\nimport { addNewProductToRegister, addProducedQty, getHubProducts, showProductionListPdf, submitEditedProducts } from \"../actions/hubProduction.js\";\r\n\r\nimport CounterField from \"../../common/components/CounterField.jsx\";\r\nimport DropDownList from \"../../common/components/DropDownList\";\r\nimport { Localization } from \"../../common/util/localization.jsx\";\r\nimport Modal from \"../../common/components/Modal.jsx\";\r\nimport PropTypes from \"prop-types\";\r\nimport React from \"react\";\r\nimport ResponsiveColumn from \"../../common/components/ResponsiveColumn\";\r\nimport ResponsiveRows from \"../../common/components/ResponsiveRows\";\r\nimport Scroll from \"../../common/components/Scroll.jsx\";\r\nimport { connect } from \"react-redux\";\r\nimport moment from \"moment\";\r\nimport { scssVariables } from \"../../common/util/config.jsx\";\r\nimport { setDropDown } from \"../../common/actions/modal.js\";\r\n\r\n/**\r\n * A counter designed for ordered items\r\n * \r\n * @param {object} props\r\n * @returns {node}\r\n */\r\nfunction CounterProducedQty({customerId, productId, addProducedQty, registeredQty}) {\r\n\r\n /**\r\n * updates produced qty\r\n * \r\n * @param {object} change\r\n * @returns {undefiend}\r\n */\r\n function onEditProducedQty(change) {\r\n addProducedQty(customerId, productId, change.value); \r\n }\r\n\r\n return (\r\n
\r\n );\r\n}\r\nCounterProducedQty.propTypes = {\r\n customerId: PropTypes.string,\r\n productId: PropTypes.string,\r\n addProducedQty: PropTypes.func,\r\n registeredQty: PropTypes.number\r\n};\r\n\r\n\r\nclass HubProductionListModal extends React.PureComponent {\r\n constructor(props) {\r\n super(props);\r\n this.handleClickOutside = this.handleClickOutside.bind(this);\r\n this.prepareCart = this.prepareCart.bind(this);\r\n this.onSaveChanges = this.onSaveChanges.bind(this);\r\n this.onEditProductChoice = this.onEditProductChoice.bind(this);\r\n this.onClickShowPdf = this.onClickShowPdf.bind(this);\r\n this.getProducedQty = this.getProducedQty.bind(this);\r\n }\r\n\r\n componentDidMount() {\r\n (async () => {\r\n await this.props.getHubProducts(this.props.hubId);\r\n })();\r\n }\r\n\r\n handleClickOutside() {\r\n if (this.props.onCloseModal) {\r\n this.props.onCloseModal();\r\n }\r\n }\r\n\r\n getProducedQty(customerId, productId) \r\n {\r\n const {\r\n editedCustomer,\r\n } = this.props;\r\n \r\n const product = editedCustomer && editedCustomer.customerId === customerId ? editedCustomer.products.find(p => p.productId === productId) : null;\r\n\r\n if(product != null)\r\n {\r\n return product.producedQty;\r\n }\r\n else\r\n {\r\n return 0;\r\n }\r\n }\r\n\r\n prepareCart() {\r\n const {\r\n customer,\r\n addProducedQty,\r\n } = this.props;\r\n \r\n const prodNodes = customer.products.map((product) => \r\n (\r\n
\r\n
\r\n
\r\n \r\n \r\n
\r\n {product.productName}\r\n
\r\n
\r\n \r\n \r\n \r\n
\r\n {product.epdNo}\r\n
\r\n
\r\n \r\n \r\n \r\n
\r\n {product.qtyToBeProduced}\r\n
\r\n
\r\n \r\n \r\n \r\n
\r\n {product.qtyProduced}\r\n
\r\n
\r\n \r\n \r\n \r\n \r\n
\r\n \r\n \r\n \r\n
\r\n {product.lastUpdatedDate ? moment(product.lastUpdatedDate).format(\"HH:mm:ss\") : \"\"}\r\n
\r\n
\r\n \r\n \r\n
\r\n
\r\n
));\r\n\r\n return prodNodes;\r\n }\r\n\r\n onClickShowPdf() {\r\n const {\r\n customer,\r\n showProductionListPdf,\r\n token,\r\n } = this.props;\r\n\r\n showProductionListPdf(customer, token);\r\n }\r\n\r\n onSaveChanges() {\r\n const {\r\n submitEditedProducts,\r\n onRefreshModal\r\n } = this.props;\r\n (async () => {\r\n await submitEditedProducts();\r\n onRefreshModal(); \r\n })();\r\n }\r\n\r\n onEditProductChoice(choice)\r\n {\r\n const {\r\n customer,\r\n hubProducts,\r\n addNewProductToRegister,\r\n onRefreshModal\r\n } = this.props;\r\n\r\n const prod = hubProducts.find(p => p.productId === choice.productId); \r\n\r\n (async () => {\r\n await addNewProductToRegister(customer.customerId, prod.productId, prod.epdNo, prod.productName);\r\n onRefreshModal(); \r\n })(); \r\n }\r\n\r\n calculateListHeight() {\r\n // const {\r\n // height,\r\n // } = this.props;\r\n\r\n let listHeight = 700;\r\n\r\n //top menu\r\n listHeight -= parseInt(scssVariables.menuHeight);\r\n //progressbar\r\n listHeight -= parseInt(scssVariables.progresbarHeight);\r\n //second menu\r\n listHeight -= parseInt(scssVariables.menuHeight);\r\n //bottom section\r\n listHeight -= parseInt(scssVariables.hubCartDetailHeight);\r\n\r\n return listHeight;\r\n }\r\n\r\n\r\n render() {\r\n const {\r\n localization,\r\n onCloseModal,\r\n title,\r\n width,\r\n customer,\r\n hubProducts,\r\n } = this.props;\r\n\r\n const listHeight = this.calculateListHeight();\r\n\r\n const freshFoodSort = hubProducts.map(p => ({ value: p.productId, label: p.productName }));\r\n\r\n const freshFoodSortNotInList = freshFoodSort.filter(v => !customer.products.some(p => p.productId === v.value));\r\n const newProduct = { productId: \"\"};\r\n\r\n return (\r\n \r\n \r\n
\r\n
\r\n
\r\n
{title}
\r\n
\r\n
{`Butikk: ${customer.storeName}`}
\r\n
{`${localization.text(\"hub\",\"production\",\"departmentStoreNo\")} ${customer.departmentStoreNo}`}
\r\n
{`${localization.text(\"hub\",\"production\",\"address\")}: ${customer.streetAddress}`}
\r\n
{`Dato: ${moment(customer.productionDate).format(\"DD.MM.YYYY\")}`}
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n\r\n
\r\n
\r\n
\r\n
\r\n \r\n \r\n {localization.text(\"hub\",\"production\",\"description\")}\r\n
\r\n \r\n \r\n \r\n {localization.text(\"hub\",\"production\",\"epdNo\")}\r\n
\r\n \r\n \r\n \r\n {localization.text(\"hub\",\"production\",\"qtyToProduction\")}\r\n
\r\n \r\n \r\n \r\n {localization.text(\"hub\",\"production\",\"qtyDelivered\")}\r\n
\r\n \r\n \r\n \r\n {localization.text(\"hub\",\"production\",\"qtyProduced\")}\r\n
\r\n \r\n \r\n \r\n {localization.text(\"hub\",\"production\",\"lastUpdated\")}\r\n
\r\n \r\n \r\n
\r\n
\r\n
\r\n {this.prepareCart()}\r\n \r\n
\r\n\r\n
\r\n
\r\n \r\n
\r\n
\r\n
{localization.text(\"hub\", \"production\", \"newProduct\")}:
\r\n
\r\n \r\n
\r\n
\r\n
\r\n \r\n \r\n
\r\n
\r\n
\r\n \r\n );\r\n }\r\n}\r\nHubProductionListModal.propTypes = {\r\n isLoading: PropTypes.bool.isRequired,\r\n localization: Localization.propTypes.isRequired,\r\n onCloseModal: PropTypes.func.isRequired,\r\n onRefreshModal: PropTypes.func.isRequired,\r\n title: PropTypes.string,\r\n width: PropTypes.number.isRequired,\r\n setDropDown: PropTypes.func.isRequired,\r\n customer: PropTypes.object.isRequired,\r\n addProducedQty: PropTypes.func.isRequired,\r\n submitEditedProducts: PropTypes.func.isRequired,\r\n addNewProductToRegister: PropTypes.func.isRequired,\r\n getHubProducts: PropTypes.func.isRequired,\r\n hubId: PropTypes.number.isRequired,\r\n hubProducts: PropTypes.array.isRequired,\r\n showProductionListPdf : PropTypes.func.isRequired,\r\n token: PropTypes.string.isRequired,\r\n editedCustomer: PropTypes.object.isRequired,\r\n //height: PropTypes.number.isRequired,\r\n};\r\n\r\nconst mapStateToProps = () => {\r\n return (state) => ({\r\n isLoading: state.singleChainSortiment.isLoading,\r\n hubId: state.authentication.hubId,\r\n token: state.authentication.token,\r\n hubProducts: state.freshFoodHub.hubProducts\r\n });\r\n};\r\n\r\nconst mapDispatchToProps = {\r\n setDropDown,\r\n addNewProductToRegister,\r\n getHubProducts,\r\n submitEditedProducts,\r\n addProducedQty,\r\n showProductionListPdf,\r\n};\r\n\r\nexport default connect(mapStateToProps, mapDispatchToProps)(HubProductionListModal);\r\n","import \"../../../styles/kjedeweb/singleChainProductListItem.scss\";\r\n//import Icon, { iconTypes } from \"../../common/components/Icon\";\r\n\r\nimport HubProductionListModal from \"./HubProductionListModal\";\r\nimport { Localization } from \"../../common/util/localization.jsx\";\r\nimport PropTypes from \"prop-types\";\r\nimport React from \"react\";\r\nimport ResponsiveColumn from \"../../common/components/ResponsiveColumn\";\r\nimport ResponsiveRows from \"../../common/components/ResponsiveRows\";\r\n\r\nexport class HubProductionListHeader extends React.PureComponent {\r\n render() {\r\n const {\r\n localization,\r\n } = this.props;\r\n\r\n return (\r\n \r\n
\r\n
\r\n
\r\n \r\n \r\n {localization.text(\"hub\", \"production\", \"departmentStoreNo\")}\r\n
\r\n \r\n \r\n \r\n {localization.text(\"hub\", \"production\", \"customerName\")}\r\n
\r\n \r\n \r\n \r\n {localization.text(\"hub\", \"production\", \"address\")}\r\n
\r\n \r\n \r\n \r\n {localization.text(\"hub\", \"production\", \"qtyToProduction\")}\r\n
\r\n \r\n \r\n \r\n {localization.text(\"hub\", \"production\", \"qtyProduced\")}\r\n
\r\n \r\n {/* \r\n \r\n {localization.text(\"hub\", \"production\", \"qtyProduced\")}\r\n
\r\n \r\n \r\n \r\n {localization.text(\"hub\", \"production\", \"lastProductionDate\")}\r\n
\r\n */}\r\n\r\n \r\n
\r\n
\r\n
\r\n );\r\n }\r\n}\r\n\r\nHubProductionListHeader.propTypes = {\r\n localization: Localization.propTypes.isRequired,\r\n};\r\n\r\nexport class HubProductionListItem extends React.PureComponent {\r\n constructor(props) {\r\n super(props);\r\n\r\n this.showProductModal = this.showProductModal.bind(this);\r\n this.closeProductModal = this.closeProductModal.bind(this);\r\n this.closeAndReopenProductModal = this.closeAndReopenProductModal.bind(this);\r\n }\r\n\r\n\r\n showProductModal(event) {\r\n\r\n if(event)\r\n {\r\n event.stopPropagation();\r\n event.preventDefault();\r\n } \r\n\r\n const {\r\n localization,\r\n customer,\r\n editedCustomer,\r\n } = this.props;\r\n\r\n const title = localization.text(\"hub\", \"production\", \"confirmProductionList\");\r\n\r\n this.props.setModal();\r\n }\r\n\r\n closeProductModal(event) {\r\n event.stopPropagation();\r\n event.preventDefault();\r\n\r\n this.props.setModal(null);\r\n }\r\n\r\n closeAndReopenProductModal(event) {\r\n this.props.setModal(null);\r\n this.showProductModal(event);\r\n }\r\n\r\n render() {\r\n const {\r\n customer,\r\n } = this.props;\r\n\r\n return (\r\n \r\n
\r\n
\r\n
\r\n \r\n \r\n
\r\n {customer.departmentStoreNo}\r\n
\r\n
\r\n \r\n \r\n \r\n
\r\n {customer.storeName}\r\n
\r\n
\r\n \r\n \r\n \r\n
\r\n {customer.streetAddress}\r\n
\r\n
\r\n \r\n \r\n \r\n
\r\n {customer.qtyToProduce}\r\n
\r\n
\r\n \r\n \r\n \r\n
\r\n {customer.qtyProduced}\r\n
\r\n
\r\n \r\n \r\n
\r\n
\r\n
\r\n );\r\n }\r\n}\r\n\r\nHubProductionListItem.propTypes = {\r\n localization: Localization.propTypes.isRequired,\r\n product: PropTypes.object,\r\n setModal: PropTypes.func.isRequired,\r\n customer: PropTypes.object.isRequired,\r\n editedCustomer: PropTypes.object.isRequired,\r\n};\r\n\r\nHubProductionListItem.defaultProps = {\r\n};","import \"../../../styles/productView.scss\";\r\nimport \"../../../styles/productViewListItem.scss\";\r\n\r\nimport { HubProductionListHeader, HubProductionListItem } from \"./HubProductionListItem.jsx\";\r\n\r\nimport HubScroll from \"./HubScroll\";\r\nimport { Localization } from \"../../common/util/localization.jsx\";\r\nimport PropTypes from \"prop-types\";\r\nimport React from \"react\";\r\n\r\nclass HubProductionList extends React.PureComponent {\r\n constructor(props) {\r\n super(props);\r\n\r\n this.state = {\r\n width: null,\r\n };\r\n this.containerNode = null;\r\n\r\n this.prepareItems = this.prepareItems.bind(this);\r\n }\r\n\r\n prepareItems() {\r\n const {\r\n list,\r\n localization,\r\n setModal,\r\n editedCustomer,\r\n } = this.props;\r\n\r\n const retNodes = [];\r\n\r\n for (let i = 0; i < list.length; i++) {\r\n retNodes[retNodes.length] = (\r\n );\r\n }\r\n\r\n return retNodes;\r\n }\r\n\r\n render() {\r\n const {\r\n //deviceType,\r\n localization,\r\n height,\r\n style,\r\n } = this.props;\r\n\r\n const nodes = this.prepareItems();\r\n\r\n return (\r\n \r\n \r\n \r\n
\r\n \r\n {nodes}\r\n \r\n \r\n );\r\n }\r\n}\r\n\r\nHubProductionList.propTypes = {\r\n height: PropTypes.number,\r\n // If true a loading icon will be displayed\r\n isLoading: PropTypes.bool,\r\n // An array of products to be displayed\r\n list: PropTypes.array.isRequired,\r\n localization: Localization.propTypes.isRequired,\r\n setModal: PropTypes.func.isRequired,\r\n style: PropTypes.object,\r\n editedCustomer: PropTypes.object.isRequired,\r\n};\r\n\r\nexport default HubProductionList;\r\n","import { HubTab, HubTabList, HubTabPanel, HubTabs } from \"./HubTabs.jsx\";\r\n\r\nimport HubProductionList from \"./HubProductionList.jsx\";\r\nimport { Localization } from \"../../common/util/localization.jsx\";\r\nimport PropTypes from \"prop-types\";\r\nimport React from \"react\";\r\n\r\nimport { scssVariables } from \"../../common/util/config.jsx\";\r\nimport { withRouter } from \"react-router-dom\";\r\n\r\nclass HubProductionCard extends React.PureComponent {\r\n constructor(props) {\r\n super(props);\r\n\r\n this.swallowOnClick = this.swallowOnClick.bind(this);\r\n this.calculateInternalPanelHeight = this.calculateInternalPanelHeight.bind(this);\r\n\r\n }\r\n\r\n swallowOnClick(event) {\r\n event.stopPropagation();\r\n event.preventDefault();\r\n }\r\n\r\n\r\n calculateInternalPanelHeight() {\r\n let tabPanelHeight = this.props.height;\r\n\r\n // Remove height of tab panel\r\n tabPanelHeight -= parseInt(scssVariables.menuHeightWithBorder);\r\n return tabPanelHeight;\r\n }\r\n\r\n render() {\r\n const {\r\n height,\r\n localization,\r\n setModal,\r\n width,\r\n customerProductionList,\r\n editedCustomer,\r\n } = this.props;\r\n const tabPanelHeight = this.calculateInternalPanelHeight();\r\n\r\n return (\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n );\r\n }\r\n}\r\n\r\nHubProductionCard.propTypes = {\r\n deviceType: PropTypes.string.isRequired,\r\n height: PropTypes.number.isRequired,\r\n history: PropTypes.object.isRequired,\r\n localization: Localization.propTypes.isRequired,\r\n location: PropTypes.object.isRequired,\r\n setModal: PropTypes.func.isRequired,\r\n width: PropTypes.number.isRequired,\r\n customerProductionList: PropTypes.array.isRequired,\r\n editedCustomer: PropTypes.object.isRequired,\r\n};\r\n\r\nHubProductionCard.defaultProps = {\r\n currentView: \"all\",\r\n};\r\nexport default withRouter(HubProductionCard);\r\n","import \"../../../styles/page/order.scss\";\r\n\r\nimport { TitleTab, TitleTabs } from \"../../common/components/TitleTabs.jsx\";\r\n\r\nimport ContentWrapper from \"../../common/components/ContentWrapper\";\r\nimport HubProductionCard from \"./HubProductionCard.jsx\";\r\nimport { Localization } from \"../../common/util/localization.jsx\";\r\nimport PropTypes from \"prop-types\";\r\nimport React from \"react\";\r\n// import SingleChainSearchBar from \"./SingleChainSearchBar.jsx\";\r\nimport { scssVariables } from \"../../common/util/config.jsx\";\r\nimport { withRouter } from \"react-router-dom\";\r\n\r\nclass HubProductionPage extends React.PureComponent {\r\n constructor(props) {\r\n super(props);\r\n\r\n this.calculateProductDisplayHeight = this.calculateProductDisplayHeight.bind(this);\r\n this.calculateProductDisplayWidth = this.calculateProductDisplayWidth.bind(this);\r\n //this.loadMoreSearchResults = this.loadMoreSearchResults.bind(this);\r\n //this.onEditFilter = this.onEditFilter.bind(this);\r\n }\r\n\r\n UNSAFE_componentWillMount() {\r\n const {\r\n getHubProduction,\r\n } = this.props;\r\n getHubProduction();\r\n }\r\n\r\n calculateProductDisplayHeight() {\r\n const {\r\n deviceType,\r\n height,\r\n } = this.props;\r\n let productDisplayHeight = height;\r\n\r\n // Page padding\r\n productDisplayHeight -= parseInt(scssVariables[`${deviceType}ContentPadding`]) * 2;\r\n\r\n if (deviceType === \"xs\") {\r\n productDisplayHeight -= parseInt(scssVariables.menuHeightWithBorder);\r\n } else {\r\n // Title tab height\r\n productDisplayHeight -= parseInt(scssVariables.cardMargin) * 2;\r\n productDisplayHeight -= parseInt(scssVariables.titleTabHeight);\r\n\r\n // Search bar height\r\n productDisplayHeight -= parseInt(scssVariables.cardMargin) * 2;\r\n productDisplayHeight -= parseInt(scssVariables.menuHeightWithBorder);\r\n }\r\n\r\n // Product display padding\r\n productDisplayHeight -= parseInt(scssVariables.cardMargin) * 2;\r\n\r\n return productDisplayHeight;\r\n }\r\n\r\n calculateProductDisplayWidth() {\r\n const {\r\n deviceType,\r\n width,\r\n } = this.props;\r\n\r\n let productDisplayWidth = width;\r\n if (deviceType === \"xs\") {\r\n // Page padding\r\n productDisplayWidth -= parseInt(scssVariables[`${deviceType}ContentPadding`]) * 2;\r\n\r\n // Product display padding\r\n productDisplayWidth -= parseInt(scssVariables.cardMargin) * 2;\r\n } else {\r\n // Page padding\r\n productDisplayWidth -= parseInt(scssVariables[`${deviceType}ContentPadding`]); // No padding on the right side(Attached to it)\r\n\r\n // Product display padding\r\n productDisplayWidth -= parseInt(scssVariables.cardMargin) * 2;\r\n }\r\n\r\n return productDisplayWidth;\r\n }\r\n\r\n\r\n render() {\r\n const {\r\n deviceType,\r\n height,\r\n localization,\r\n setModal,\r\n customerProductionList,\r\n flowControl,\r\n editedCustomer,\r\n } = this.props;\r\n\r\n const productDisplayHeight = this.calculateProductDisplayHeight();\r\n const productDisplayWidth = this.calculateProductDisplayWidth();\r\n\r\n return (\r\n \r\n \r\n
\r\n \r\n \r\n \r\n \r\n { }\r\n
\r\n
\r\n );\r\n }\r\n}\r\n\r\nHubProductionPage.propTypes = {\r\n deviceType: PropTypes.string.isRequired,\r\n flowControl: PropTypes.func.isRequired,\r\n height: PropTypes.number.isRequired,\r\n localization: Localization.propTypes.isRequired,\r\n setModal: PropTypes.func.isRequired,\r\n setDropDown: PropTypes.func.isRequired,\r\n startView: PropTypes.string.isRequired,\r\n width: PropTypes.number.isRequired,\r\n getHubProduction: PropTypes.func.isRequired,\r\n customerProductionList: PropTypes.array.isRequired,\r\n editedCustomer: PropTypes.object.isRequired,\r\n};\r\n\r\nexport default withRouter(HubProductionPage);\r\n","import { setDropDown, setModal } from \"../../common/actions/modal\";\r\n\r\nimport HubProductionPage from \"../components/HubProductionPage.jsx\";\r\nimport { connect } from \"react-redux\";\r\nimport { createBoundFunction } from \"../../common/util/reselect.js\";\r\nimport { createFlowControl } from \"../../common/util/flowControl\";\r\nimport { createLocalization } from \"../../common/util/localization.jsx\";\r\nimport { getHubProduction } from \"../actions/hubProduction.js\";\r\nimport { scssVariables } from \"../../common/util/config.jsx\";\r\n\r\nconst mapStateToProps = () => {\r\n const flowControl = createFlowControl();\r\n const flowControlCounter = createFlowControl();\r\n\r\n return (state, ownProps) => ({\r\n deviceType: state.view.deviceType,\r\n flowControl: flowControl,\r\n flowControlCounter: flowControlCounter,\r\n height: state.view.innerHeight - parseInt(scssVariables.menuHeight),\r\n localization: createLocalization(state),\r\n startView: ownProps.match.params.view || \"all\",\r\n width: state.view.innerWidth,\r\n customerProductionList : state.freshFoodHub.customerProductionList,\r\n editedCustomer: state.freshFoodHub.editedCustomer,\r\n hubId : state.authentication.hubId,\r\n });\r\n};\r\n\r\nconst mapDispatchToProps = {\r\n getHubProduction,\r\n setModal,\r\n setDropDown,\r\n};\r\n\r\nconst myGetHubProduction = createBoundFunction();\r\n\r\nconst mergeProps = (stateProps, dispatchProps, ownProps) => ({\r\n ...stateProps,\r\n ...dispatchProps,\r\n ...ownProps,\r\n getHubProduction: myGetHubProduction(() => dispatchProps.getHubProduction(stateProps.hubId)), \r\n});\r\n\r\nexport default connect(mapStateToProps, mapDispatchToProps, mergeProps)(HubProductionPage);\r\n","import { getApi, getEncodedSearchString, postApi } from \"../../common/actions/net.js\";\r\nimport { getExistingProductImage, loadProductImage } from \"../../kundeweb/actions/productImage.js\";\r\nimport { messageType, pushSystemMessage } from \"../../common/actions/systemMessage.js\";\r\n\r\nimport Logger from \"../../common/util/Logger.js\";\r\nimport { UPDATE_MULTI_CHAIN_PRODUCT_LIST } from \"./multiChainSortiment.js\";\r\n\r\nexport const SET_MULTI_EPIX_SORTIMENT = \"SET_MULTI_EPIX_SORTIMENT\";\r\nexport const ADD_MULTI_EPIX_SORTIMENT = \"ADD_MULTI_EPIX_SORTIMENT\";\r\nexport const SET_QUERY_PRODUCT_IMAGE_URL = \"SET_QUERY_PRODUCT_IMAGE_URL\";\r\nexport const MULTI_EPIX_SORTIMENT_IS_LOADING = \"MULTI_EPIX_SORTIMENT_IS_LOADING\";\r\nexport const MULTI_EPIX_QUERY_DONE_LOADING = \"MULTI_EPIX_QUERY_DONE_LOADING\";\r\nexport const MULTI_EPIX_QUERY_FAILED_LOADING = \"MULTI_EPIX_QUERY_DONE_LOADING\";\r\nexport const MULTI_EPIX_QUERY_ALL_LOADED = \"MULTI_EPIX_QUERY_ALL_LOADED\";\r\nexport const EDIT_MULTI_EPIX_FILTER = \"EDIT_MULTI_EPIX_FILTER\";\r\nexport const CLEAR_MULTI_EPIX_SORTIMENT = \"CLEAR_MULTI_EPIX_SORTIMENT\";\r\nexport const SET_MULTI_EPIX_SORTIMENT_FILTER = \"SET_MULTI_EPIX_SORTIMENT_FILTER\";\r\n\r\nexport const SET_MULTI_EPIX_PRODUCT_DETAIL = \"SET_MULTI_EPIX_PRODUCT_DETAIL\";\r\nexport const CLEAR_MULTI_EPIX_PRODUCT_DETAIL = \"CLEAR_MULTI_EPIX_PRODUCT_DETAIL\";\r\nexport const UPDATE_MULTI_EPIX_PRODUCT_LIST = \"UPDATE_MULTI_EPIX_PRODUCT_LIST\";\r\nexport const SET_INVOICE_GROUPS = \"SET_INVOICE_GROUPS\";\r\nexport const SET_QUERY_OPTION = \"SET_QUERY_OPTION\";\r\n\r\nexport const LOADING_NEW_EPIX_PRODUCTS = \"LOADING_NEW_EPIX_PRODUCTS\";\r\nexport const SET_NEW_EPIX_PRODUCTS = \"SET_NEW_EPIX_PRODUCTS\";\r\n\r\nconst setQueryProductImageUrl = (index, imageUrl) => ({\r\n type: SET_QUERY_PRODUCT_IMAGE_URL,\r\n index,\r\n imageUrl\r\n});\r\n\r\nconst setMultiEpixSortimentIsLoading = () => ({\r\n type: MULTI_EPIX_SORTIMENT_IS_LOADING\r\n});\r\nconst setMultiEpixSortimentDoneLoading = () => ({\r\n type: MULTI_EPIX_QUERY_DONE_LOADING\r\n});\r\nconst setMultiEpixSortimentFailedLoading = () => ({\r\n type: MULTI_EPIX_QUERY_FAILED_LOADING\r\n});\r\n\r\nconst setMultiEpixSortimentAllLoaded = () => ({\r\n type: MULTI_EPIX_QUERY_ALL_LOADED\r\n});\r\n\r\n/**\r\n * Downloads more multi chain Epix sortiment items\r\n * @param {object} multiEpixSortiment\r\n * @param {object} productImage\r\n * @param {number} noOfProducts\r\n * @returns {func}\r\n */\r\nexport function loadMoreMultiEpixSortiment(multiEpixSortiment, productImage, noOfProducts = 50) {\r\n return async (dispatch, getState) => {\r\n try {\r\n //make sure there is something new to load\r\n if (multiEpixSortiment.allResultsLoaded) {\r\n return;\r\n }\r\n\r\n //start collection new lines\r\n dispatch(setMultiEpixSortimentIsLoading());\r\n\r\n const startIndex = multiEpixSortiment.allProducts.length;\r\n\r\n // Load in more products\r\n const { payload } = await dispatch(\r\n getApi(\"Chain/ProductsFreeTextQuery\", {\r\n chainType: getState().authentication.chainType,\r\n onlyAvailableForChain: false,\r\n noOfProducts: noOfProducts,\r\n startIndex: startIndex,\r\n freeText: getEncodedSearchString(multiEpixSortiment.chainFilter.searchString),\r\n supplierId: multiEpixSortiment.chainFilter.supplierId ? multiEpixSortiment.chainFilter.supplierId : undefined,\r\n productGroupId: multiEpixSortiment.chainFilter.productGroupId ? multiEpixSortiment.chainFilter.productGroupId : undefined,\r\n InvoiceGroup: multiEpixSortiment.chainFilter.invoiceGroupId ? multiEpixSortiment.chainFilter.invoiceGroupId : undefined,\r\n ProductStatus: multiEpixSortiment.chainFilter.productStatus >= 0 ? multiEpixSortiment.chainFilter.productStatus : undefined,\r\n onlyNews: multiEpixSortiment.chainFilter.onlyNews,\r\n })\r\n );\r\n\r\n // Check if all data has been loaded\r\n if (payload.products.length != noOfProducts) {\r\n dispatch(setMultiEpixSortimentAllLoaded());\r\n }\r\n\r\n // Insert existing images\r\n for (let i = 0; i < payload.products.length; i++) {\r\n payload.products[i].imageUrl = getExistingProductImage(payload.products[i].productId);\r\n }\r\n // Convert to default layout\r\n const prdList = payload.products.map(prd => {\r\n return { product: prd };\r\n });\r\n\r\n // Store query results\r\n await dispatch({ type: ADD_MULTI_EPIX_SORTIMENT, allProducts: prdList });\r\n\r\n // Download all images not already inserted\r\n for (let index = 0; index < prdList.length; index++) {\r\n if (!prdList[index].product.imageUrl || prdList[index].product.imageUrl.length === 0) {\r\n const callback = imageUrl => dispatch(setQueryProductImageUrl(startIndex + index, imageUrl));\r\n dispatch(loadProductImage(productImage, prdList[index].product.productId, prdList[index].product.imageFileName, callback));\r\n }\r\n }\r\n\r\n dispatch(setMultiEpixSortimentDoneLoading());\r\n } catch (error) {\r\n dispatch(setMultiEpixSortimentFailedLoading());\r\n dispatch(pushSystemMessage(error && error.message || \"Laster sortiment mislyktes\", messageType.error));\r\n Logger.error(error);\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Changes the query filter\r\n * @param {object} change\r\n * @param {func} callback // function will be called when the state has been updated\r\n * @returns {func}\r\n */\r\nexport function editMultiEpixFilter(change, callback) {\r\n return async dispatch => {\r\n await dispatch({\r\n type: EDIT_MULTI_EPIX_FILTER,\r\n change\r\n });\r\n\r\n try {\r\n dispatch(setMultiEpixSortimentIsLoading());\r\n await callback();\r\n } catch (error) {\r\n Logger.error(error);\r\n } finally {\r\n dispatch(setMultiEpixSortimentDoneLoading());\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Clears the single chain Epix sortiment\r\n * @returns {func}\r\n */\r\nexport function clearMultiEpixSortiment() {\r\n return async dispatch => {\r\n dispatch({\r\n type: CLEAR_MULTI_EPIX_SORTIMENT\r\n });\r\n };\r\n}\r\n\r\n/**\r\n * Sets the single chain Epix sortiment filter \"OnlyAvailableForChain\" flag\r\n * @param {object} change\r\n * @returns {func}\r\n */\r\nexport function setMultiEpixSortimentFilter(change) {\r\n return async dispatch => {\r\n dispatch({\r\n type: SET_MULTI_EPIX_SORTIMENT_FILTER,\r\n change\r\n });\r\n };\r\n}\r\n\r\n/**\r\n * Changes the query filter\r\n * @returns {func}\r\n */\r\nexport function prepareQueryOptions() {\r\n return async (dispatch, getState) => {\r\n const state = getState();\r\n const payload = await dispatch(getApi(\"Chain/FilterOptionsQuery\", {\r\n chainType: state.authentication.chainType}));\r\n dispatch({\r\n type: SET_QUERY_OPTION,\r\n productGroups: payload ? payload.payload.productGroups : null,\r\n productSuppliers: payload ? payload.payload.suppliers : null\r\n });\r\n };\r\n}\r\n\r\n/**\r\n * Gets product details for the given product id\r\n * @param {number} chainId\r\n * @param {string} productId\r\n * @param {string} imageUrl\r\n * @returns {function.}\r\n */\r\nexport function getMultiEpixProductDetail(chainId, productId, imageUrl) {\r\n return async dispatch => {\r\n try {\r\n // Call webApi to make Products details request\r\n const { payload: productDetail } = await dispatch(getApi(\"Chain/ProductsDetailQuery\", { chainId, productId }));\r\n productDetail.imageUrl = imageUrl;\r\n\r\n dispatch({\r\n type: SET_MULTI_EPIX_PRODUCT_DETAIL,\r\n productDetail\r\n });\r\n } catch (error) {\r\n dispatch(pushSystemMessage(error && error.message || \"Lasting av varedetaljer mislyktes\", messageType.error));\r\n Logger.error(error);\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Clears chain product detail modal\r\n * @returns {function.}\r\n */\r\nexport function clearEpixProductDetails() {\r\n return async dispatch => {\r\n try {\r\n dispatch({\r\n type: CLEAR_MULTI_EPIX_PRODUCT_DETAIL\r\n });\r\n } catch (error) {\r\n Logger.error(error);\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Gets invoice groups\r\n * @returns {function.}\r\n */\r\nexport function getInvoiceGroups() {\r\n return async dispatch => {\r\n try {\r\n // Call webApi to get a list of invoice groups\r\n const { payload: invoiceGroups } = await dispatch(getApi(\"Chain/InvoiceGroupsQuery\"));\r\n\r\n dispatch({\r\n type: SET_INVOICE_GROUPS,\r\n invoiceGroups\r\n });\r\n } catch (error) {\r\n dispatch(pushSystemMessage(error && error.message || \"Lasting av fakturagrupper mislyktes\", messageType.error));\r\n Logger.error(error);\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Commit product changes\r\n * @param {array} products\r\n * @returns {func}\r\n */\r\nexport function updateChainProducts(products) {\r\n return async (dispatch, getState) => {\r\n try {\r\n // dispatch({\r\n // type: UPDATE_PRODUCTS,\r\n // committing: true,\r\n // });\r\n\r\n const payload = await dispatch(\r\n postApi(\"Chain/UpdateChainProductsCommand\", {\r\n chainType: getState().authentication.chainType,\r\n productsToUpdate: products.map(p => {\r\n return {\r\n chainId: p.chainId,\r\n productId: p.productId,\r\n isAvailable: p.isAvailable,\r\n inCatalogue: p.inCatalogue,\r\n invoiceGroupId: p.invoiceGroupId,\r\n sortimentCode: p.sortimentCode,\r\n futureEndPrice: p.futureEndPrice,\r\n futureEndPriceDate: p.futureEndPriceDate,\r\n futureAdminCharge: p.futureAdminCharge,\r\n futureAdminChargeDate: p.futureAdminChargeDate\r\n };\r\n })\r\n })\r\n );\r\n\r\n if (payload && payload.message === \"OK\") {\r\n dispatch(pushSystemMessage(\"Varer ble oppdatert!\", messageType.message));\r\n // history.push(\"/dashboard\");\r\n // dispatch({\r\n // type: CLEAR_CLAIM,\r\n // });\r\n\r\n // Call reducer that updates the product in the list from free text search\r\n dispatch({ type: UPDATE_MULTI_EPIX_PRODUCT_LIST, products });\r\n dispatch({ type: UPDATE_MULTI_CHAIN_PRODUCT_LIST, products });\r\n } else {\r\n dispatch(pushSystemMessage(payload && payload.displayMessage || \"Kan ikke oppdatere varer\", messageType.error));\r\n }\r\n } catch (error) {\r\n dispatch(pushSystemMessage(error && error.message || \"Oppdatering av kjedevarer mislyktes\", messageType.error));\r\n Logger.error(error);\r\n } finally {\r\n // dispatch({\r\n // type: UPDATE_PRODUCTS,\r\n // committing: false,\r\n // });\r\n }\r\n };\r\n}\r\n\r\n","import { getApi, getEncodedSearchString, postApi } from \"../../common/actions/net.js\";\r\nimport { getExistingProductImage, loadProductImage } from \"../../kundeweb/actions/productImage.js\";\r\nimport { messageType, pushSystemMessage } from \"../../common/actions/systemMessage.js\";\r\n\r\nimport Logger from \"../../common/util/Logger.js\";\r\nimport { UPDATE_MULTI_EPIX_PRODUCT_LIST } from \"./multiEpixSortiment.js\";\r\n\r\nimport moment from \"moment\";\r\nimport { toLocaleFixed} from \"../../common/util/localization.jsx\";\r\n\r\nexport const SET_MULTI_CHAIN_SORTIMENT = \"SET_MULTI_CHAIN_SORTIMENT\";\r\nexport const ADD_MULTI_CHAIN_SORTIMENT = \"ADD_MULTI_CHAIN_SORTIMENT\";\r\nexport const SET_QUERY_PRODUCT_IMAGE_URL = \"SET_QUERY_PRODUCT_IMAGE_URL\";\r\nexport const MULTI_CHAIN_SORTIMENT_IS_LOADING = \"MULTI_CHAIN_SORTIMENT_IS_LOADING\";\r\nexport const MULTI_CHAIN_QUERY_DONE_LOADING = \"MULTI_CHAIN_QUERY_DONE_LOADING\";\r\nexport const MULTI_CHAIN_QUERY_FAILED_LOADING = \"MULTI_CHAIN_QUERY_DONE_LOADING\";\r\nexport const MULTI_CHAIN_QUERY_ALL_LOADED = \"MULTI_CHAIN_QUERY_ALL_LOADED\";\r\nexport const EDIT_MULTI_CHAIN_FILTER = \"EDIT_MULTI_CHAIN_FILTER\";\r\nexport const CLEAR_MULTI_CHAIN_SORTIMENT = \"CLEAR_MULTI_CHAIN_SORTIMENT\";\r\nexport const SET_MULTI_CHAIN_SORTIMENT_FILTER = \"SET_MULTI_CHAIN_SORTIMENT_FILTER\";\r\n\r\nexport const SET_MULTI_CHAIN_PRODUCT_DETAIL = \"SET_MULTI_CHAIN_PRODUCT_DETAIL\";\r\nexport const CLEAR_MULTI_CHAIN_PRODUCT_DETAIL = \"CLEAR_MULTI_CHAIN_PRODUCT_DETAIL\";\r\nexport const UPDATE_MULTI_CHAIN_PRODUCT_LIST = \"UPDATE_MULTI_CHAIN_PRODUCT_LIST\";\r\nexport const SET_INVOICE_GROUPS = \"SET_INVOICE_GROUPS\";\r\nexport const SET_QUERY_OPTION = \"SET_QUERY_OPTION\";\r\n\r\nexport const LOADING_NEW_CHAIN_PRODUCTS = \"LOADING_NEW_CHAIN_PRODUCTS\";\r\nexport const SET_NEW_CHAIN_PRODUCTS = \"SET_NEW_CHAIN_PRODUCTS\";\r\n\r\nexport const SET_MULTI_SELECT = \"SET_MULTI_SELECT\";\r\nexport const CLEAR_MULTI_SELECT = \"CLEAR_MULTI_SELECT\";\r\n\r\nconst setQueryProductImageUrl = (index, imageUrl) => ({\r\n type: SET_QUERY_PRODUCT_IMAGE_URL,\r\n index,\r\n imageUrl\r\n});\r\n\r\nconst setMultiChainSortimentIsLoading = () => ({\r\n type: MULTI_CHAIN_SORTIMENT_IS_LOADING\r\n});\r\nconst setMultiChainSortimentDoneLoading = () => ({\r\n type: MULTI_CHAIN_QUERY_DONE_LOADING\r\n});\r\nconst setMultiChainSortimentFailedLoading = () => ({\r\n type: MULTI_CHAIN_QUERY_FAILED_LOADING\r\n});\r\n\r\nconst setMultiChainSortimentAllLoaded = () => ({\r\n type: MULTI_CHAIN_QUERY_ALL_LOADED\r\n});\r\n\r\nconst setNewChainProducts = (products) => ({\r\n type: SET_NEW_CHAIN_PRODUCTS,\r\n products\r\n});\r\n\r\n/**\r\n * Downloads more multi chain sortiment items\r\n * @param {object} multiChainSortiment\r\n * @param {object} productImage\r\n * @param {number} noOfProducts\r\n * @returns {func}\r\n */\r\nexport function loadMoreMultiChainSortiment(multiChainSortiment, productImage, noOfProducts = 50) {\r\n return async (dispatch, getState) => {\r\n try {\r\n //make sure there is something new to load\r\n if (multiChainSortiment.allResultsLoaded) {\r\n return;\r\n }\r\n\r\n const state = getState();\r\n\r\n //start collection new lines\r\n dispatch(setMultiChainSortimentIsLoading());\r\n\r\n const startIndex = multiChainSortiment.chainProducts.length;\r\n\r\n // Load in more products\r\n const { payload } = await dispatch(\r\n getApi(\"Chain/ProductsFreeTextQuery\", {\r\n chainType: state.authentication.chainType,\r\n chainId: multiChainSortiment.chainFilter.chainId,\r\n onlyAvailableForChain: true,\r\n noOfProducts: noOfProducts,\r\n startIndex: startIndex,\r\n freeText: getEncodedSearchString(multiChainSortiment.chainFilter.searchString),\r\n supplierId: multiChainSortiment.chainFilter.supplierId ? multiChainSortiment.chainFilter.supplierId : undefined,\r\n productGroupId: multiChainSortiment.chainFilter.productGroupId ? multiChainSortiment.chainFilter.productGroupId : undefined,\r\n InvoiceGroup: multiChainSortiment.chainFilter.invoiceGroupId ? multiChainSortiment.chainFilter.invoiceGroupId : undefined,\r\n ProductStatus: multiChainSortiment.chainFilter.productStatus >= 0 ? multiChainSortiment.chainFilter.productStatus : undefined,\r\n onlyNews: false,\r\n })\r\n );\r\n\r\n // Check if all data has been loaded\r\n if (payload.products.length != noOfProducts) {\r\n dispatch(setMultiChainSortimentAllLoaded());\r\n }\r\n\r\n // Insert existing images\r\n for (let i = 0; i < payload.products.length; i++) {\r\n payload.products[i].imageUrl = getExistingProductImage(payload.products[i].productId);\r\n }\r\n // Convert to default layout\r\n const prdList = payload.products.map(prd => {\r\n return { product: prd };\r\n });\r\n\r\n // Store query results\r\n await dispatch({ type: ADD_MULTI_CHAIN_SORTIMENT, chainProducts: prdList });\r\n\r\n // Download all images not already inserted\r\n for (let index = 0; index < prdList.length; index++) {\r\n if (!prdList[index].product.imageUrl || prdList[index].product.imageUrl.length === 0) {\r\n const callback = imageUrl => dispatch(setQueryProductImageUrl(startIndex + index, imageUrl));\r\n dispatch(loadProductImage(productImage, prdList[index].product.productId, prdList[index].product.imageFileName, callback));\r\n }\r\n }\r\n\r\n dispatch(setMultiChainSortimentDoneLoading());\r\n } catch (error) {\r\n dispatch(setMultiChainSortimentFailedLoading());\r\n dispatch(pushSystemMessage(error && error.message || \"Varesøk mislyktes\", messageType.error));\r\n Logger.error(error);\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Changes the query filter\r\n * @param {object} change\r\n * @param {func} callback // function will be called when the state has been updated\r\n * @returns {func}\r\n */\r\nexport function editMultiChainFilter(change, callback) {\r\n return async dispatch => {\r\n await dispatch({\r\n type: EDIT_MULTI_CHAIN_FILTER,\r\n change\r\n });\r\n\r\n try {\r\n dispatch(setMultiChainSortimentIsLoading());\r\n await callback();\r\n } catch (error) {\r\n Logger.error(error);\r\n } finally {\r\n dispatch(setMultiChainSortimentDoneLoading());\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Clears the single chain sortiment\r\n * @returns {func}\r\n */\r\nexport function clearMultiChainSortiment() {\r\n return async dispatch => {\r\n dispatch({\r\n type: CLEAR_MULTI_CHAIN_SORTIMENT\r\n });\r\n };\r\n}\r\n\r\n/**\r\n * Sets the single chain sortiment filter \"OnlyAvailableForChain\" flag\r\n * @param {object} change\r\n * @returns {func}\r\n */\r\nexport function setMultiChainSortimentFilter(change) {\r\n return async dispatch => {\r\n dispatch({\r\n type: SET_MULTI_CHAIN_SORTIMENT_FILTER,\r\n change\r\n });\r\n };\r\n}\r\n\r\n/**\r\n * Changes the query filter\r\n * @returns {func}\r\n */\r\nexport function prepareQueryOptions() {\r\n return async (dispatch, getState) => {\r\n const state = getState();\r\n const payload = await dispatch(getApi(\"Chain/FilterOptionsQuery\", {\r\n chainType: state.authentication.chainType}));\r\n dispatch({\r\n type: SET_QUERY_OPTION,\r\n productGroups: payload ? payload.payload.productGroups : null,\r\n productSuppliers: payload ? payload.payload.suppliers : null\r\n });\r\n };\r\n}\r\n\r\n/**\r\n * Gets product details for the given product id\r\n * @param {number[]} chainIds\r\n * @param {string} productId\r\n * @param {string} imageUrl\r\n * @returns {function.}\r\n */\r\nexport function getMultiChainProductDetail(chainIds, productId, imageUrl) {\r\n return async dispatch => {\r\n try {\r\n // Call webApi to make Products details request\r\n const productDetails = {};\r\n for (const chainId of chainIds) {\r\n const { payload } = await dispatch(getApi(\"Chain/ProductsDetailQuery\", { chainId, productId }));\r\n payload.imageUrl = imageUrl;\r\n productDetails[chainId] = payload;\r\n }\r\n\r\n dispatch({\r\n type: SET_MULTI_CHAIN_PRODUCT_DETAIL,\r\n productDetails\r\n });\r\n\r\n return productDetails;\r\n } catch (error) {\r\n dispatch(pushSystemMessage(error && error.message || \"Å få vareinformasjonen mislykte\", messageType.error));\r\n Logger.error(error);\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Clears chain product detail modal\r\n * @returns {function.}\r\n */\r\nexport function clearChainProductDetails() {\r\n return async dispatch => {\r\n try {\r\n dispatch({\r\n type: CLEAR_MULTI_CHAIN_PRODUCT_DETAIL\r\n });\r\n } catch (error) {\r\n Logger.error(error);\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Gets invoice groups\r\n * @returns {function.}\r\n */\r\nexport function getInvoiceGroups() {\r\n return async dispatch => {\r\n try {\r\n // Call webApi to get a list of invoice groups\r\n const { payload: invoiceGroups } = await dispatch(getApi(\"Chain/InvoiceGroupsQuery\"));\r\n\r\n dispatch({\r\n type: SET_INVOICE_GROUPS,\r\n invoiceGroups\r\n });\r\n } catch (error) {\r\n dispatch(pushSystemMessage(error && error.message || \"Innhenting av fakturagrupper mislyktes\", messageType.error));\r\n Logger.error(error);\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Commit product changes\r\n * @param {array} products\r\n * @returns {func}\r\n */\r\nexport function updateChainProducts(products) {\r\n return async (dispatch, getState) => {\r\n const state = getState();\r\n try {\r\n // dispatch({\r\n // type: UPDATE_PRODUCTS,\r\n // committing: true,\r\n // });\r\n\r\n const payload = await dispatch(\r\n postApi(\"Chain/UpdateChainProductsCommand\", {\r\n chainType: state.authentication.chainType,\r\n productsToUpdate: products.map(p => {\r\n return {\r\n chainId: p.chainId,\r\n productId: p.productId,\r\n isAvailable: p.isAvailable,\r\n inCatalogue: p.inCatalogue,\r\n invoiceGroupId: p.invoiceGroupId,\r\n sortimentCode: p.sortimentCode,\r\n futureEndPrice: p.futureEndPrice,\r\n futureEndPriceDate: p.futureEndPriceDate,\r\n futureAdminCharge: p.futureAdminCharge,\r\n futureAdminChargeDate: p.futureAdminChargeDate\r\n };\r\n })\r\n })\r\n );\r\n\r\n if (payload && payload.message === \"OK\") {\r\n dispatch(pushSystemMessage(\"Varer ble oppdatert!\", messageType.message));\r\n // history.push(\"/dashboard\");\r\n // dispatch({\r\n // type: CLEAR_CLAIM,\r\n // });\r\n\r\n // Call reducer that updates the product in the list from free text search\r\n dispatch({ type: UPDATE_MULTI_CHAIN_PRODUCT_LIST, products });\r\n dispatch({ type: UPDATE_MULTI_EPIX_PRODUCT_LIST, products });\r\n } else {\r\n dispatch(pushSystemMessage(payload && payload.displayMessage || \"Kan ikke oppdatere varer\", messageType.error));\r\n }\r\n } catch (error) {\r\n dispatch(pushSystemMessage(error && error.message || \"Kan ikke oppdatere varer\", messageType.error));\r\n Logger.error(error);\r\n } finally {\r\n // dispatch({\r\n // type: UPDATE_PRODUCTS,\r\n // committing: false,\r\n // });\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Loads new products for active chain\r\n * @returns {func}\r\n */\r\nexport function getNewChainProducts() {\r\n return async (dispatch, getState) => {\r\n try {\r\n if (getState().productLists.newProductsLoading) {\r\n return;\r\n }\r\n dispatch({\r\n type: LOADING_NEW_CHAIN_PRODUCTS,\r\n loading: true\r\n });\r\n\r\n // Collect info regarding all the new products\r\n const { payload } = await dispatch(\r\n getApi(\"Chain/ProductsFreeTextQuery\", {\r\n chainType: getState().authentication.chainType,\r\n onlyAvailableForChain: true,\r\n noOfProducts: 1000,\r\n startIndex: 0,\r\n onlyNews: true,\r\n })\r\n );\r\n\r\n // Insert existing images\r\n for (let i = 0; i < payload.length; i++) {\r\n payload.products[i].imageUrl = getExistingProductImage(payload.products[i].productId);\r\n }\r\n\r\n // Convert to default layout\r\n const prdList = payload.products.map(prd => {\r\n return { product: prd };\r\n });\r\n\r\n await dispatch(setNewChainProducts(prdList));\r\n } catch (error) {\r\n dispatch(pushSystemMessage(error && error.message || \"Lasting av nye produkter for kjeden mislyktes\", messageType.error));\r\n Logger.error(error);\r\n } finally {\r\n dispatch({\r\n type: LOADING_NEW_CHAIN_PRODUCTS,\r\n loading: false\r\n });\r\n }\r\n };\r\n}\r\n\r\nexport const LOADING_CHAINS = \"LOADING_CHAINS\";\r\nexport const LOADED_CHAINS = \"LOADED_CHAINS\";\r\nexport const LOADING_CHAINS_FAILED = \"LOADING_CHAINS_FAILED\";\r\n\r\n/**\r\n * Loads the list of chains.\r\n * @returns {func}\r\n */\r\nexport function loadChains() {\r\n return async (dispatch,) => {\r\n dispatch({\r\n type: LOADING_CHAINS\r\n });\r\n\r\n try {\r\n const { payload } = await dispatch(getApi(\"Chain/ChainsQuery\", {}));\r\n \r\n dispatch({\r\n type: LOADED_CHAINS,\r\n chains: Object.assign({}, ...payload.map(c => ({\r\n [c.chainId]: c\r\n })))\r\n });\r\n } catch (_) {\r\n dispatch({\r\n type: LOADING_CHAINS_FAILED\r\n });\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Sets if the product is selected ot not\r\n * @param {object} change\r\n * @returns {function}\r\n */\r\nexport function editSelectedProduct(change) {\r\n return async dispatch => {\r\n try {\r\n dispatch({\r\n type: SET_MULTI_SELECT,\r\n change,\r\n });\r\n } catch (error) {\r\n Logger.error(error);\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Clears all multi selected products\r\n * @returns {function}\r\n */\r\nexport function clearSelectedProducts() {\r\n return async dispatch => {\r\n try {\r\n dispatch({\r\n type: CLEAR_MULTI_SELECT,\r\n });\r\n } catch (error) {\r\n Logger.error(error);\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Exports the contents to a CSV file\r\n * @param {object} multiChainSortiment\r\n * @returns {function}\r\n */\r\nexport function exportCsv(multiChainSortiment) {\r\n return async (dispatch, getState) => {\r\n try {\r\n \r\n\r\n\r\n const state = getState();\r\n\r\n // Load in more products\r\n const { payload } = await dispatch(\r\n getApi(\"Chain/ProductsFreeTextQuery\", {\r\n chainType: state.authentication.chainType,\r\n chainId: multiChainSortiment.chainFilter.chainId,\r\n onlyAvailableForChain: true,\r\n noOfProducts: 10000,\r\n startIndex: 0,\r\n freeText: getEncodedSearchString(multiChainSortiment.chainFilter.searchString),\r\n supplierId: multiChainSortiment.chainFilter.supplierId ? multiChainSortiment.chainFilter.supplierId : undefined,\r\n productGroupId: multiChainSortiment.chainFilter.productGroupId ? multiChainSortiment.chainFilter.productGroupId : undefined,\r\n InvoiceGroup: multiChainSortiment.chainFilter.invoiceGroupId ? multiChainSortiment.chainFilter.invoiceGroupId : undefined,\r\n ProductStatus: multiChainSortiment.chainFilter.productStatus >= 0 ? multiChainSortiment.chainFilter.productStatus : undefined,\r\n onlyNews: false,\r\n })\r\n );\r\n\r\n const rows = [[\"Kjede\", \"Varetekst\", \"EPD\", \"Åpen\", /*\"I Katalog\",*/ \"Varestatus\", \r\n \"Gjeldende nettopris inkl. adm\", \"Gjeldende Nettopris pr f-pak\", \r\n \"Fremtidig nettopris inkl. adm\", \"Fremtidig Nettopris pr f-pak\", \"Gjelder fra dato\",\r\n \"Gjeldende Adm gebyr\", \"Fremtidig Adm gebyr\", \"Gjelder fra dato\",\r\n \"Fakturagruppe\", \"Sortimentkode\", \"Antall f-pak i d-pak\", \"Endringsdato\", \r\n \"Kolly varenr\", \"Leverandør navn\", \"Leverandør varenr\", \r\n \"Gjeldende detaljistpris ex adm\", \"Fremtidig detaljistpris ex adm\", \"Gjelder fra dato\",\r\n \"Gjeldende grunnlag for Adm/PDCC\", \"Fremtidig grunnlag for Adm/PDCC\", \"Gjelder fra dato\",\r\n \"Gjeldende pris inkl. avgifter ex Adm/PDCC\", \"Fremtidig pris inkl. avgifter ex Adm/PDCC\", \"Gjelder fra dato\",\r\n \"Gjeldende kampanjepris\", \"Fremtidig kampanjepris\", \"Gjelder fra dato\",\r\n \"Varegruppe\", \"Kalkylegruppe\",\r\n \"EAN F-pack\", \"EAN D-pak\", \"MVA\", \"Varetype\", \"Status\", \"Linket til vare\", \"Erstatter\", \"Holdbarhet (dager)\", \"Nettovekt (kg)\", \"Anbrekk\",\r\n \"Antall enheter i hel eske\", \"Pant pr D-pak / F-pack\",\"Grunnpris\", \"Vekt F-pack (g)\", \"Bredde F-pack\", \"Høyde F-pack\", \"Dybde F-pack\", \"Felles\",\r\n \"Gjeldende utsalgspris\", \"Fremtidig utsalgspris\", \"Gjelder fra dato\"]];\r\n \r\n for (const p of payload.products) {\r\n\r\n const lastChangedDate = !p.lastChangedDate ? null : moment(p.lastChangedDate).format(\"DD.MM.YYYY\");\r\n const futureCustomerBasePriceDate = !p.futureCustomerBasePriceDate ? null : moment(p.futureCustomerBasePriceDate).format(\"DD.MM.YYYY\");\r\n const futureEndPriceDate = !p.futureEndPriceDate ? null : moment(p.futureEndPriceDate).format(\"DD.MM.YYYY\");\r\n const futureAdminChargeDate = !p.futureAdminChargeDate ? null : moment(p.futureAdminChargeDate).format(\"DD.MM.YYYY\");\r\n\r\n rows.push([p.chainName, p.productName, p.epdNo, /*p.isAvailable ? \"Ja\" : \"nei\",*/ p.inCatalogue ? \"Ja\" : \"nei\", p.status, \r\n toLocaleFixed(p.currentNetPrice, 2), toLocaleFixed(p.currentNetPricePerSalesUnit, 3), \r\n toLocaleFixed(p.futureNetPrice, 3), toLocaleFixed(p.futureNetPricePerSalesUnit, 3), futureCustomerBasePriceDate,\r\n toLocaleFixed(p.adminChargePercent, 2), toLocaleFixed(p.futureAdminCharge, 2), futureAdminChargeDate,\r\n p.invoiceGroupName, p.catalogueCode, p.noOfSalesUnits, lastChangedDate,\r\n p.productId, p.supplierName, p.supplierProductId, \r\n toLocaleFixed(p.currentCustomerBasePrice,2), toLocaleFixed(p.futureCustomerBasePrice,2), futureCustomerBasePriceDate,\r\n toLocaleFixed(p.basePriceForAdminCharge,2), toLocaleFixed(p.futureBasePriceForAdminCharge,2), futureCustomerBasePriceDate, \r\n toLocaleFixed(p.customerBasePriceWithChargesExclAdminCharge,2), toLocaleFixed(p.futureCustomerBasePriceWithChargesExclAdminCharge,2), futureCustomerBasePriceDate,\r\n toLocaleFixed(p.currentCampaignPercent,2), toLocaleFixed(p.futureCampaignPercent,2), p.futureCampaignPeriod,\r\n p.category, p.calcGroup,\r\n p.eanNoSalesUnit, p.eanNoWarehouseUnit, toLocaleFixed(p.vatRate,2), p.productStorageType, p.status, p.linkProductId, p.replacingProductIds, p.durabilityDays, toLocaleFixed(p.weight,2), p.useSalesUnit ? \"Ja\" : \"Nei\",\r\n p.noOfUnitsInPackage, p.depositAmountWarehouseAndSalesUnit, toLocaleFixed(p.currentInPrice,2), toLocaleFixed(p.weightSalesUnit,3), toLocaleFixed(p.widthSalesUnit,3), \r\n toLocaleFixed(p.heightSalesUnit,3), toLocaleFixed(p.lengthSalesUnit,3), p.uniqueForChain ? \"Ja\" : \"Nei\",\r\n toLocaleFixed(p.currentEndCusPrice, 2), toLocaleFixed(p.futureEndPrice, 2), futureEndPriceDate,\r\n ]);\r\n }\r\n\r\n var BOM = \"\\uFEFF\"; \r\n const csvContent = `data:text/csv;charset=utf-8,${BOM}${rows.map(e => e.join(\";\")).join(\"\\n\")}`;\r\n\r\n var encodedUri = encodeURI(csvContent).replace(/#/g, \"%23\");\r\n var link = document.createElement(\"a\");\r\n link.setAttribute(\"href\", encodedUri);\r\n link.setAttribute(\"download\", \"chain_sortiment.csv\");\r\n document.body.appendChild(link); // Required for FF\r\n\r\n link.click(); // This will download the data file named \"chain_sortiment.csv\".\r\n\r\n\r\n } catch (error) {\r\n Logger.error(error);\r\n }\r\n };\r\n}\r\n","import \"../../../styles/kjedeweb/chainScroll.scss\";\r\n\r\nimport PropTypes from \"prop-types\";\r\nimport React from \"react\";\r\nimport { scssVariables } from \"../../common/util/config\";\r\n\r\n/**\r\n * Returnerar Icon node med icon kod inkluderad\r\n * \r\n * @param {object} props\r\n * @returns {node}\r\n */\r\nclass Scroll extends React.Component {\r\n constructor(props) {\r\n super(props);\r\n\r\n this.state = {\r\n topShadow: false,\r\n bottomShadow: false,\r\n leftShadow: false,\r\n rightShadow: false,\r\n\r\n lastCloseToBottomScrollTop: -1,\r\n };\r\n\r\n this.listenToScroll = this.listenToScroll.bind(this);\r\n this.setRef = this.setRef.bind(this);\r\n }\r\n\r\n componentDidMount() {\r\n this.listenToScroll();\r\n }\r\n\r\n UNSAFE_componentWillReceiveProps() {\r\n this.listenToScroll();\r\n }\r\n\r\n listenToScroll() {\r\n const {\r\n shadowX,\r\n shadowY,\r\n style,\r\n onCloseToBottom,\r\n } = this.props;\r\n const element = this.element;\r\n //test what needs a shadow\r\n const needTopShadow = element.offsetHeight < element.scrollHeight && shadowY && element.scrollTop > 0;\r\n const needBottomShadow = element.offsetHeight < element.scrollHeight && shadowY && element.scrollTop + element.offsetHeight !== element.scrollHeight;\r\n const needleftShadow = element.offsetWidth < element.scrollWidth && shadowX && element.scrollLeft > 0;\r\n const needRightShadow = element.offsetWidth < element.scrollWidth && shadowX && element.scrollLeft + element.offsetWidth !== element.scrollWidth;\r\n let lastCloseToBottomScrollTop = this.state.lastCloseToBottomScrollTop;\r\n //If we are close to the bottom, do the callback(onCloseToBottom)\r\n if (onCloseToBottom && style && element.scrollTop !== this.state.lastCloseToBottomScrollTop && element.scrollHeight - element.scrollTop < (parseInt(style.height) * 1.5)) {\r\n //position is used to protect against unecesary callbacks on UNSAFE_componentWillReceiveProps()\r\n lastCloseToBottomScrollTop = element.scrollTop;\r\n\r\n // Will be called multiple times on a single scroll\r\n clearTimeout(this.onScroll);\r\n this.onScroll = setTimeout(function () {\r\n onCloseToBottom();\r\n }, 50);\r\n }\r\n //update only if anything changed\r\n if (this.state.topShadow !== needTopShadow || this.state.bottomShadow !== needBottomShadow || this.state.leftShadow !== needleftShadow || this.state.rightShadow !== needRightShadow ||\r\n this.state.lastCloseToBottomScrollTop !== lastCloseToBottomScrollTop) {\r\n this.setState({\r\n topShadow: needTopShadow,\r\n bottomShadow: needBottomShadow,\r\n leftShadow: needleftShadow,\r\n rightShadow: needRightShadow,\r\n lastCloseToBottomScrollTop: lastCloseToBottomScrollTop,\r\n });\r\n }\r\n\r\n if (this.props.onScroll) {\r\n this.props.onScroll(element.scrollLeft, element.scrollTop);\r\n }\r\n }\r\n\r\n setRef(element) {\r\n this.element = element;\r\n }\r\n\r\n render() {\r\n const {\r\n children,\r\n style,\r\n className,\r\n shadowStyle,\r\n } = this.props;\r\n const {\r\n topShadow,\r\n bottomShadow,\r\n leftShadow,\r\n rightShadow,\r\n } = this.state;\r\n\r\n return (\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n {children}\r\n
\r\n
\r\n );\r\n }\r\n\r\n}\r\n\r\nScroll.propTypes = {\r\n children: PropTypes.node.isRequired,\r\n style: PropTypes.object,\r\n className: PropTypes.string,\r\n //If shadow should be used when overflowing on X\r\n shadowX: PropTypes.bool,\r\n //If shadow should be used when overflowing on Y\r\n shadowY: PropTypes.bool,\r\n //Style used by shadows\r\n shadowStyle: PropTypes.object,\r\n //Called when half the height is left on the scroll\r\n onCloseToBottom: PropTypes.func,\r\n onScroll: PropTypes.func\r\n};\r\n\r\nScroll.defaultProps = {\r\n shadowX: true,\r\n shadowY: true,\r\n};\r\n\r\nexport default Scroll;","import \"../../../styles/input.scss\";\r\n\r\nimport React, { Component } from \"react\";\r\n\r\nimport ChainScroll from \"./ChainScroll\";\r\nimport PropTypes from \"prop-types\";\r\n\r\nexport class ChainTabList extends Component {\r\n constructor(props) {\r\n super(props);\r\n\r\n this.setElement = this.setElement.bind(this);\r\n }\r\n\r\n setElement(element) {\r\n this.element = element;\r\n }\r\n\r\n render() {\r\n const {\r\n tabIndexSelected,\r\n onTabClick\r\n } = this.props;\r\n const tabChildrenWithProps = [];\r\n const otherChildren = [];\r\n\r\n React.Children.forEach(this.props.children, function (child, index) {\r\n if (child) {\r\n if (child.type === ChainTab) {\r\n tabChildrenWithProps.push(React.cloneElement(child, {\r\n tabSelected: tabIndexSelected === index,\r\n index: index,\r\n onTabClick: onTabClick,\r\n key: index\r\n }));\r\n } else {\r\n otherChildren.push(React.cloneElement(child, {\r\n key: index\r\n }));\r\n }\r\n }\r\n });\r\n return (\r\n
\r\n \r\n {tabChildrenWithProps}\r\n \r\n {otherChildren}\r\n
\r\n );\r\n }\r\n}\r\nChainTabList.propTypes = {\r\n children: PropTypes.node.isRequired,\r\n tabIndexSelected: PropTypes.number,\r\n // Private: Tabs will use this\r\n onTabClick: PropTypes.func,\r\n};\r\n\r\n\r\nexport class ChainTab extends Component {\r\n constructor(props) {\r\n super(props);\r\n\r\n this.onTabClick = this.onTabClick.bind(this);\r\n }\r\n\r\n onTabClick(e) {\r\n const {\r\n onTabClick,\r\n onClick,\r\n index\r\n } = this.props;\r\n if (onTabClick) {\r\n onTabClick(e, index);\r\n }\r\n if (onClick) {\r\n onClick(index);\r\n }\r\n }\r\n\r\n render() {\r\n const {\r\n tabSelected,\r\n label,\r\n logoUrl\r\n } = this.props;\r\n return (\r\n
\r\n
\r\n {logoUrl && (\r\n
\r\n

\r\n
\r\n )}\r\n {label}\r\n
\r\n
\r\n );\r\n }\r\n}\r\nChainTab.propTypes = {\r\n tabSelected: PropTypes.bool,\r\n label: PropTypes.string.isRequired,\r\n // Private: TabList will use this\r\n onTabClick: PropTypes.func,\r\n // Use this if you want a callback when tab is clicked\r\n onClick: PropTypes.func,\r\n index: PropTypes.number,\r\n id: PropTypes.string,\r\n logoUrl: PropTypes.string\r\n};\r\nChainTab.defaultProps = {\r\n tabSelected: false\r\n};\r\n\r\nexport class ChainTabPanel extends Component {\r\n render() {\r\n const {\r\n children,\r\n overflowHidden,\r\n onScroll\r\n } = this.props;\r\n\r\n return (\r\n
\r\n {children}\r\n
\r\n );\r\n }\r\n}\r\nChainTabPanel.propTypes = {\r\n children: PropTypes.node.isRequired,\r\n onScroll: PropTypes.func,\r\n overflowHidden: PropTypes.bool\r\n};\r\n\r\nexport class ChainTabs extends Component {\r\n constructor(props) {\r\n super(props);\r\n\r\n let selectIndex = 0;\r\n let count = 0;\r\n if (props.startTabId) {\r\n React.Children.forEach(props.children, child => {\r\n if (child.type === ChainTabList) {\r\n for (let i = 0; i < child.props.children.length; i++) {\r\n if (child.props.children[i].props && child.props.children[i].props.id === props.startTabId) {\r\n selectIndex = count;\r\n }\r\n count += child.props.children[i].type === ChainTab ? 1 : 0;\r\n }\r\n }\r\n });\r\n }\r\n this.state = {\r\n tabIndexSelected: selectIndex,\r\n };\r\n\r\n this.onTabClick = this.onTabClick.bind(this);\r\n }\r\n\r\n onTabClick(e, index) {\r\n e.stopPropagation();\r\n\r\n this.setState({\r\n tabIndexSelected: index\r\n });\r\n }\r\n\r\n\r\n render() {\r\n const childrenWithProps = [];\r\n let count = 0;\r\n //prepare the children with needed props\r\n React.Children.forEach(this.props.children, child => {\r\n //if the child is a TabList button on the otop\r\n if (child.type === ChainTabList) {\r\n childrenWithProps[childrenWithProps.length] = React.cloneElement(child, {\r\n tabIndexSelected: this.state.tabIndexSelected,\r\n onTabClick: this.onTabClick,\r\n key: -1\r\n });\r\n }\r\n //if it is a panel with all the content\r\n else {\r\n if (this.state.tabIndexSelected === count) {\r\n childrenWithProps[childrenWithProps.length] = React.cloneElement(child, {\r\n key: count\r\n });\r\n }\r\n count++;\r\n }\r\n });\r\n return (\r\n
\r\n {childrenWithProps}\r\n
\r\n );\r\n }\r\n}\r\n\r\nChainTabs.propTypes = {\r\n children: PropTypes.node.isRequired,\r\n startTabId: PropTypes.string,\r\n};\r\n\r\nChainTabs.defaultProps = {\r\n};\r\n","import \"../../../styles/kjedeweb/singleChainProductListItem.scss\";\r\n\r\nimport Icon, { iconColor, iconTypes } from \"../../common/components/Icon.jsx\";\r\n\r\nimport PropTypes from \"prop-types\";\r\nimport React from \"react\";\r\nimport moment from \"moment\";\r\nimport { toLocaleFixed } from \"../../common/util/localization.jsx\";\r\n\r\n/**\r\n * Creates a node component, used to display value, futureValue, future date\r\n * @param {object} props \r\n * @return {node}\r\n */\r\nfunction FuturePriceItem({currentValue, futureEndValue, futureEndValueDate}) {\r\n const futureDate = !futureEndValueDate ? moment() : moment(futureEndValueDate);\r\n\r\n return (\r\n
\r\n
\r\n {currentValue!=null && (\r\n
{toLocaleFixed(currentValue,2)}
\r\n )}\r\n {futureEndValueDate!=null && futureEndValue!=null && (\r\n
\r\n \r\n
\r\n
{toLocaleFixed(futureEndValue,2)}
\r\n
\r\n {futureDate.format(\"DD.MM.YYYY\")}
\r\n \r\n )}\r\n
\r\n
\r\n );\r\n}\r\nFuturePriceItem.propTypes = {\r\n currentValue: PropTypes.number,\r\n futureEndValue: PropTypes.number,\r\n futureEndValueDate: PropTypes.string,\r\n};\r\n\r\nexport default FuturePriceItem;","import \"../../../styles/kjedeweb/multiChainProductView.scss\";\r\n\r\nimport Icon, { iconColor, iconTypes } from \"../../common/components/Icon\";\r\nimport { SubMenu, SubMenuItem } from \"../../common/components/SubMenu.jsx\";\r\nimport { getInvoiceGroups, getMultiChainProductDetail, updateChainProducts } from \"../actions/multiChainSortiment.js\";\r\n\r\nimport Calendar from \"../../common/components/Calendar\";\r\nimport DropDownList from \"../../common/components/DropDownList\";\r\nimport { Localization } from \"../../common/util/localization.jsx\";\r\nimport Modal from \"../../common/components/Modal.jsx\";\r\nimport PropTypes from \"prop-types\";\r\nimport React from \"react\";\r\nimport TextField from \"../../common/components/TextField.jsx\";\r\nimport { connect } from \"react-redux\";\r\nimport { createReselector } from \"../../common/util/reselect\";\r\nimport { downloadHmsPdf } from \"../../kundeweb/util/productUtil.jsx\";\r\nimport { getChainLogo } from \"./MultiChainSortimentListItem\";\r\nimport moment from \"moment\";\r\nimport { setDropDown } from \"../../common/actions/modal.js\";\r\nimport { toLocaleFixed } from \"../../common/util/localization.jsx\";\r\n\r\n/**\r\n * Returnerar kalender komponent\r\n * \r\n * @param {object} props\r\n * @returns {node}\r\n */\r\nfunction CalendarDropdown({ setDropDown, dropDown, localization, date, validDates, previousDates, nextOrderDate, onSelectDate, source }) {\r\n /**\r\n * selects the date and hides the dropdown window\r\n * \r\n * @param {object} date\r\n * @returns {undefined}\r\n */\r\n function onClick(date) {\r\n setDropDown();\r\n onSelectDate(date, source);\r\n }\r\n\r\n const minDate = moment(new Date());\r\n const maxDate = moment(\"2100-01-01\");\r\n\r\n return (\r\n
\r\n );\r\n}\r\nCalendarDropdown.propTypes = {\r\n date: PropTypes.string,\r\n dropDown: PropTypes.bool,\r\n localization: Localization.propTypes.isRequired,\r\n nextOrderDate: PropTypes.string,\r\n setDropDown: PropTypes.func,\r\n onSelectDate: PropTypes.func,\r\n previousDates: PropTypes.arrayOf(PropTypes.string.isRequired),\r\n validDates: PropTypes.arrayOf(PropTypes.string.isRequired),\r\n source: PropTypes.object.isRequired\r\n};\r\n\r\n\r\n\r\nclass MultiChainProductModal extends React.PureComponent {\r\n constructor(props) {\r\n super(props);\r\n this.handleClickOutside = this.handleClickOutside.bind(this);\r\n this.fakeSetState = this.fakeSetState.bind(this);\r\n this.onClickPrintHms = this.onClickPrintHms.bind(this);\r\n //this.onDeleteProduct = this.onDeleteProduct.bind(this);\r\n this.onEditProductStatus = this.onEditProductStatus.bind(this);\r\n //this.onEditProductCatalogue = this.onEditProductCatalogue.bind(this);\r\n this.onEditInvoiceGroup = this.onEditInvoiceGroup.bind(this);\r\n this.onEditNewAdmCharge = this.onEditNewAdmCharge.bind(this);\r\n this.onSaveChanges = this.onSaveChanges.bind(this);\r\n this.onSelectAdmDate = this.onSelectAdmDate.bind(this);\r\n this.onSelectDate = this.onSelectDate.bind(this);\r\n this.shouldComponentRender = this.shouldComponentRender.bind(this);\r\n this.state = { editProducts: {} };\r\n\r\n this.start = true;\r\n }\r\n\r\n componentDidMount() {\r\n if (!this.shouldComponentRender() || this.start) {\r\n this.start = false;\r\n (async () => {\r\n await this.props.getInvoiceGroups();\r\n const productDetails = await this.props.getMultiChainProductDetail(this.props.chainIds, this.props.product.productId, this.props.product.imageUrl);\r\n // eslint-disable-next-line react/no-did-mount-set-state\r\n this.setState({\r\n editProducts: productDetails\r\n });\r\n })();\r\n }\r\n }\r\n\r\n componentDidUpdate(prevProps) {\r\n if (this.shouldComponentRender() && prevProps.productDetails != this.props.productDetails) {\r\n this.fakeSetState();\r\n }\r\n }\r\n\r\n fakeSetState() {\r\n this.setState({ editProducts: this.props.productDetails });\r\n }\r\n\r\n handleClickOutside() {\r\n if (this.props.onCloseModal) {\r\n this.props.onCloseModal();\r\n }\r\n }\r\n\r\n shouldComponentRender = () => Object.values(this.props.productDetails).find(d => d.productId);\r\n\r\n onEditProductStatus(change, source) {\r\n this.setState(prevState => ({\r\n editProducts: { // object that we want to update\r\n ...prevState.editProducts,\r\n [source.chainId]: {\r\n ...prevState.editProducts[source.chainId],\r\n inCatalogue: change.inCatalogue\r\n }\r\n }\r\n }));\r\n }\r\n\r\n // onEditProductCatalogue(change, source) {\r\n // this.setState(prevState => ({\r\n // editProducts: { // object that we want to update\r\n // ...prevState.editProducts,\r\n // [source.chainId]: {\r\n // ...prevState.editProducts[source.chainId],\r\n // inCatalogue: change.inCatalogue // update the value of specific key\r\n // }\r\n // }\r\n // }));\r\n // }\r\n\r\n onEditInvoiceGroup(change, source) {\r\n\r\n const ig = this.props.invoiceGroups.find(ig => ig.invoiceCode === change.invoiceGroupId);\r\n const igName = this.capitalizeFirstLetter(ig.description);\r\n\r\n this.setState(prevState => ({\r\n editProducts: { // object that we want to update\r\n ...prevState.editProducts,\r\n [source.chainId]: {\r\n ...prevState.editProducts[source.chainId],\r\n invoiceGroupId: change.invoiceGroupId,\r\n invoiceGroupName: igName\r\n }\r\n }\r\n }));\r\n }\r\n\r\n onEditNewAdmCharge(change, source) {\r\n const testAdmCharge = Number(change.futureAdminCharge);\r\n if (isNaN(testAdmCharge)) {\r\n //console.log(\"Ukjent verdi \", change.futureAdminCharge);\r\n }\r\n else {\r\n this.setState(prevState => ({\r\n editProducts: { // object that we want to update\r\n ...prevState.editProducts,\r\n [source.chainId]: {\r\n ...prevState.editProducts[source.chainId],\r\n futureAdminCharge: testAdmCharge // update the value of specific key\r\n }\r\n }\r\n }));\r\n }\r\n }\r\n onSelectDate(date, source) {\r\n this.setState(prevState => ({\r\n editProducts: { // object that we want to update\r\n ...prevState.editProducts,\r\n [source.chainId]: {\r\n ...prevState.editProducts[source.chainId],\r\n futureEndPriceDate: date // update the value of specific key\r\n }\r\n }\r\n }));\r\n }\r\n onSelectAdmDate(date, source) {\r\n this.setState(prevState => ({\r\n editProducts: { // object that we want to update\r\n ...prevState.editProducts,\r\n [source.chainId]: {\r\n ...prevState.editProducts[source.chainId],\r\n futureAdminChargeDate: date // update the value of specific key\r\n }\r\n }\r\n }));\r\n }\r\n\r\n // onDeleteProduct() {\r\n // this.setState(prevState => ({\r\n // editProducts: Object.assign({}, ...Object.keys(prevState.editProducts).map(chainId => ({\r\n // [chainId]: {\r\n // ...prevState.editProducts[chainId],\r\n // inCatalogue: false\r\n // }\r\n // })))\r\n // }));\r\n // }\r\n\r\n capitalizeFirstLetter(s) {\r\n s = s.toLowerCase();\r\n return s.charAt(0).toUpperCase() + s.slice(1);\r\n }\r\n\r\n validateNewPrice() {\r\n return true;\r\n }\r\n\r\n getDropDownDateStyle() {\r\n return {\r\n width: 450,\r\n };\r\n }\r\n\r\n onClickPrintHms() {\r\n this.props.downloadHmsPdf(this.props.token, this.props.product, true);\r\n }\r\n\r\n onSaveChanges() {\r\n this.props.updateChainProducts([...Object.values(this.state.editProducts)]);\r\n //this.props.onCloseModal(event);\r\n }\r\n\r\n\r\n render() {\r\n const {\r\n chainIds,\r\n invoiceGroups,\r\n localization,\r\n onCloseModal,\r\n productDetails,\r\n saveButtonText,\r\n setDropDown,\r\n title,\r\n width,\r\n chains,\r\n } = this.props;\r\n\r\n // Check if data has been loaded, if not just return empty component\r\n if (!this.shouldComponentRender()) return
;\r\n\r\n const statusOptions = [{ value: true, label: \"Åpen\" }, { value: false, label: \"Stengt\" }];\r\n //const catalogueOptions = [{ value: true, label: \"I varekatalog\" }, { value: false, label: \"Ikke i varekatalog\" }];\r\n const invoiceGroupOptions = invoiceGroups.map(ig => { return { value: ig.invoiceCode, label: this.capitalizeFirstLetter(ig.description) }; });\r\n\r\n const productDetail = Object.values(productDetails)[0];\r\n\r\n const anyOpen = Object.values(productDetails).some(pd => pd.inCatalogue);\r\n const currentInprice = `${toLocaleFixed(productDetail.currentInPrice, 2)}`;\r\n const currentInpriceText = anyOpen ? `${currentInprice}` : \"\";\r\n const futureInprice = `${toLocaleFixed(productDetail.futureInPrice, 2)}`;\r\n const futureInpriceDate = `${productDetail.futureInPriceDate && moment(productDetail.futureInPriceDate).format(\"DD.MM.YY\")}`;\r\n const futureInpriceText = anyOpen && productDetail.futureInPrice ? `${futureInprice} (Gjelder fra ${futureInpriceDate})` : \"\";\r\n\r\n\r\n const userChains = [...chainIds.map(id => chains[id]).filter(c => c)];\r\n const editInvoiceGroup = userChains.some(c => c.webEditInvoiceGroupEndPrice);\r\n\r\n let iconType = iconTypes.x;\r\n if (productDetail.productStorageType == \"Tørr\") {\r\n iconType = iconTypes.box;\r\n } else if (productDetail.productStorageType == \"Frys\") {\r\n iconType = iconTypes.snowflake;\r\n } else if (productDetail.productStorageType == \"Kjøl\") {\r\n iconType = iconTypes.fridge;\r\n }\r\n\r\n const canSubmit = (saveButtonText == \"Lagre\");\r\n\r\n return (\r\n
\r\n \r\n
\r\n
\r\n
\r\n
{title}
\r\n
\r\n
{this.props.product.productName}
\r\n
EPD {this.props.product.epdNo}
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
Varestatus
\r\n
{/*Varekatalog*/}
\r\n { editInvoiceGroup && (\r\n
Fakturagruppe
\r\n )} \r\n
Adm gebyr (%)
\r\n
\r\n {chainIds.map(chainId => [this.state.editProducts[chainId], productDetails[chainId]]).map(([editProduct, productDetail]) => {\r\n if (!editProduct || !productDetail) {\r\n return null;\r\n }\r\n\r\n const chain = chains[editProduct.chainId];\r\n const chainLogo = getChainLogo(chain && chain.chainLogoFileName);\r\n \r\n const futureAdmDate = !editProduct.futureAdminChargeDate ? productDetail.futureAdminChargeDate : editProduct.futureAdminChargeDate;\r\n const futureAdmDateForDropDown = !futureAdmDate ? moment() : moment(futureAdmDate);\r\n const futureAdmDateForDisplay = !futureAdmDate ? \"Sett dato\" : moment(futureAdmDate).format(\"DD.MM.YYYY\");\r\n const futureAdmReadOnlyChains = !futureAdmDate ? \"\" : `${toLocaleFixed(productDetail.currentNetPricePerSalesUnit, 2)} (fra ${futureAdmDateForDisplay})`;\r\n\r\n const previousDates = [];\r\n const validDates = [];\r\n \r\n const iconAvailable = editProduct.inCatalogue ? \"circle-green\" : \"circle-red\";\r\n //const iconInCatalogue = editProduct.inCatalogue ? \"circle-blue\" : undefined;\r\n\r\n return (\r\n
\r\n
\r\n

\r\n
\r\n
\r\n \r\n
\r\n
\r\n {/**/}\r\n
\r\n { chain.webEditInvoiceGroupEndPrice && (\r\n
\r\n \r\n
\r\n )}\r\n
\r\n
\r\n {toLocaleFixed(productDetail.currentAdminChargePercent, 2)}\r\n
\r\n {productDetail.adminChargeEditable ? (\r\n
\r\n \r\n \r\n \r\n {futureAdmDateForDisplay}
)} flex={true} disableDimScreen={true} dropDownStyle={this.getDropDownDateStyle()} expand={true} dropDownShiftLeft={true} setDropDown={setDropDown} dropDownChildren={(\r\n \r\n )} />\r\n \r\n \r\n {/* Ifall ett datum och en tid är satta - och det finns minst en annan rad vars motsvarande värden skiljer sig från detta datum och tid, lägg in en knapp för att kopiera värdena till de andra raderna. */}\r\n {(futureAdmDate && editProduct.futureAdminCharge != null && editProduct.futureAdminCharge != \"\" &&\r\n Object.values(this.state.editProducts).find(p => p !== editProduct && (p.futureAdminChargeDate != futureAdmDate || p.futureAdminCharge != editProduct.futureAdminCharge))) && (\r\n
\r\n )}\r\n \r\n ) : \r\n
\r\n { futureAdmReadOnlyChains }\r\n
\r\n }\r\n \r\n
\r\n
\r\n );\r\n })}\r\n
\r\n
\r\n
\r\n
\r\n
{\"Priser per kjede\"}
\r\n {userChains.map(chain => {\r\n return (
{chain.chainName}
);\r\n })}\r\n
\r\n\r\n
\r\n
\r\n {userChains.map(chain => {\r\n return (\r\n
\r\n
{\"Gjeldende\"}
\r\n
{\"Fremtidig\"}
\r\n
);\r\n })}\r\n
\r\n\r\n
\r\n
\r\n {chainIds.map(chainId => [productDetails[chainId]]).map(([productDetail]) => {\r\n return (\r\n
\r\n
\r\n
{productDetail.futureCustomerBasePriceDate && moment(productDetail.futureCustomerBasePriceDate).format(\"DD.MM.YY\")}
\r\n
);\r\n })}\r\n
\r\n\r\n
\r\n
{localization.text(\"chain\", \"chainSortiment\", \"netPrice\")}
\r\n {chainIds.map(chainId => [productDetails[chainId]]).map(([productDetail]) => {\r\n return (\r\n
\r\n
{toLocaleFixed(productDetail.currentNetPrice, 2)}
\r\n
{toLocaleFixed(productDetail.futureNetPrice, 2)}
\r\n
);\r\n })} \r\n
\r\n
\r\n
{localization.text(\"chain\", \"chainSortiment\", \"netPricePerUnit\")}
\r\n {chainIds.map(chainId => [productDetails[chainId]]).map(([productDetail]) => {\r\n return (\r\n
\r\n
{toLocaleFixed(productDetail.currentNetPricePerSalesUnit, 2)}
\r\n
{toLocaleFixed(productDetail.futureNetPricePerSalesUnit, 2)}
\r\n
);\r\n })}\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"basePriceForAdminCharge\")}
\r\n {chainIds.map(chainId => [productDetails[chainId]]).map(([productDetail]) => {\r\n return (\r\n
\r\n
{toLocaleFixed(productDetail.basePriceForAdminCharge, 2)}
\r\n
{toLocaleFixed(productDetail.futureBasePriceForAdminCharge, 2)}
\r\n
);\r\n })}\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"basePriceWithChargesExclAdminCharge\")}
\r\n {chainIds.map(chainId => [productDetails[chainId]]).map(([productDetail]) => {\r\n return (\r\n
\r\n
{toLocaleFixed(productDetail.customerBasePriceWithChargesExclAdminCharge, 2)}
\r\n
{toLocaleFixed(productDetail.futureCustomerBasePriceWithChargesExclAdminCharge, 2)}
\r\n
);\r\n })}\r\n
\r\n\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"currentCusBasePrice\")}
\r\n {chainIds.map(chainId => [productDetails[chainId]]).map(([productDetail]) => {\r\n return (\r\n
\r\n
{toLocaleFixed(productDetail.currentCustomerBasePrice, 2)}
\r\n
{toLocaleFixed(productDetail.futureCustomerBasePrice, 2)}
\r\n
);\r\n })}\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"campaignPrice\")}
\r\n {chainIds.map(chainId => [productDetails[chainId]]).map(([productDetail]) => {\r\n return (\r\n
\r\n
\r\n
{productDetail.currentCampaignPercent}
\r\n
{productDetail.currentCampaignPeriod}
\r\n
\r\n
\r\n
{productDetail.futureCampaignPercent}
\r\n
{productDetail.futureCampaignPeriod}
\r\n
\r\n
);\r\n })}\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n

\r\n
\r\n {/*
\r\n \r\n
*/}\r\n
\r\n
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"eanNoSalesUnit\")}
\r\n
{productDetail.eanNoSalesUnit}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"eanNoWarehouseUnit\")}
\r\n
{productDetail.eanNoWarehouseUnit}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"epProductId\")}
\r\n
{productDetail.productId}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"supplierName\")}
\r\n
{productDetail.supplierName}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"supplierProductid\")}
\r\n
{productDetail.supplierProductId}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"category\")}
\r\n
{productDetail.category}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"calcGroup\")}
\r\n
{productDetail.calcGroup}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"storageType\")}
\r\n
\r\n
{productDetail.productStorageType}
\r\n
\r\n
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"status\")}
\r\n
{productDetail.status}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"chainSortiment\", \"noOfSalesUnits\")}
\r\n
{productDetail.noOfSalesUnits}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"weightSalesUnit\")}
\r\n
{toLocaleFixed(productDetail.weightSalesUnit, 3)}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"heightSalesUnit\")}
\r\n
{toLocaleFixed(productDetail.heightSalesUnit, 3)}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"lengthSalesUnit\")}
\r\n
{toLocaleFixed(productDetail.lengthSalesUnit, 3)}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"widthSalesUnit\")}
\r\n
{toLocaleFixed(productDetail.widthSalesUnit, 3)}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"noOfUnitsInPackage\")}
\r\n
{productDetail.noOfUnitsInPackage}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"uniqueForChain\")}
\r\n
{productDetail.uniqueForChain}
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"depositAmountWarehouseAndSalesUnit\")}
\r\n
{productDetail.depositAmountWarehouseAndSalesUnit}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"currentInPrice\")}
\r\n
{currentInpriceText}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"futureInPrice\")}
\r\n
{futureInpriceText}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"linkProductId\")}
\r\n
{productDetail.linkProductId}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"replacingProductIds\")}
\r\n
{productDetail.replacingProductIds}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"durabilityDays\")}
\r\n
{productDetail.durabilityDays}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"weight\")}
\r\n
{toLocaleFixed(productDetail.weight, 2)}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"useSalesUnit\")}
\r\n
{productDetail.useSalesUnit ? \"Ja\" : \"Nei\" }
\r\n
\r\n
\r\n
{productDetail.campaignInfo}
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n\r\n \r\n
\r\n \r\n
\r\n
\r\n \r\n \r\n
\r\n
\r\n \r\n \r\n );\r\n }\r\n}\r\nMultiChainProductModal.propTypes = {\r\n chainIds: PropTypes.array.isRequired,\r\n chains: PropTypes.object.isRequired,\r\n chainType: PropTypes.number.isRequired,\r\n downloadHmsPdf: PropTypes.func.isRequired,\r\n getInvoiceGroups: PropTypes.func.isRequired,\r\n getMultiChainProductDetail: PropTypes.func.isRequired,\r\n invoiceGroups: PropTypes.array.isRequired,\r\n isLoading: PropTypes.bool.isRequired,\r\n localization: Localization.propTypes.isRequired,\r\n onCloseModal: PropTypes.func.isRequired,\r\n product: PropTypes.object.isRequired,\r\n productDetails: PropTypes.object.isRequired,\r\n saveButtonText: PropTypes.string,\r\n title: PropTypes.string,\r\n token: PropTypes.string.isRequired,\r\n updateChainProducts: PropTypes.func.isRequired,\r\n width: PropTypes.number.isRequired,\r\n setDropDown: PropTypes.func.isRequired,\r\n};\r\n\r\nconst mapStateToProps = () => {\r\n const chainIdsReselector = createReselector((chainIds, chains) => {\r\n const userChains = [...chainIds.map(id => chains[id]).filter(c => c)];\r\n userChains.sort((a, b) => a.chainName.localeCompare(b.chainName));\r\n const ids = userChains.map(uc => uc.chainId);\r\n return ids;\r\n });\r\n \r\n return (state) => ({\r\n chainIds: chainIdsReselector(state.authentication.chainIds, state.multiChainSortiment.chains),\r\n chains: state.multiChainSortiment.chains,\r\n chainType: state.authentication.chainType,\r\n deviceType: state.view.deviceType,\r\n invoiceGroups: state.multiChainSortiment.invoiceGroups,\r\n isLoading: state.multiChainSortiment.isLoading,\r\n productDetails: state.multiChainSortiment.productDetails,\r\n token: state.authentication.token,\r\n });\r\n};\r\n\r\nconst mapDispatchToProps = {\r\n downloadHmsPdf,\r\n getInvoiceGroups,\r\n getMultiChainProductDetail,\r\n updateChainProducts,\r\n setDropDown,\r\n};\r\n\r\nexport default connect(mapStateToProps, mapDispatchToProps)(MultiChainProductModal);\r\n","import { getApi, getEncodedSearchString, postApi } from \"../../common/actions/net.js\";\r\nimport { getExistingProductImage, loadProductImage } from \"../../kundeweb/actions/productImage.js\";\r\nimport { messageType, pushSystemMessage } from \"../../common/actions/systemMessage.js\";\r\nimport Logger from \"../../common/util/Logger.js\";\r\n\r\nexport const SET_SINGLE_CHAIN_SORTIMENT = \"SET_SINGLE_CHAIN_SORTIMENT\";\r\nexport const ADD_SINGLE_CHAIN_SORTIMENT = \"ADD_SINGLE_CHAIN_SORTIMENT\";\r\nexport const SET_QUERY_PRODUCT_IMAGE_URL = \"SET_QUERY_PRODUCT_IMAGE_URL\";\r\nexport const SINGLE_CHAIN_SORTIMENT_IS_LOADING = \"SINGLE_CHAIN_SORTIMENT_IS_LOADING\";\r\nexport const SINGLE_CHAIN_QUERY_DONE_LOADING = \"SINGLE_CHAIN_QUERY_DONE_LOADING\";\r\nexport const SINGLE_CHAIN_QUERY_FAILED_LOADING = \"SINGLE_CHAIN_QUERY_DONE_LOADING\";\r\nexport const SINGLE_CHAIN_QUERY_ALL_LOADED = \"SINGLE_CHAIN_QUERY_ALL_LOADED\";\r\nexport const EDIT_SINGLE_CHAIN_FILTER = \"EDIT_SINGLE_CHAIN_FILTER\";\r\nexport const CLEAR_SINGLE_CHAIN_SORTIMENT = \"CLEAR_SINGLE_CHAIN_SORTIMENT\";\r\nexport const SET_SINGLE_CHAIN_SORTIMENT_FILTER = \"SET_SINGLE_CHAIN_SORTIMENT_FILTER\";\r\n\r\nexport const SET_SINGLE_CHAIN_PRODUCT_DETAIL = \"SET_SINGLE_CHAIN_PRODUCT_DETAIL\";\r\nexport const CLEAR_SINGLE_CHAIN_PRODUCT_DETAIL = \"CLEAR_SINGLE_CHAIN_PRODUCT_DETAIL\";\r\nexport const UPDATE_SINGLE_CHAIN_PRODUCT_LIST = \"UPDATE_SINGLE_CHAIN_PRODUCT_LIST\";\r\nexport const SET_INVOICE_GROUPS = \"SET_INVOICE_GROUPS\";\r\nexport const SET_QUERY_OPTION = \"SET_QUERY_OPTION\";\r\n\r\nexport const SET_MULTI_SELECT = \"SET_MULTI_SELECT\";\r\nexport const CLEAR_MULTI_SELECT = \"CLEAR_MULTI_SELECT\";\r\n\r\nconst setQueryProductImageUrl = (index, imageUrl) => ({\r\n type: SET_QUERY_PRODUCT_IMAGE_URL,\r\n index,\r\n imageUrl\r\n});\r\n\r\nconst setSingleChainSortimentIsLoading = () => ({\r\n type: SINGLE_CHAIN_SORTIMENT_IS_LOADING\r\n});\r\nconst setSingleChainSortimentDoneLoading = () => ({\r\n type: SINGLE_CHAIN_QUERY_DONE_LOADING\r\n});\r\nconst setSingleChainSortimentFailedLoading = () => ({\r\n type: SINGLE_CHAIN_QUERY_FAILED_LOADING\r\n});\r\n\r\nconst setSingleChainSortimentAllLoaded = () => ({\r\n type: SINGLE_CHAIN_QUERY_ALL_LOADED\r\n});\r\n\r\n/**\r\n * Downloads more single chain sortiment items\r\n * @param {object} singleChainSortiment\r\n * @param {object} productImage\r\n * @param {number} noOfProducts\r\n * @returns {func}\r\n */\r\nexport function loadMoreSingleChainSortiment(singleChainSortiment, productImage, noOfProducts = 50) {\r\n return async (dispatch, getState) => {\r\n try {\r\n //make sure there is something new to load\r\n if (singleChainSortiment.allResultsLoaded) {\r\n return;\r\n }\r\n\r\n //start collection new lines\r\n dispatch(setSingleChainSortimentIsLoading());\r\n\r\n const startIndex = singleChainSortiment.chainProducts.length;\r\n\r\n // Load in more products\r\n const { payload } = await dispatch(\r\n getApi(\"Chain/ProductsFreeTextQuery\", {\r\n chainType: getState().authentication.chainType,\r\n onlyAvailableForChain: true,\r\n noOfProducts: noOfProducts,\r\n startIndex: startIndex,\r\n freeText: getEncodedSearchString(singleChainSortiment.chainFilter.searchString),\r\n supplierId: singleChainSortiment.chainFilter.supplierId ? singleChainSortiment.chainFilter.supplierId : undefined,\r\n productGroupId: singleChainSortiment.chainFilter.productGroupId ? singleChainSortiment.chainFilter.productGroupId : undefined,\r\n InvoiceGroup: singleChainSortiment.chainFilter.invoiceGroupId ? singleChainSortiment.chainFilter.invoiceGroupId : undefined,\r\n ProductStatus: singleChainSortiment.chainFilter.productStatus >= 0 ? singleChainSortiment.chainFilter.productStatus : undefined,\r\n onlyNews: singleChainSortiment.chainFilter.onlyNews,\r\n })\r\n );\r\n\r\n // Check if all data has been loaded\r\n if (payload.products.length != noOfProducts) {\r\n dispatch(setSingleChainSortimentAllLoaded());\r\n }\r\n\r\n // Insert existing images\r\n for (let i = 0; i < payload.products.length; i++) {\r\n payload.products[i].imageUrl = getExistingProductImage(payload.products[i].productId);\r\n }\r\n // Convert to default layout\r\n const prdList = payload.products.map(prd => {\r\n return { product: prd };\r\n });\r\n\r\n // Store query results\r\n await dispatch({ type: ADD_SINGLE_CHAIN_SORTIMENT, chainProducts: prdList });\r\n\r\n // Download all images not already inserted\r\n for (let index = 0; index < prdList.length; index++) {\r\n if (!prdList[index].product.imageUrl || prdList[index].product.imageUrl.length === 0) {\r\n const callback = imageUrl => dispatch(setQueryProductImageUrl(startIndex + index, imageUrl));\r\n dispatch(loadProductImage(productImage, prdList[index].product.productId, prdList[index].product.imageFileName, callback));\r\n }\r\n }\r\n\r\n dispatch(setSingleChainSortimentDoneLoading());\r\n } catch (error) {\r\n dispatch(setSingleChainSortimentFailedLoading());\r\n dispatch(pushSystemMessage(error && error.message || \"Lasting av flere varer mislyktes\", messageType.error));\r\n Logger.error(error);\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Changes the query filter\r\n * @param {object} change\r\n * @param {func} callback // function will be called when the state has been updated\r\n * @returns {func}\r\n */\r\nexport function editSingleChainFilter(change, callback) {\r\n return async dispatch => {\r\n await dispatch({\r\n type: EDIT_SINGLE_CHAIN_FILTER,\r\n change\r\n });\r\n\r\n try {\r\n dispatch(setSingleChainSortimentIsLoading());\r\n await callback();\r\n } catch (error) {\r\n Logger.error(error);\r\n } finally {\r\n dispatch(setSingleChainSortimentDoneLoading());\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Clears the single chain sortiment\r\n * @returns {func}\r\n */\r\nexport function clearSingleChainSortiment() {\r\n return async dispatch => {\r\n dispatch({\r\n type: CLEAR_SINGLE_CHAIN_SORTIMENT\r\n });\r\n };\r\n}\r\n\r\n/**\r\n * Sets the single chain sortiment filter \"OnlyAvailableForChain\" flag\r\n * @param {object} change\r\n * @returns {func}\r\n */\r\nexport function setSingleChainSortimentFilter(change) {\r\n return async dispatch => {\r\n dispatch({\r\n type: SET_SINGLE_CHAIN_SORTIMENT_FILTER,\r\n change\r\n });\r\n };\r\n}\r\n\r\n/**\r\n * Changes the query filter\r\n * @returns {func}\r\n */\r\nexport function prepareQueryOptions() {\r\n return async (dispatch, getState) => {\r\n const state = getState();\r\n const payload = await dispatch(getApi(\"Chain/FilterOptionsQuery\", {\r\n chainType: state.authentication.chainType}));\r\n dispatch({\r\n type: SET_QUERY_OPTION,\r\n productGroups: payload ? payload.payload.productGroups : null,\r\n productSuppliers: payload ? payload.payload.suppliers : null\r\n });\r\n };\r\n}\r\n\r\n/**\r\n * Gets product details for the given product id\r\n * @param {number} chainId\r\n * @param {string} productId\r\n * @param {string} imageUrl\r\n * @returns {function.}\r\n */\r\nexport function getSingleChainProductDetail(chainId, productId, imageUrl) {\r\n return async dispatch => {\r\n try {\r\n // Call webApi to make Products details request\r\n const { payload: productDetail } = await dispatch(getApi(\"Chain/ProductsDetailQuery\", { chainId, productId }));\r\n productDetail.imageUrl = imageUrl;\r\n\r\n dispatch({\r\n type: SET_SINGLE_CHAIN_PRODUCT_DETAIL,\r\n productDetail\r\n });\r\n } catch (error) {\r\n dispatch(pushSystemMessage(error && error.message || \"Innlasting av varedetaljer mislyktes\", messageType.error));\r\n Logger.error(error);\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Clears chain product detail modal\r\n * @returns {function.}\r\n */\r\nexport function clearChainProductDetails() {\r\n return async dispatch => {\r\n try {\r\n dispatch({\r\n type: CLEAR_SINGLE_CHAIN_PRODUCT_DETAIL\r\n });\r\n } catch (error) {\r\n Logger.error(error);\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Gets invoice groups\r\n * @returns {function.}\r\n */\r\nexport function getInvoiceGroups() {\r\n return async dispatch => {\r\n try {\r\n // Call webApi to get a list of invoice groups\r\n const { payload: invoiceGroups } = await dispatch(getApi(\"Chain/InvoiceGroupsQuery\"));\r\n\r\n dispatch({\r\n type: SET_INVOICE_GROUPS,\r\n invoiceGroups\r\n });\r\n } catch (error) {\r\n dispatch(pushSystemMessage(error && error.message || \"Lasting av fakturagruppe mislyktes\", messageType.error));\r\n Logger.error(error);\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Sets if the product is selected ot not\r\n * @param {object} change\r\n * @returns {function}\r\n */\r\nexport function editSelectedProduct(change) {\r\n return async dispatch => {\r\n try {\r\n dispatch({\r\n type: SET_MULTI_SELECT,\r\n change,\r\n });\r\n } catch (error) {\r\n Logger.error(error);\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Clears all multi selected products\r\n * @returns {function}\r\n */\r\nexport function clearSelectedProducts() {\r\n return async dispatch => {\r\n try {\r\n dispatch({\r\n type: CLEAR_MULTI_SELECT,\r\n });\r\n } catch (error) {\r\n Logger.error(error);\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Commit product changes\r\n * @param {number} chainType\r\n * @param {array} products\r\n * @returns {func}\r\n */\r\nexport function updateChainProducts(chainType, products) {\r\n return async dispatch => {\r\n try {\r\n // dispatch({\r\n // type: UPDATE_PRODUCTS,\r\n // committing: true,\r\n // });\r\n\r\n const payload = await dispatch(\r\n postApi(\"Chain/UpdateChainProductsCommand\", {\r\n chainType: chainType,\r\n productsToUpdate: products.map(p => {\r\n return {\r\n chainId: p.chainId,\r\n productId: p.productId,\r\n isAvailable: p.isAvailable,\r\n inCatalogue: p.inCatalogue,\r\n invoiceGroupId: p.invoiceGroupId,\r\n sortimentCode: p.sortimentCode,\r\n futureEndPrice: p.futureEndPrice,\r\n futureEndPriceDate: p.futureEndPriceDate,\r\n futureAdminCharge: p.futureAdminCharge,\r\n futureAdminChargeDate: p.futureAdminChargeDate\r\n };\r\n })\r\n })\r\n );\r\n\r\n if (payload && payload.message === \"OK\") {\r\n dispatch(pushSystemMessage(\"Varer ble oppdatert!\", messageType.message));\r\n // history.push(\"/dashboard\");\r\n // dispatch({\r\n // type: CLEAR_CLAIM,\r\n // });\r\n\r\n // Call reducer that updates the product in the list from free text search\r\n dispatch({ type: UPDATE_SINGLE_CHAIN_PRODUCT_LIST, products });\r\n } else {\r\n dispatch(pushSystemMessage(payload && payload.displayMessage || \"Kan ikke oppdatere varer\", messageType.error));\r\n }\r\n } catch (error) {\r\n dispatch(pushSystemMessage(error && error.message || \"Mislyktes til oppdatere varer\", messageType.error));\r\n Logger.error(error);\r\n } finally {\r\n // dispatch({\r\n // type: UPDATE_PRODUCTS,\r\n // committing: false,\r\n // });\r\n }\r\n };\r\n}\r\n","import \"../../../styles/kjedeweb/chainProductView.scss\";\r\n\r\nimport Icon, { iconColor, iconTypes } from \"../../common/components/Icon\";\r\nimport { SubMenu, SubMenuItem } from \"../../common/components/SubMenu.jsx\";\r\nimport { getInvoiceGroups, getSingleChainProductDetail, updateChainProducts } from \"../actions/singleChainSortiment.js\";\r\n\r\nimport Calendar from \"../../common/components/Calendar\";\r\nimport DropDownList from \"../../common/components/DropDownList\";\r\nimport { Localization } from \"../../common/util/localization.jsx\";\r\nimport Modal from \"../../common/components/Modal.jsx\";\r\nimport PropTypes from \"prop-types\";\r\nimport React from \"react\";\r\nimport TextField from \"../../common/components/TextField.jsx\";\r\nimport { connect } from \"react-redux\";\r\nimport { downloadHmsPdf } from \"../../kundeweb/util/productUtil.jsx\";\r\nimport moment from \"moment\";\r\nimport { setDropDown } from \"../../common/actions/modal.js\";\r\nimport { toLocaleFixed } from \"../../common/util/localization.jsx\";\r\n\r\n/**\r\n * Returnerar kalender komponent\r\n * \r\n * @param {object} props\r\n * @returns {node}\r\n */\r\nfunction CalendarDropdown({ setDropDown, dropDown, localization, date, validDates, previousDates, nextOrderDate, onSelectDate }) {\r\n /**\r\n * selects the date and hides the dropdown window\r\n * \r\n * @param {object} date\r\n * @returns {undefined}\r\n */\r\n function onClick(date) {\r\n setDropDown();\r\n onSelectDate(date);\r\n }\r\n const minDate = moment(new Date());\r\n const maxDate = moment(\"2100-01-01\");\r\n\r\n return (\r\n \r\n );\r\n}\r\nCalendarDropdown.propTypes = {\r\n date: PropTypes.string,\r\n dropDown: PropTypes.bool,\r\n localization: Localization.propTypes.isRequired,\r\n nextOrderDate: PropTypes.string,\r\n setDropDown: PropTypes.func,\r\n onSelectDate: PropTypes.func,\r\n previousDates: PropTypes.arrayOf(PropTypes.string.isRequired),\r\n validDates: PropTypes.arrayOf(PropTypes.string.isRequired),\r\n};\r\n\r\n\r\n\r\nclass SingleChainProductModal extends React.PureComponent {\r\n constructor(props) {\r\n super(props);\r\n this.handleClickOutside = this.handleClickOutside.bind(this);\r\n this.fakeSetState = this.fakeSetState.bind(this);\r\n this.onClickPrintHms = this.onClickPrintHms.bind(this);\r\n //this.onDeleteProduct = this.onDeleteProduct.bind(this);\r\n this.onEditProductStatus = this.onEditProductStatus.bind(this);\r\n //this.onEditProductCatalogue = this.onEditProductCatalogue.bind(this);\r\n this.onEditInvoiceGroup = this.onEditInvoiceGroup.bind(this);\r\n this.onEditNewAdmCharge = this.onEditNewAdmCharge.bind(this);\r\n this.onSaveChanges = this.onSaveChanges.bind(this);\r\n this.onSelectAdmDate = this.onSelectAdmDate.bind(this);\r\n this.shouldComponentRender = this.shouldComponentRender.bind(this);\r\n this.state = { editProduct: this.props.product };\r\n\r\n this.start = true;\r\n }\r\n\r\n componentDidMount() {\r\n if (!this.shouldComponentRender() || this.start) {\r\n this.start = false;\r\n (async () => {\r\n await this.props.getInvoiceGroups();\r\n await this.props.getSingleChainProductDetail(this.props.product.chainId, this.props.product.productId, this.props.product.imageUrl);\r\n })();\r\n }\r\n }\r\n\r\n componentDidUpdate(prevProps) {\r\n if (this.shouldComponentRender() && prevProps.productDetail != this.props.productDetail) {\r\n this.fakeSetState();\r\n }\r\n }\r\n\r\n fakeSetState() {\r\n this.setState({ editProduct: this.props.productDetail });\r\n }\r\n\r\n handleClickOutside() {\r\n if (this.props.onCloseModal) {\r\n this.props.onCloseModal();\r\n }\r\n }\r\n\r\n shouldComponentRender = () => this.props.productDetail.productId;\r\n\r\n onEditProductStatus(change) {\r\n this.setState(prevState => ({\r\n editProduct: { // object that we want to update\r\n ...prevState.editProduct, // keep all other key-value pairs\r\n inCatalogue: change.inCatalogue // update the value of specific key\r\n }\r\n }));\r\n }\r\n\r\n // onEditProductCatalogue(change) {\r\n // this.setState(prevState => ({\r\n // editProduct: { // object that we want to update\r\n // ...prevState.editProduct, // keep all other key-value pairs\r\n // inCatalogue: change.inCatalogue // update the value of specific key\r\n // }\r\n // }));\r\n // }\r\n\r\n onEditInvoiceGroup(change) {\r\n\r\n const ig = this.props.invoiceGroups.find(ig => ig.invoiceCode === change.invoiceGroupId);\r\n const igName = this.capitalizeFirstLetter(ig.description);\r\n\r\n this.setState(prevState => ({\r\n editProduct: { // object that we want to update\r\n ...prevState.editProduct, // keep all other key-value pairs\r\n invoiceGroupId: change.invoiceGroupId,\r\n invoiceGroupName: igName\r\n }\r\n }));\r\n }\r\n\r\n onEditNewAdmCharge(change) {\r\n const testAdmCharge = Number(change.futureAdminCharge);\r\n if (isNaN(testAdmCharge)) {\r\n //console.log(\"Ukjent verdi \", change.futureAdminCharge);\r\n }\r\n else {\r\n this.setState(prevState => ({\r\n editProduct: { // object that we want to update\r\n ...prevState.editProduct, // keep all other key-value pairs\r\n futureAdminCharge: testAdmCharge // update the value of specific key\r\n }\r\n }));\r\n }\r\n }\r\n onSelectAdmDate(date) {\r\n this.setState(prevState => ({\r\n editProduct: { // object that we want to update\r\n ...prevState.editProduct, // keep all other key-value pairs\r\n futureAdminChargeDate: date // update the value of specific key\r\n }\r\n }));\r\n }\r\n\r\n // onDeleteProduct() {\r\n // this.setState(prevState => ({\r\n // editProduct: { // object that we want to update\r\n // ...prevState.editProduct, // keep all other key-value pairs\r\n // inCatalogue: false // update the value of specific key\r\n // }\r\n // }));\r\n // }\r\n\r\n capitalizeFirstLetter(s) {\r\n s = s.toLowerCase();\r\n return s.charAt(0).toUpperCase() + s.slice(1);\r\n }\r\n\r\n validateNewPrice() {\r\n return true;\r\n }\r\n\r\n getDropDownDateStyle() {\r\n return {\r\n width: \"450px\",\r\n };\r\n }\r\n\r\n onClickPrintHms() {\r\n this.props.downloadHmsPdf(this.props.token, this.props.product, true);\r\n }\r\n\r\n onSaveChanges() {\r\n this.props.updateChainProducts(this.props.chainType, [this.state.editProduct]);\r\n //this.props.onCloseModal(event);\r\n }\r\n\r\n\r\n render() {\r\n const {\r\n invoiceGroups,\r\n localization,\r\n onCloseModal,\r\n productDetail,\r\n saveButtonText,\r\n title,\r\n width,\r\n setDropDown,\r\n } = this.props;\r\n\r\n // Check if data has been loaded, if not just return empty component\r\n if (!this.shouldComponentRender()) return ;\r\n\r\n const statusOptions = [{ value: true, label: \"Åpen\" }, { value: false, label: \"Stengt\" }];\r\n //const catalogueOptions = [{ value: true, label: \"I varekatalog\" }, { value: false, label: \"Ikke i varekatalog\" }];\r\n const invoiceGroupOptions = invoiceGroups.map(ig => { return { value: ig.invoiceCode, label: this.capitalizeFirstLetter(ig.description) }; });\r\n\r\n let iconType = iconTypes.x;\r\n if (productDetail.productStorageType == \"Tørr\") {\r\n iconType = iconTypes.box;\r\n } else if (productDetail.productStorageType == \"Frys\") {\r\n iconType = iconTypes.snowflake;\r\n } else if (productDetail.productStorageType == \"Kjøl\") {\r\n iconType = iconTypes.fridge;\r\n }\r\n\r\n const futureAdmDate = !this.state.editProduct.futureAdminChargeDate ? productDetail.futureAdminChargeDate : this.state.editProduct.futureAdminChargeDate;\r\n const futureAdmDateForDropDown = !futureAdmDate ? moment() : moment(futureAdmDate);\r\n const futureAdmDateForDisplay = !futureAdmDate ? \"Sett dato\" : moment(futureAdmDate).format(\"DD.MM.YYYY\");\r\n const futureAdmReadOnlyChains = !futureAdmDate ? \"\" : `${toLocaleFixed(productDetail.currentNetPricePerSalesUnit, 2)} (fra ${futureAdmDateForDisplay})`;\r\n\r\n const futureInprice = `${toLocaleFixed(productDetail.futureInPrice, 2)}`;\r\n const futureInpriceDate = `${productDetail.futureInPriceDate && moment(productDetail.futureInPriceDate).format(\"DD.MM.YY\")}`;\r\n const futureInpriceText = productDetail.futureInPrice ? `${futureInprice} (Gjelder fra ${futureInpriceDate})` : \"\";\r\n\r\n const previousDates = [];\r\n const validDates = [];\r\n\r\n const iconAvailable = this.state.editProduct.inCatalogue ? \"circle-green\" : \"circle-red\";\r\n //const iconInCatalogue = this.state.editProduct.inCatalogue ? \"cicle-blue\" : undefined;\r\n\r\n const canSubmit = (saveButtonText == \"Lagre\");\r\n\r\n return (\r\n \r\n \r\n
\r\n
\r\n
\r\n
{title}
\r\n
\r\n
{this.props.product.productName}
\r\n
EPD {this.props.product.epdNo}
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
Varestatus
\r\n
{/*Varekatalog*/}
\r\n { productDetail.webEditInvoiceGroupEndPrice && (\r\n
Fakturagruppe
\r\n )}\r\n
Adm gebyr (%)
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n {/**/}\r\n
\r\n
\r\n { productDetail.webEditInvoiceGroupEndPrice && (\r\n
\r\n )}\r\n
\r\n
\r\n {toLocaleFixed(productDetail.currentAdminChargePercent, 2)}\r\n
\r\n {productDetail.adminChargeEditable ? (\r\n
\r\n \r\n \r\n \r\n {futureAdmDateForDisplay}
)} flex={true} disableDimScreen={true} dropDownStyle={this.getDropDownDateStyle()} expand={true} setDropDown={setDropDown} dropDownChildren={(\r\n \r\n )} />\r\n \r\n \r\n \r\n ) : \r\n
\r\n { futureAdmReadOnlyChains }\r\n
\r\n }\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
{\"Priser\"}
\r\n
{\"Gjeldende\"}
\r\n
{\"Fremtidig\"}
\r\n
\r\n
\r\n
\r\n
\r\n
{productDetail.futureCustomerBasePriceDate && moment(productDetail.futureCustomerBasePriceDate).format(\"DD.MM.YY\")}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"chainSortiment\", \"netPrice\")}
\r\n
{toLocaleFixed(productDetail.currentNetPrice, 2)}
\r\n
{toLocaleFixed(productDetail.futureNetPrice, 2)}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"chainSortiment\", \"netPricePerUnit\")}
\r\n
{toLocaleFixed(productDetail.currentNetPricePerSalesUnit, 2)}
\r\n
{toLocaleFixed(productDetail.futureNetPricePerSalesUnit, 2)}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"basePriceForAdminCharge\")}
\r\n
{toLocaleFixed(productDetail.basePriceForAdminCharge, 2)}
\r\n
{toLocaleFixed(productDetail.futureBasePriceForAdminCharge, 2)}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"basePriceWithChargesExclAdminCharge\")}
\r\n
{toLocaleFixed(productDetail.customerBasePriceWithChargesExclAdminCharge, 2)}
\r\n
{toLocaleFixed(productDetail.futureCustomerBasePriceWithChargesExclAdminCharge, 2)}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"currentCusBasePrice\")}
\r\n
{toLocaleFixed(productDetail.currentCustomerBasePrice, 2)}
\r\n
{toLocaleFixed(productDetail.futureCustomerBasePrice, 2)}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"campaignPrice\")}
\r\n
\r\n
{productDetail.currentCampaignPercent}
\r\n
{productDetail.currentCampaignPeriod}
\r\n
\r\n
\r\n
{productDetail.futureCampaignPercent}
\r\n
{productDetail.futureCampaignPeriod}
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n

\r\n
\r\n {/*
\r\n \r\n
*/}\r\n
\r\n
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"eanNoSalesUnit\")}
\r\n
{productDetail.eanNoSalesUnit}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"eanNoWarehouseUnit\")}
\r\n
{productDetail.eanNoWarehouseUnit}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"epProductId\")}
\r\n
{productDetail.productId}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"supplierName\")}
\r\n
{productDetail.supplierName}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"supplierProductid\")}
\r\n
{productDetail.supplierProductId}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"category\")}
\r\n
{productDetail.category}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"calcGroup\")}
\r\n
{productDetail.calcGroup}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"storageType\")}
\r\n
\r\n
{productDetail.productStorageType}
\r\n
\r\n
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"status\")}
\r\n
{productDetail.status}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"chainSortiment\", \"noOfSalesUnits\")}
\r\n
{productDetail.noOfSalesUnits}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"weightSalesUnit\")}
\r\n
{toLocaleFixed(productDetail.weightSalesUnit, 3)}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"heightSalesUnit\")}
\r\n
{toLocaleFixed(productDetail.heightSalesUnit, 3)}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"lengthSalesUnit\")}
\r\n
{toLocaleFixed(productDetail.lengthSalesUnit, 3)}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"widthSalesUnit\")}
\r\n
{toLocaleFixed(productDetail.widthSalesUnit, 3)}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"noOfUnitsInPackage\")}
\r\n
{productDetail.noOfUnitsInPackage}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"uniqueForChain\")}
\r\n
{productDetail.uniqueForChain}
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"depositAmountWarehouseAndSalesUnit\")}
\r\n
{productDetail.depositAmountWarehouseAndSalesUnit}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"currentInPrice\")}
\r\n
{toLocaleFixed(productDetail.currentInPrice, 2)}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"futureInPrice\")}
\r\n
{futureInpriceText}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"linkProductId\")}
\r\n
{productDetail.linkProductId}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"replacingProductIds\")}
\r\n
{productDetail.replacingProductIds}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"durabilityDays\")}
\r\n
{productDetail.durabilityDays}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"weight\")}
\r\n
{toLocaleFixed(productDetail.weight, 2)}
\r\n
\r\n
\r\n
{localization.text(\"chain\", \"detail\", \"useSalesUnit\")}
\r\n
{productDetail.useSalesUnit ? \"Ja\" : \"Nei\" }
\r\n
\r\n
\r\n
{productDetail.campaignInfo}
\r\n
\r\n
\r\n
\r\n
\r\n\r\n
\r\n
\r\n\r\n \r\n
\r\n \r\n
\r\n
\r\n \r\n \r\n
\r\n
\r\n \r\n \r\n );\r\n }\r\n}\r\nSingleChainProductModal.propTypes = {\r\n chainType: PropTypes.number.isRequired,\r\n downloadHmsPdf: PropTypes.func.isRequired,\r\n getInvoiceGroups: PropTypes.func.isRequired,\r\n getSingleChainProductDetail: PropTypes.func.isRequired,\r\n invoiceGroups: PropTypes.array.isRequired,\r\n isLoading: PropTypes.bool.isRequired,\r\n localization: Localization.propTypes.isRequired,\r\n onCloseModal: PropTypes.func.isRequired,\r\n product: PropTypes.object.isRequired,\r\n productDetail: PropTypes.object.isRequired,\r\n saveButtonText: PropTypes.string,\r\n title: PropTypes.string,\r\n token: PropTypes.string.isRequired,\r\n updateChainProducts: PropTypes.func.isRequired,\r\n width: PropTypes.number.isRequired,\r\n setDropDown: PropTypes.func.isRequired,\r\n};\r\n\r\nconst mapStateToProps = () => {\r\n return (state) => ({\r\n chainType: state.authentication.chainType,\r\n deviceType: state.view.deviceType,\r\n invoiceGroups: state.singleChainSortiment.invoiceGroups,\r\n isLoading: state.singleChainSortiment.isLoading,\r\n productDetail: state.singleChainSortiment.productDetail,\r\n token: state.authentication.token,\r\n });\r\n};\r\n\r\nconst mapDispatchToProps = {\r\n downloadHmsPdf,\r\n getInvoiceGroups,\r\n getSingleChainProductDetail,\r\n updateChainProducts,\r\n setDropDown\r\n};\r\n\r\nexport default connect(mapStateToProps, mapDispatchToProps)(SingleChainProductModal);\r\n","import \"../../../styles/kjedeweb/multiChainProductListItem.scss\";\r\n\r\nimport Icon, { iconTypes } from \"../../common/components/Icon.jsx\";\r\n\r\nimport CheckBox from \"../../common/components/CheckBox\";\r\nimport DefaultLogo from \"../../../assets/images/logoImages/DefaultLogo.png\";\r\nimport FuturePriceItem from \"./FuturePriceComponent\";\r\nimport { Localization } from \"../../common/util/localization.jsx\";\r\nimport LogoChain1 from \"../../../assets/images/logoImages/LogoChain1.png\";\r\nimport LogoChain22 from \"../../../assets/images/logoImages/LogoChain22.png\";\r\nimport LogoChain24 from \"../../../assets/images/logoImages/LogoChain24.png\";\r\nimport LogoChain26 from \"../../../assets/images/logoImages/LogoChain26.png\";\r\nimport LogoChain30 from \"../../../assets/images/logoImages/LogoChain30.png\";\r\nimport LogoChain31 from \"../../../assets/images/logoImages/LogoChain31.png\";\r\nimport LogoChain34 from \"../../../assets/images/logoImages/LogoChain34.png\";\r\nimport LogoChain37 from \"../../../assets/images/logoImages/LogoChain37.png\";\r\nimport LogoChain38 from \"../../../assets/images/logoImages/LogoChain38.png\";\r\nimport LogoChain40 from \"../../../assets/images/logoImages/LogoChain40.png\";\r\nimport LogoChain43 from \"../../../assets/images/logoImages/LogoChain43.png\";\r\nimport LogoChain47 from \"../../../assets/images/logoImages/LogoChain47.png\";\r\nimport LogoChain5 from \"../../../assets/images/logoImages/LogoChain5.png\";\r\nimport MultiChainProductModal from \"./MultiChainProductModal.jsx\";\r\nimport PropTypes from \"prop-types\";\r\nimport React from \"react\";\r\nimport ResponsiveColumn from \"../../common/components/ResponsiveColumn\";\r\nimport ResponsiveRows from \"../../common/components/ResponsiveRows\";\r\nimport SingleChainProductModal from \"./SingleChainProductModal.jsx\";\r\n\r\nimport moment from \"moment\";\r\nimport { toLocaleFixed } from \"../../common/util/localization.jsx\";\r\n\r\nconst LOGOS = {\r\n \"defaultlogo.png\": DefaultLogo,\r\n \"logochain22.png\": LogoChain22,\r\n \"logochain26.png\": LogoChain26,\r\n \"logochain31.png\": LogoChain31,\r\n \"logochain40.png\": LogoChain40,\r\n \"logochain47.png\": LogoChain47,\r\n \"logochain1.png\": LogoChain1,\r\n \"logochain24.png\": LogoChain24,\r\n \"logochain30.png\": LogoChain30,\r\n \"logochain34.png\": LogoChain34,\r\n \"logochain43.png\": LogoChain43,\r\n \"logochain5.png\": LogoChain5,\r\n \"logochain37.png\": LogoChain37,\r\n \"logochain38.png\": LogoChain38\r\n};\r\n\r\n/**\r\n * Returns a render node, for selecting a single product\r\n * @param {object} props \r\n * @returns {node}\r\n */\r\nfunction SelectProduct({product, selected, editSelectedProduct}) {\r\n const getId = () => `${product.productId}:${product.chainId}`;\r\n /**\r\n * Calls the action to select/unselect the product\r\n * @param {object} change \r\n * @returns {*}\r\n */\r\n function onClickSelect(change) {\r\n editSelectedProduct({\r\n [getId()]: change[getId()] ? product : undefined,\r\n });\r\n }\r\n /**\r\n * Returns true if the product\r\n * @param {object} change \r\n * @returns {boolean}\r\n */\r\n\r\n return (\r\n
\r\n \r\n
\r\n );\r\n}\r\nSelectProduct.propTypes = {\r\n product: PropTypes.object.isRequired,\r\n selected: PropTypes.object.isRequired,\r\n editSelectedProduct: PropTypes.func.isRequired,\r\n};\r\n\r\n/**\r\n * Fetch the url to a logo given its image name\r\n * @param {string} name \r\n * @returns {string}\r\n */\r\nexport function getChainLogo(name) {\r\n if (name && LOGOS[name.toLowerCase()]) {\r\n const logo = LOGOS[name.toLowerCase()];\r\n return logo;\r\n } else {\r\n return DefaultLogo;\r\n }\r\n}\r\n\r\nexport class MultiChainSortimentListHeader extends React.PureComponent {\r\n render() {\r\n const {\r\n localization,\r\n multiSelect,\r\n showInvoiceGroup,\r\n } = this.props;\r\n\r\n return (\r\n
\r\n
\r\n \r\n \r\n {localization.text(\"chain\", \"chainSortiment\", \"productAndStatus\")}\r\n
\r\n \r\n \r\n {multiSelect && ()}\r\n \r\n \r\n \r\n \r\n \r\n {localization.text(\"chain\", \"chainSortiment\", \"productStatus\")}\r\n
\r\n \r\n \r\n \r\n {localization.text(\"chain\", \"chainSortiment\", \"noOfSalesUnits\")}\r\n
\r\n \r\n \r\n \r\n {localization.text(\"chain\", \"chainSortiment\", \"netPrice\")}\r\n
\r\n \r\n \r\n \r\n {localization.text(\"chain\", \"chainSortiment\", \"netPricePerUnit\")}\r\n
\r\n \r\n \r\n \r\n {localization.text(\"chain\", \"chainSortiment\", \"adminChargePercent\")}\r\n
\r\n \r\n \r\n \r\n {localization.text(\"chain\", \"chainSortiment\", \"changed\")}\r\n
\r\n \r\n {showInvoiceGroup && (\r\n \r\n \r\n {localization.text(\"chain\", \"chainSortiment\", \"invoiceGroup\")}\r\n
\r\n \r\n )}\r\n \r\n \r\n \r\n \r\n
\r\n );\r\n }\r\n}\r\n\r\nMultiChainSortimentListHeader.propTypes = {\r\n localization: Localization.propTypes.isRequired,\r\n multiSelect: PropTypes.bool.isRequired,\r\n showInvoiceGroup : PropTypes.bool,\r\n};\r\n\r\nexport class MultiChainSortimentListItem extends React.PureComponent {\r\n constructor(props) {\r\n super(props);\r\n\r\n this.showProductModal = this.showProductModal.bind(this);\r\n this.closeProductModal = this.closeProductModal.bind(this);\r\n this.onMouseOver = this.onMouseOver.bind(this);\r\n this.onMouseOut = this.onMouseOut.bind(this);\r\n\r\n this.state = {\r\n mouseOver: false\r\n };\r\n }\r\n\r\n onMouseOver() {\r\n this.setState({\r\n mouseOver: true\r\n });\r\n }\r\n\r\n onMouseOut() {\r\n this.setState({\r\n mouseOver: false\r\n });\r\n }\r\n\r\n showProductModal(event) {\r\n event.stopPropagation();\r\n event.preventDefault();\r\n\r\n const {\r\n localization,\r\n productGroup,\r\n selectedTabChainId,\r\n } = this.props;\r\n\r\n const title = localization.text(\"chain\", \"productDetail\");\r\n const saveButtonText = localization.text(\"chain\", \"save\");\r\n\r\n if(selectedTabChainId === \"all\"){\r\n this.props.setModal(
);\r\n }\r\n else {\r\n this.props.setModal(
);\r\n }\r\n\r\n }\r\n\r\n closeProductModal(event) {\r\n event.stopPropagation();\r\n event.preventDefault();\r\n\r\n this.props.setModal(null);\r\n this.props.clearChainProductDetails();\r\n }\r\n\r\n capitalizeFirstLetter(s) {\r\n if (!s) {\r\n return \"\";\r\n }\r\n s = s.toLowerCase();\r\n return s.charAt(0).toUpperCase() + s.slice(1);\r\n }\r\n\r\n render() {\r\n const {\r\n chains,\r\n productGroup,\r\n multiSelect,\r\n selected,\r\n editSelectedProduct,\r\n } = this.props;\r\n\r\n return (\r\n
\r\n
\r\n \r\n \r\n
\r\n {productGroup[0].imageUrl && (\r\n
\r\n
\r\n \r\n )}\r\n
\r\n
\r\n
EPD {productGroup[0].epdNo}
\r\n
{productGroup[0].productName}
\r\n
\r\n
\r\n \r\n \r\n {productGroup.map((product, idx) => (\r\n \r\n {multiSelect && (\r\n
\r\n )}\r\n \r\n \r\n \r\n

\r\n
\r\n
\r\n {product.inCatalogue ?
:
}{product.inCatalogue ? \"Åpen\" : \"Stengt\"}\r\n
\r\n {/*
\r\n {product.inCatalogue && (
)}\r\n {product.inCatalogue ? \"I varekatalog\" : \"Ikke i varekatalog\"}\r\n
*/}\r\n
\r\n
\r\n \r\n
\r\n \r\n
\r\n {product.status}\r\n
\r\n
\r\n \r\n
\r\n \r\n
\r\n {product.noOfSalesUnits}\r\n
\r\n
\r\n \r\n
\r\n \r\n
\r\n {product.currentNetPrice && toLocaleFixed(product.currentNetPrice,2)}\r\n
\r\n
\r\n \r\n
\r\n \r\n
\r\n {product.currentNetPricePerSalesUnit && toLocaleFixed(product.currentNetPricePerSalesUnit,3)}\r\n
\r\n
\r\n \r\n
\r\n \r\n \r\n
\r\n \r\n
\r\n {product.lastChangedDate && moment(product.lastChangedDate).format(\"DD.MM.YY\")}\r\n
\r\n
\r\n \r\n {product.showInvoiceGroup && (\r\n
\r\n \r\n
\r\n {this.capitalizeFirstLetter(product.invoiceGroupName)}\r\n
\r\n
\r\n \r\n )}\r\n \r\n
\r\n ))}\r\n \r\n
\r\n {this.state.mouseOver && (\r\n \r\n )}\r\n \r\n \r\n
\r\n );\r\n }\r\n}\r\n\r\nMultiChainSortimentListItem.propTypes = {\r\n chains: PropTypes.object.isRequired,\r\n clearChainProductDetails: PropTypes.func.isRequired,\r\n localization: Localization.propTypes.isRequired,\r\n productGroup: PropTypes.arrayOf(PropTypes.object),\r\n setModal: PropTypes.func.isRequired,\r\n selected: PropTypes.object.isRequired,\r\n editSelectedProduct: PropTypes.func.isRequired,\r\n multiSelect: PropTypes.bool.isRequired,\r\n selectedTabChainId : PropTypes.string,\r\n};\r\n\r\nMultiChainSortimentListItem.defaultProps = {\r\n};","import \"../../../styles/productView.scss\";\r\nimport \"../../../styles/productViewListItem.scss\";\r\n\r\nimport Loading, { loadingTypes } from \"../../common/components/Loading\";\r\nimport { MultiChainSortimentListHeader, MultiChainSortimentListItem } from \"./MultiChainSortimentListItem.jsx\";\r\n\r\nimport ChainScroll from \"./ChainScroll\";\r\nimport { Localization } from \"../../common/util/localization.jsx\";\r\nimport PropTypes from \"prop-types\";\r\nimport React from \"react\";\r\n\r\nclass MultiChainSortimentList extends React.PureComponent {\r\n constructor(props) {\r\n super(props);\r\n\r\n this.state = {\r\n width: null,\r\n };\r\n this.containerNode = null;\r\n this.trackScrolling = this.trackScrolling.bind(this);\r\n this.prepareItems = this.prepareItems.bind(this);\r\n }\r\n\r\n trackScrolling() {\r\n const {\r\n isLoading,\r\n loadMoreProducts,\r\n } = this.props;\r\n\r\n //load more products if none is loading\r\n if (isLoading === false && loadMoreProducts) {\r\n loadMoreProducts(50);\r\n }\r\n }\r\n\r\n prepareItems() {\r\n const {\r\n chains,\r\n clearChainProductDetails,\r\n deviceType,\r\n list,\r\n localization,\r\n isLoading,\r\n setModal,\r\n multiSelect,\r\n editSelectedProduct,\r\n selected,\r\n selectedTabChainId,\r\n } = this.props;\r\n\r\n const retNodes = [];\r\n\r\n for (let i = 0; i < list.length; i++) {\r\n retNodes[retNodes.length] = (\r\n
);\r\n }\r\n if (isLoading) {\r\n retNodes[retNodes.length] =\r\n retNodes[retNodes.length] =\r\n
;\r\n }\r\n return retNodes;\r\n }\r\n\r\n render() {\r\n const {\r\n deviceType,\r\n localization,\r\n height,\r\n style,\r\n multiSelect,\r\n list,\r\n } = this.props;\r\n\r\n const nodes = this.prepareItems();\r\n\r\n var listFlattened = Array.prototype.concat.apply([], list);\r\n const showInvoiceGroup = listFlattened.some(li => li.showInvoiceGroup);\r\n\r\n return (\r\n
\r\n \r\n \r\n
\r\n \r\n {nodes}\r\n \r\n \r\n );\r\n }\r\n}\r\n\r\nMultiChainSortimentList.propTypes = {\r\n chains: PropTypes.object.isRequired,\r\n clearChainProductDetails: PropTypes.func.isRequired,\r\n deviceType: PropTypes.string.isRequired,\r\n height: PropTypes.number,\r\n // If true a loading icon will be displayed\r\n isLoading: PropTypes.bool,\r\n // An array of products to be displayed\r\n list: PropTypes.arrayOf(PropTypes.array).isRequired,\r\n // A function that will load in more items into list\r\n loadMoreProducts: PropTypes.func,\r\n localization: Localization.propTypes.isRequired,\r\n setModal: PropTypes.func.isRequired,\r\n multiSelect: PropTypes.bool.isRequired,\r\n editSelectedProduct: PropTypes.func.isRequired,\r\n selected: PropTypes.object.isRequired,\r\n style: PropTypes.object,\r\n selectedTabChainId : PropTypes.string,\r\n};\r\n\r\nexport default MultiChainSortimentList;\r\n","import \"../../../styles/kjedeweb/chainProductView.scss\";\r\n\r\nimport Icon, { iconColor, iconTypes } from \"../../common/components/Icon\";\r\nimport { SubMenu, SubMenuItem } from \"../../common/components/SubMenu.jsx\";\r\nimport { getInvoiceGroups, updateChainProducts } from \"../actions/singleChainSortiment.js\";\r\nimport { getInvoiceGroups as getInvoiceGroupsMultiChain, updateChainProducts as updateChainProductsMultiChain } from \"../actions/multiChainSortiment.js\";\r\n\r\nimport Calendar from \"../../common/components/Calendar\";\r\nimport DropDownList from \"../../common/components/DropDownList\";\r\nimport LabelField from \"../../common/components/LabelField\";\r\nimport { Localization } from \"../../common/util/localization.jsx\";\r\nimport Modal from \"../../common/components/Modal.jsx\";\r\nimport PropTypes from \"prop-types\";\r\nimport React from \"react\";\r\nimport TextField from \"../../common/components/TextField.jsx\";\r\nimport { connect } from \"react-redux\";\r\nimport { downloadHmsPdf } from \"../../kundeweb/util/productUtil.jsx\";\r\nimport moment from \"moment\";\r\nimport { setDropDown } from \"../../common/actions/modal.js\";\r\n\r\n/**\r\n * Returnerar kalender komponent\r\n * \r\n * @param {object} props\r\n * @returns {node}\r\n */\r\nfunction CalendarDropdown({ onClickHide, dropDown, localization, date, validDates, previousDates, nextOrderDate, onSelectDate }) {\r\n /**\r\n * selects the date and hides the dropdown window\r\n * \r\n * @param {object} date\r\n * @returns {undefined}\r\n */\r\n function onClick(date) {\r\n onClickHide();\r\n onSelectDate(date);\r\n }\r\n\r\n const minDate = moment(new Date());\r\n const maxDate = moment(\"2100-01-01\");\r\n\r\n return (\r\n
\r\n );\r\n}\r\nCalendarDropdown.propTypes = {\r\n date: PropTypes.string,\r\n dropDown: PropTypes.bool,\r\n localization: Localization.propTypes.isRequired,\r\n nextOrderDate: PropTypes.string,\r\n onClickHide: PropTypes.func,\r\n onSelectDate: PropTypes.func,\r\n previousDates: PropTypes.arrayOf(PropTypes.string.isRequired),\r\n validDates: PropTypes.arrayOf(PropTypes.string.isRequired),\r\n};\r\n\r\n\r\n\r\nclass MultiProductModal extends React.PureComponent {\r\n constructor(props) {\r\n super(props);\r\n\r\n this.state = {\r\n\r\n };\r\n\r\n this.handleClickOutside = this.handleClickOutside.bind(this);\r\n this.onSaveChanges = this.onSaveChanges.bind(this);\r\n this.onSelectAdmDate = this.onSelectAdmDate.bind(this);\r\n this.onSelectDate = this.onSelectDate.bind(this);\r\n this.onEdit = this.onEdit.bind(this);\r\n }\r\n\r\n componentDidMount() {\r\n const {\r\n isMultiChain,\r\n getInvoiceGroups,\r\n getInvoiceGroupsMultiChain,\r\n } = this.props;\r\n (async () => {\r\n if(isMultiChain){\r\n await getInvoiceGroupsMultiChain();\r\n } else {\r\n await getInvoiceGroups();\r\n }\r\n })();\r\n }\r\n\r\n handleClickOutside() {\r\n if (this.props.onCloseModal) {\r\n this.props.onCloseModal();\r\n }\r\n }\r\n\r\n onSelectDate(date) {\r\n this.setState({\r\n futureEndPriceDate: date // update the value of specific key\r\n });\r\n }\r\n onSelectAdmDate(date) {\r\n this.setState({\r\n futureAdminChargeDate: date // update the value of specific key\r\n });\r\n }\r\n\r\n capitalizeFirstLetter(s) {\r\n s = s.toLowerCase();\r\n return s.charAt(0).toUpperCase() + s.slice(1);\r\n }\r\n\r\n validateNewPrice() {\r\n return true;\r\n }\r\n\r\n getDropDownDateStyle() {\r\n return {\r\n width: \"450px\",\r\n left: \"unset\",\r\n right: \"0px\",\r\n top: \"30px\",\r\n };\r\n }\r\n\r\n onSaveChanges(event) {\r\n const {\r\n isMultiChain,\r\n chainType,\r\n selected,\r\n updateChainProducts,\r\n updateChainProductsMultiChain,\r\n onCloseModal,\r\n } = this.props;\r\n const products = [];\r\n for(const key in selected) {\r\n products.push({\r\n ...selected[key],\r\n ...this.state,\r\n });\r\n }\r\n if( isMultiChain ){\r\n updateChainProductsMultiChain(products);\r\n } else {\r\n updateChainProducts(chainType, products);\r\n }\r\n onCloseModal(event);\r\n }\r\n\r\n onEdit(change) {\r\n this.setState(change);\r\n }\r\n\r\n\r\n render() {\r\n const {\r\n invoiceGroups,\r\n localization,\r\n onCloseModal,\r\n saveButtonText,\r\n width,\r\n setDropDown,\r\n } = this.props;\r\n\r\n const invoiceGroupOptions = invoiceGroups.map(ig => { return { value: ig.invoiceCode, label: this.capitalizeFirstLetter(ig.description) }; });\r\n\r\n const futureEndPriceDateForDropdown = !this.state.futureEndPriceDate ? moment() : moment(this.state.futureEndPriceDate);\r\n const futureEndPriceDateForDisplay = !this.state.futureEndPriceDate ? \"Sett dato\" : moment(this.state.futureEndPriceDate).format(\"DD.MM.YYYY\");\r\n\r\n const futureAdmDateForDropDown = !this.state.futureAdminChargeDate ? moment() : moment(this.state.futureAdminChargeDate);\r\n const futureAdmDateForDisplay = !this.state.futureAdminChargeDate ? \"Sett dato\" : moment(this.state.futureAdminChargeDate).format(\"DD.MM.YYYY\");\r\n\r\n const previousDates = [];\r\n const validDates = [];\r\n\r\n return (\r\n \r\n \r\n
\r\n
\r\n
\r\n
{localization.text(\"chain\",\"editMultiple\")}
\r\n
\r\n
{localization.text(\"chain\",\"multiModalInfo1\")}
\r\n
{localization.text(\"chain\",\"multiModalInfo2\")}
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
{/**/}
\r\n
{/**/}
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n {/* */}\r\n
\r\n
\r\n
\r\n
\r\n {/**/}\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n \r\n {futureEndPriceDateForDisplay}
)} flex={true} disableDimScreen={true} dropDownStyle={this.getDropDownDateStyle()} expand={true} setDropDown={setDropDown} dropDownChildren={(\r\n
\r\n )} />\r\n \r\n \r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n \r\n {futureAdmDateForDisplay}
)} flex={true} disableDimScreen={true} dropDownStyle={this.getDropDownDateStyle()} expand={true} setDropDown={setDropDown} dropDownChildren={(\r\n
\r\n )} />\r\n \r\n
\r\n
\r\n
\r\n
\r\n \r\n\r\n \r\n
\r\n \r\n
\r\n
\r\n \r\n \r\n
\r\n
\r\n \r\n \r\n );\r\n }\r\n}\r\nMultiProductModal.propTypes = {\r\n chainType: PropTypes.number.isRequired,\r\n downloadHmsPdf: PropTypes.func.isRequired,\r\n getInvoiceGroups: PropTypes.func.isRequired,\r\n invoiceGroups: PropTypes.array.isRequired,\r\n isLoading: PropTypes.bool.isRequired,\r\n localization: Localization.propTypes.isRequired,\r\n onCloseModal: PropTypes.func.isRequired,\r\n saveButtonText: PropTypes.string,\r\n token: PropTypes.string.isRequired,\r\n updateChainProducts: PropTypes.func.isRequired,\r\n width: PropTypes.number.isRequired,\r\n selected: PropTypes.object.isRequired,\r\n isMultiChain: PropTypes.bool.isRequired,\r\n getInvoiceGroupsMultiChain: PropTypes.func.isRequired,\r\n updateChainProductsMultiChain: PropTypes.func.isRequired,\r\n setDropDown: PropTypes.func.isRequired,\r\n};\r\n\r\nconst mapStateToProps = () => {\r\n return (state) => ({\r\n isMultiChain: state.authentication.chainIds.length>1,\r\n chainType: state.authentication.chainType,\r\n deviceType: state.view.deviceType,\r\n invoiceGroups: state.singleChainSortiment.invoiceGroups,\r\n isLoading: state.singleChainSortiment.isLoading,\r\n token: state.authentication.token,\r\n });\r\n};\r\n\r\nconst mapDispatchToProps = {\r\n downloadHmsPdf,\r\n getInvoiceGroups,\r\n getInvoiceGroupsMultiChain,\r\n updateChainProducts,\r\n updateChainProductsMultiChain,\r\n setDropDown,\r\n};\r\n\r\nexport default connect(mapStateToProps, mapDispatchToProps)(MultiProductModal);\r\n","import { ChainTab, ChainTabList, ChainTabPanel, ChainTabs } from \"./ChainTabs.jsx\";\r\nimport Icon, {iconTypes} from \"../../common/components/Icon.jsx\";\r\nimport { SubMenu, SubMenuItem } from \"../../common/components/SubMenu.jsx\";\r\n\r\nimport { Localization } from \"../../common/util/localization.jsx\";\r\nimport MultiChainSortimentList from \"./MultiChainSortimentList.jsx\";\r\nimport MultiProductModal from \"./MultiProductModal.jsx\";\r\nimport PropTypes from \"prop-types\";\r\nimport React from \"react\";\r\nimport { createReselector } from \"../../common/util/reselect.js\";\r\nimport { getChainLogo } from \"./MultiChainSortimentListItem.jsx\";\r\nimport { scssVariables } from \"../../common/util/config.jsx\";\r\nimport { withRouter } from \"react-router-dom\";\r\n\r\nclass MultiChainSortimentCard extends React.PureComponent {\r\n constructor(props) {\r\n super(props);\r\n\r\n this.state = {\r\n multiSelectOn: false,\r\n };\r\n\r\n this.closeProductModal = this.closeProductModal.bind(this);\r\n this.swallowOnClick = this.swallowOnClick.bind(this);\r\n this.onTabAllClicked = this.onTabAllClicked.bind(this);\r\n this.onChainClick = this.onChainClick.bind(this);\r\n this.onMultiSelectClick = this.onMultiSelectClick.bind(this);\r\n this.onEditMultiSelect = this.onEditMultiSelect.bind(this);\r\n this.onExportCsv = this.onExportCsv.bind(this);\r\n this.calculateInternalPanelHeight = this.calculateInternalPanelHeight.bind(this);\r\n\r\n this.groupProductsReselector = createReselector(chainProducts => {\r\n let group = [];\r\n const groups = [];\r\n\r\n for (const p of chainProducts) {\r\n if (group.length === 0) {\r\n group.push(p.product);\r\n } else if (group[0].productId === p.product.productId) {\r\n group.push(p.product);\r\n } else {\r\n groups.push(group);\r\n group.sort((a, b) => a.chainName - b.chainName);\r\n group = [p.product];\r\n }\r\n }\r\n\r\n if (group.length > 0) {\r\n groups.push(group);\r\n group.sort((a, b) => a.chainName - b.chainName);\r\n }\r\n\r\n return groups;\r\n });\r\n }\r\n\r\n closeProductModal(event) {\r\n event.stopPropagation();\r\n event.preventDefault();\r\n\r\n this.props.setModal(null);\r\n this.props.clearChainProductDetails();\r\n }\r\n\r\n onTabAllClicked() {\r\n this.props.editMultiChainFilter({\r\n chainId: undefined\r\n });\r\n }\r\n\r\n onChainClick(index) {\r\n this.props.editMultiChainFilter({\r\n chainId: this.props.userChains[index - 1].chainId\r\n });\r\n }\r\n\r\n onMultiSelectClick() {\r\n if( this.state.multiSelectOn ){\r\n this.props.clearSelectedProducts();\r\n }\r\n this.setState({\r\n multiSelectOn: !this.state.multiSelectOn,\r\n });\r\n }\r\n\r\n onEditMultiSelect() {\r\n const {\r\n localization,\r\n multiChainSortiment,\r\n } = this.props;\r\n\r\n const title = localization.text(\"chain\", \"productDetail\");\r\n const saveButtonText = localization.text(\"chain\", \"save\");\r\n this.props.setModal();\r\n }\r\n\r\n onExportCsv() {\r\n\r\n const {\r\n multiChainSortiment,\r\n exportCsv,\r\n } = this.props;\r\n\r\n exportCsv(multiChainSortiment);\r\n }\r\n\r\n swallowOnClick(event) {\r\n event.stopPropagation();\r\n event.preventDefault();\r\n }\r\n\r\n calculateInternalPanelHeight() {\r\n let tabPanelHeight = this.props.height;\r\n\r\n // Remove height of tab panel\r\n tabPanelHeight -= parseInt(scssVariables.menuHeightWithBorder);\r\n return tabPanelHeight;\r\n }\r\n\r\n render() {\r\n const {\r\n chains,\r\n clearChainProductDetails,\r\n currentView,\r\n deviceType,\r\n height,\r\n loadMoreSearchResults,\r\n localization,\r\n setModal,\r\n multiChainSortiment,\r\n userChains,\r\n width,\r\n editSelectedProduct,\r\n } = this.props;\r\n const tabPanelHeight = this.calculateInternalPanelHeight();\r\n\r\n const groupedList = this.groupProductsReselector(multiChainSortiment.chainProducts);\r\n\r\n let anyProductsSelected = false;\r\n for(const key in multiChainSortiment.selected) {\r\n if( multiChainSortiment.selected.hasOwnProperty(key) && multiChainSortiment.selected[key] ){\r\n anyProductsSelected = true;\r\n break;\r\n }\r\n }\r\n\r\n return (\r\n \r\n
\r\n \r\n \r\n {userChains.map((chain) => (\r\n \r\n ))}\r\n \r\n \r\n \r\n \r\n \r\n {anyProductsSelected && (\r\n \r\n \r\n \r\n {localization.text(\"chain\", \"editSelected\")}\r\n
\r\n \r\n )}\r\n \r\n \r\n \r\n \r\n \r\n {userChains.map((chain) => (\r\n \r\n \r\n \r\n ))} \r\n \r\n
\r\n );\r\n }\r\n}\r\n\r\nMultiChainSortimentCard.propTypes = {\r\n chains: PropTypes.object.isRequired,\r\n clearChainProductDetails: PropTypes.func.isRequired,\r\n currentView: PropTypes.string,\r\n deviceType: PropTypes.string.isRequired,\r\n editMultiChainFilter: PropTypes.func.isRequired,\r\n height: PropTypes.number.isRequired,\r\n history: PropTypes.object.isRequired,\r\n loadMoreSearchResults: PropTypes.func.isRequired,\r\n localization: Localization.propTypes.isRequired,\r\n location: PropTypes.object.isRequired,\r\n setModal: PropTypes.func.isRequired,\r\n multiChainSortiment: PropTypes.object.isRequired,\r\n width: PropTypes.number.isRequired,\r\n userChains: PropTypes.array.isRequired,\r\n editSelectedProduct: PropTypes.func.isRequired,\r\n clearSelectedProducts: PropTypes.func.isRequired,\r\n exportCsv : PropTypes.func.isRequired,\r\n};\r\n\r\nMultiChainSortimentCard.defaultProps = {\r\n currentView: \"all\",\r\n};\r\nexport default withRouter(MultiChainSortimentCard);\r\n","\r\nimport Icon, { iconColor, iconTypes } from \"../../common/components/Icon.jsx\";\r\n\r\nimport DropDownList from \"../../common/components/DropDownList.jsx\";\r\nimport LabelField from \"../../common/components/LabelField.jsx\";\r\nimport {Localization} from \"../../common/util/localization.jsx\";\r\nimport PropTypes from \"prop-types\";\r\nimport React from \"react\";\r\nimport { connect } from \"react-redux\";\r\n\r\nconst mapStateToProps = () => {\r\n return (state) => ({\r\n singleChainSortiment: state.singleChainSortiment,\r\n singleEpixSortiment: state.singleEpixSortiment,\r\n multiChainSortiment: state.multiChainSortiment,\r\n multiEpixSortiment: state.multiEpixSortiment,\r\n });\r\n};\r\nconst mapDispatchToProps = {\r\n};\r\n\r\n/**\r\n * Creates a compunents, with tools the change the filter\r\n * @param {props} object\r\n * @returns {node}\r\n */\r\nfunction ChainFilterComponent({singleChainSortiment, singleEpixSortiment, multiChainSortiment, multiEpixSortiment, localization, onEdit, setDropDown, useSingleEpix, useMultiChain, useMultiEpix}) {\r\n\r\n /**\r\n * Clears the filter\r\n * @returns {*}\r\n */\r\n function onClickClearFilter() {\r\n onEdit({\r\n productStatus: null,\r\n invoiceGroupId: null,\r\n productGroupId: null,\r\n supplierId: null,\r\n });\r\n }\r\n\r\n const chainSort = useSingleEpix ? singleEpixSortiment : useMultiChain ? multiChainSortiment : useMultiEpix ? multiEpixSortiment : singleChainSortiment;\r\n\r\n const prdGroupOptions = [\r\n {\r\n value: undefined,\r\n label: localization.text(\"order\", \"all\"),\r\n },\r\n ...(chainSort && chainSort.productGroups && chainSort.productGroups.map((item) => {\r\n return {\r\n value: item.productGroupId,\r\n label: item.productGroupName,\r\n };\r\n }) || []),\r\n ];\r\n const supplierGroupOptions = [\r\n {\r\n value: undefined,\r\n label: localization.text(\"order\", \"all\"),\r\n },\r\n ...(chainSort && chainSort.productSuppliers && chainSort.productSuppliers.map((item) => {\r\n return {\r\n value: item.supplierId,\r\n label: item.supplierName,\r\n };\r\n }) || []),\r\n ];\r\n const invoiceGroupsOptions = [\r\n {\r\n value: undefined,\r\n label: localization.text(\"order\", \"all\"),\r\n },\r\n ...(chainSort && chainSort.invoiceGroups && chainSort.invoiceGroups.map((item) => {\r\n return {\r\n value: item.invoiceCode,\r\n label: item.description,\r\n };\r\n }) || []),\r\n ];\r\n const statusOptions = [\r\n {value: 0, label: localization.text(\"order\", \"all\")},\r\n {value: 1, label: \"Aktiv\" },\r\n {value: 2, label: \"Erstattes ved utsolgt\" },\r\n {value: 4, label: \"Innkommende\" },\r\n {value: 5, label: \"Erstattet\" },\r\n {value: 6, label: \"Ikke aktiv ved utsolgt\" },\r\n ];\r\n\r\n const isFilterSelected = chainSort.chainFilter.productGroupId != null || chainSort.chainFilter.supplierId != null || chainSort.chainFilter.productStatus != null || singleChainSortiment.chainFilter.invoiceGroupId != null;\r\n\r\n return (\r\n \r\n
\r\n \r\n
\r\n
\r\n \r\n \r\n
\r\n \r\n \r\n \r\n
\r\n \r\n \r\n \r\n
\r\n \r\n {isFilterSelected && (\r\n \r\n \r\n
\r\n )}\r\n \r\n );\r\n}\r\n\r\nChainFilterComponent.propTypes = {\r\n localization: Localization.propTypes.isRequired,\r\n singleChainSortiment: PropTypes.object.isRequired,\r\n singleEpixSortiment: PropTypes.object.isRequired,\r\n multiChainSortiment: PropTypes.object.isRequired,\r\n multiEpixSortiment: PropTypes.object.isRequired,\r\n onEdit: PropTypes.func.isRequired,\r\n setDropDown: PropTypes.func.isRequired,\r\n useSingleEpix: PropTypes.bool.isRequired,\r\n useMultiChain: PropTypes.bool.isRequired,\r\n useMultiEpix: PropTypes.bool.isRequired,\r\n};\r\n\r\nexport default connect(mapStateToProps,mapDispatchToProps)(ChainFilterComponent);","import Icon, { iconColor, iconTypes } from \"../../common/components/Icon.jsx\";\r\n\r\nimport ChainFilterComponent from \"./ChainFilterComponent.jsx\";\r\nimport DropDown from \"../../common/components/DropDown.jsx\";\r\nimport { Localization } from \"../../common/util/localization.jsx\";\r\nimport PropTypes from \"prop-types\";\r\nimport React from \"react\";\r\nimport TextField from \"../../common/components/TextField.jsx\";\r\n\r\nclass SingleChainSearchBar extends React.PureComponent {\r\n constructor(props) {\r\n super(props);\r\n\r\n this.state = {\r\n filterActive: false,\r\n expanded: false,\r\n searchString: \"\",\r\n };\r\n this.wrapperRef = React.createRef();\r\n\r\n this.hideFilter = this.hideFilter.bind(this);\r\n this.onClickFilter = this.onClickFilter.bind(this);\r\n this.onClickClearFilter = this.onClickClearFilter.bind(this);\r\n this.handleClickOutside = this.handleClickOutside.bind(this);\r\n this.onEdit = this.onEdit.bind(this);\r\n }\r\n\r\n UNSAFE_componentWillMount() {\r\n const {\r\n onEdit,\r\n filter,\r\n } = this.props;\r\n if (filter) {\r\n onEdit({\r\n onlyNews: false,\r\n productGroupId: null,\r\n supplierId: null,\r\n ...filter,\r\n searchString: \"\",\r\n });\r\n } else {\r\n this.props.onEdit({\r\n searchString: \"\",\r\n });\r\n }\r\n\r\n this.setState({\r\n searchString: \"\",\r\n });\r\n }\r\n\r\n hideFilter() {\r\n this.setState({filterActive: false});\r\n this.props.setDropDown(null);\r\n }\r\n onClickFilter() {\r\n const {\r\n localization,\r\n setDropDown,\r\n useSingleEpix,\r\n useMultiChain,\r\n useMultiEpix,\r\n } = this.props;\r\n if( this.state.filterActive ) {\r\n this.hideFilter();\r\n } else if( !this.props.disabled && !this.state.filterActive ) {\r\n this.props.setDropDown(\r\n \r\n \r\n \r\n );\r\n\r\n this.setState({filterActive: true});\r\n }\r\n }\r\n\r\n onClickClearFilter() {\r\n this.onEdit({\r\n productStatus: null,\r\n invoiceGroupId: null,\r\n productGroupId: null,\r\n supplierId: null,\r\n });\r\n }\r\n\r\n handleClickOutside() {\r\n // Clear search\r\n this.setState({\r\n expanded: false,\r\n });\r\n }\r\n\r\n onEdit(change) {\r\n const {\r\n onEdit,\r\n } = this.props;\r\n\r\n onEdit({\r\n ...change,\r\n });\r\n\r\n if (change.searchString && this.state.expanded !== (change.searchString.length > 0) && change.searchString !== this.state.searchString) {\r\n this.setState({\r\n expanded: change.searchString ? change.searchString.length > 0 : this.state.expanded,\r\n ...change,\r\n });\r\n } else {\r\n this.setState({\r\n ...change,\r\n });\r\n }\r\n }\r\n\r\n render() {\r\n const {\r\n deviceType,\r\n disabled,\r\n localization,\r\n style,\r\n useFilter,\r\n } = this.props;\r\n\r\n const tinyDevice = deviceType == \"sm\" || deviceType == \"xs\";\r\n\r\n const isFilterSelected = this.state.productGroupId != null || this.state.supplierId != null || this.state.productStatus != null || this.state.invoiceGroupId != null;\r\n const isFilterActive = this.state.filterActive || isFilterSelected;\r\n\r\n return (\r\n \r\n \r\n
\r\n
\r\n {useFilter && (\r\n
\r\n
\r\n {!tinyDevice && (\r\n
\r\n {localization.text(\"order\", \"filterResaults\")}\r\n
\r\n )}\r\n
\r\n )}\r\n
\r\n
\r\n \r\n );\r\n }\r\n}\r\n\r\nSingleChainSearchBar.propTypes = {\r\n deviceType: PropTypes.string.isRequired,\r\n localization: Localization.propTypes.isRequired,\r\n filter: PropTypes.object.isRequired,\r\n onEdit: PropTypes.func.isRequired,\r\n setDropDown: PropTypes.func.isRequired,\r\n //\r\n disabled: PropTypes.bool,\r\n style: PropTypes.object,\r\n useFilter: PropTypes.bool,\r\n useSingleEpix: PropTypes.bool.isRequired,\r\n useMultiChain: PropTypes.bool.isRequired,\r\n useMultiEpix: PropTypes.bool.isRequired,\r\n};\r\nSingleChainSearchBar.defaultProps = {\r\n disabled: false,\r\n};\r\n\r\nexport default SingleChainSearchBar;\r\n","import \"../../../styles/page/order.scss\";\r\n\r\nimport { TitleTab, TitleTabs } from \"../../common/components/TitleTabs.jsx\";\r\n\r\nimport ContentWrapper from \"../../common/components/ContentWrapper\";\r\nimport { Localization } from \"../../common/util/localization.jsx\";\r\nimport MultiChainSortimentCard from \"./MultiChainSortimentCard.jsx\";\r\nimport PropTypes from \"prop-types\";\r\nimport React from \"react\";\r\nimport SingleChainSearchBar from \"./SingleChainSearchBar.jsx\";\r\nimport { scssVariables } from \"../../common/util/config.jsx\";\r\nimport { withRouter } from \"react-router-dom\";\r\n\r\nclass MultiChainPage extends React.PureComponent {\r\n constructor(props) {\r\n super(props);\r\n\r\n this.calculateProductDisplayHeight = this.calculateProductDisplayHeight.bind(this);\r\n this.calculateProductDisplayWidth = this.calculateProductDisplayWidth.bind(this);\r\n this.loadMoreSearchResults = this.loadMoreSearchResults.bind(this);\r\n this.onEditFilter = this.onEditFilter.bind(this);\r\n }\r\n\r\n UNSAFE_componentWillMount() {\r\n const {\r\n clearMultiChainSortiment,\r\n getNewChainProducts,\r\n loadChains,\r\n prepareQueryOptions,\r\n getInvoiceGroups,\r\n } = this.props;\r\n\r\n loadChains();\r\n clearMultiChainSortiment();\r\n getNewChainProducts();\r\n prepareQueryOptions();\r\n getInvoiceGroups();\r\n }\r\n\r\n calculateProductDisplayHeight() {\r\n const {\r\n deviceType,\r\n height,\r\n } = this.props;\r\n let productDisplayHeight = height;\r\n\r\n // Page padding\r\n productDisplayHeight -= parseInt(scssVariables[`${deviceType}ContentPadding`]) * 2;\r\n\r\n if (deviceType === \"xs\") {\r\n productDisplayHeight -= parseInt(scssVariables.menuHeightWithBorder);\r\n } else {\r\n // Title tab height\r\n productDisplayHeight -= parseInt(scssVariables.cardMargin) * 2;\r\n productDisplayHeight -= parseInt(scssVariables.titleTabHeight);\r\n\r\n // Search bar height\r\n productDisplayHeight -= parseInt(scssVariables.cardMargin) * 2;\r\n productDisplayHeight -= parseInt(scssVariables.menuHeightWithBorder);\r\n }\r\n\r\n // Product display padding\r\n productDisplayHeight -= parseInt(scssVariables.cardMargin) * 2;\r\n\r\n return productDisplayHeight;\r\n }\r\n\r\n calculateProductDisplayWidth() {\r\n const {\r\n deviceType,\r\n width,\r\n } = this.props;\r\n\r\n let productDisplayWidth = width;\r\n if (deviceType === \"xs\") {\r\n // Page padding\r\n productDisplayWidth -= parseInt(scssVariables[`${deviceType}ContentPadding`]) * 2;\r\n\r\n // Product display padding\r\n productDisplayWidth -= parseInt(scssVariables.cardMargin) * 2;\r\n } else {\r\n // Page padding\r\n productDisplayWidth -= parseInt(scssVariables[`${deviceType}ContentPadding`]); // No padding on the right side(Attached to it)\r\n\r\n // Product display padding\r\n productDisplayWidth -= parseInt(scssVariables.cardMargin) * 2;\r\n }\r\n\r\n return productDisplayWidth;\r\n }\r\n\r\n onEditFilter(...args) {\r\n const {\r\n editMultiChainFilter,\r\n flowControl,\r\n } = this.props;\r\n flowControl(async () => {\r\n await editMultiChainFilter(...args);\r\n });\r\n }\r\n\r\n loadMoreSearchResults() {\r\n const {\r\n deviceType,\r\n loadMoreMultiChainSortiment,\r\n } = this.props;\r\n const productDisplayHeight = this.calculateProductDisplayHeight();\r\n const rowsToLoad = (Math.floor(productDisplayHeight / parseInt(scssVariables.productItemHeight)) + 2);\r\n // rowsToLoad * itemsPerRow\r\n switch (deviceType) {\r\n case \"xs\":\r\n case \"sm\":\r\n this.props.flowControl(async () => { await loadMoreMultiChainSortiment(rowsToLoad * 2); });\r\n break;\r\n case \"md\":\r\n this.props.flowControl(async () => { await loadMoreMultiChainSortiment(rowsToLoad * 4); });\r\n break;\r\n case \"lg\":\r\n this.props.flowControl(async () => { await loadMoreMultiChainSortiment(rowsToLoad * 6); });\r\n break;\r\n default:\r\n this.props.flowControl(async () => { await loadMoreMultiChainSortiment(rowsToLoad * 8); });\r\n break;\r\n }\r\n }\r\n\r\n render() {\r\n const {\r\n chains,\r\n clearChainProductDetails,\r\n deviceType,\r\n editMultiChainFilter,\r\n height,\r\n localization,\r\n setModal,\r\n setDropDown,\r\n multiChainSortiment,\r\n userChains,\r\n editSelectedProduct,\r\n clearSelectedProducts,\r\n exportCsv,\r\n } = this.props;\r\n\r\n const productDisplayHeight = this.calculateProductDisplayHeight();\r\n const productDisplayWidth = this.calculateProductDisplayWidth();\r\n\r\n // const availableTabs = {\r\n // all: true,\r\n // new: true,\r\n // };\r\n\r\n const filter = {\r\n onlyNews: false,\r\n productGroupId: null,\r\n supplierId: null,\r\n };\r\n\r\n return (\r\n \r\n \r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n
\r\n );\r\n }\r\n}\r\n\r\nMultiChainPage.propTypes = {\r\n chains: PropTypes.object.isRequired,\r\n clearChainProductDetails: PropTypes.func.isRequired,\r\n clearMultiChainSortiment: PropTypes.func.isRequired,\r\n deviceType: PropTypes.string.isRequired,\r\n editMultiChainFilter: PropTypes.func.isRequired,\r\n flowControl: PropTypes.func.isRequired,\r\n getNewChainProducts: PropTypes.func.isRequired,\r\n height: PropTypes.number.isRequired,\r\n loadChains: PropTypes.func.isRequired,\r\n loadMoreMultiChainSortiment: PropTypes.func.isRequired,\r\n localization: Localization.propTypes.isRequired,\r\n prepareQueryOptions: PropTypes.func.isRequired,\r\n setModal: PropTypes.func.isRequired,\r\n setDropDown: PropTypes.func.isRequired,\r\n multiChainSortiment: PropTypes.object.isRequired,\r\n width: PropTypes.number.isRequired,\r\n userChains: PropTypes.array.isRequired,\r\n editSelectedProduct: PropTypes.func.isRequired,\r\n clearSelectedProducts: PropTypes.func.isRequired,\r\n exportCsv: PropTypes.func.isRequired,\r\n getInvoiceGroups: PropTypes.func.isRequired,\r\n};\r\n\r\nexport default withRouter(MultiChainPage);\r\n","import { clearChainProductDetails, clearMultiChainSortiment, clearSelectedProducts, editMultiChainFilter, editSelectedProduct, exportCsv, getInvoiceGroups, getNewChainProducts, loadChains, loadMoreMultiChainSortiment, prepareQueryOptions } from \"../actions/multiChainSortiment\";\r\nimport { createBoundFunction, createReselector } from \"../../common/util/reselect.js\";\r\nimport { setDropDown, setModal } from \"../../common/actions/modal\";\r\n\r\nimport MultiChainPage from \"../components/MultiChainPage.jsx\";\r\nimport { connect } from \"react-redux\";\r\nimport { createFlowControl } from \"../../common/util/flowControl\";\r\nimport { createLocalization } from \"../../common/util/localization.jsx\";\r\nimport { scssVariables } from \"../../common/util/config.jsx\";\r\n\r\nconst mapStateToProps = () => {\r\n const flowControl = createFlowControl();\r\n const flowControlCounter = createFlowControl();\r\n\r\n const userChainReselector = createReselector((chainIds, chains) => {\r\n const userChains = [...chainIds.map(id => chains[id]).filter(c => c)];\r\n userChains.sort((a, b) => a.chainName.localeCompare(b.chainName));\r\n return userChains;\r\n });\r\n\r\n return (state) => ({\r\n chains: state.multiChainSortiment.chains,\r\n deviceType: state.view.deviceType,\r\n flowControl: flowControl,\r\n flowControlCounter: flowControlCounter,\r\n height: state.view.innerHeight - parseInt(scssVariables.menuHeight),\r\n localization: createLocalization(state),\r\n multiChainSortiment: state.multiChainSortiment,\r\n userChains: userChainReselector(state.authentication.chainIds, state.multiChainSortiment.chains),\r\n width: state.view.innerWidth,\r\n });\r\n};\r\n\r\nconst mapDispatchToProps = {\r\n clearChainProductDetails,\r\n clearMultiChainSortiment,\r\n editMultiChainFilter,\r\n getNewChainProducts,\r\n loadMoreMultiChainSortiment,\r\n prepareQueryOptions,\r\n setModal,\r\n setDropDown,\r\n loadChains,\r\n editSelectedProduct,\r\n clearSelectedProducts,\r\n getInvoiceGroups,\r\n exportCsv,\r\n};\r\n\r\nconst myLoadMoreMultiChainSortiment = createBoundFunction();\r\nconst myEditMultiChainFilter = createBoundFunction();\r\n\r\nconst mergeProps = (stateProps, dispatchProps, ownProps) => ({\r\n ...stateProps,\r\n ...dispatchProps,\r\n ...ownProps,\r\n loadMoreMultiChainSortiment: myLoadMoreMultiChainSortiment((noOfProducts) => dispatchProps.loadMoreMultiChainSortiment(stateProps.multiChainSortiment, stateProps.productImage, noOfProducts)),\r\n editMultiChainFilter: myEditMultiChainFilter((change) => dispatchProps.editMultiChainFilter(change,\r\n myLoadMoreMultiChainSortiment((noOfProducts) => dispatchProps.loadMoreMultiChainSortiment(stateProps.multiChainSortiment, stateProps.productImage, noOfProducts))\r\n )),\r\n});\r\n\r\nexport default connect(mapStateToProps, mapDispatchToProps, mergeProps)(MultiChainPage);\r\n","import \"../../../styles/kjedeweb/singleChainProductListItem.scss\";\r\n\r\nimport Icon, { iconTypes } from \"../../common/components/Icon.jsx\";\r\n\r\nimport { Localization } from \"../../common/util/localization.jsx\";\r\nimport MultiChainProductModal from \"./MultiChainProductModal\";\r\nimport PropTypes from \"prop-types\";\r\nimport React from \"react\";\r\nimport ResponsiveColumn from \"../../common/components/ResponsiveColumn\";\r\nimport ResponsiveRows from \"../../common/components/ResponsiveRows\";\r\nimport { getChainLogo } from \"./MultiChainSortimentListItem\";\r\nimport moment from \"moment\";\r\n\r\nexport class MultiEpixSortimentListHeader extends React.PureComponent {\r\n render() {\r\n const {\r\n localization,\r\n showInvoiceGroup,\r\n } = this.props;\r\n\r\n return (\r\n \r\n
\r\n \r\n \r\n {localization.text(\"chain\", \"chainSortiment\", \"productAndStatus\")}\r\n
\r\n \r\n \r\n \r\n {localization.text(\"chain\", \"chainSortiment\", \"productStatus\")}\r\n
\r\n \r\n \r\n \r\n {localization.text(\"chain\", \"chainSortiment\", \"noOfSalesUnits\")}\r\n
\r\n \r\n \r\n \r\n {localization.text(\"chain\", \"chainSortiment\", \"changed\")}\r\n
\r\n \r\n {showInvoiceGroup && (\r\n \r\n \r\n {localization.text(\"chain\", \"chainSortiment\", \"invoiceGroup\")}\r\n
\r\n \r\n )}\r\n \r\n \r\n {localization.text(\"chain\", \"chainSortiment\", \"chainStatus\")}\r\n
\r\n \r\n \r\n \r\n
\r\n \r\n \r\n
\r\n );\r\n }\r\n}\r\n\r\nMultiEpixSortimentListHeader.propTypes = {\r\n localization: Localization.propTypes.isRequired,\r\n showInvoiceGroup : PropTypes.bool,\r\n};\r\n\r\nexport class MultiEpixSortimentListItem extends React.PureComponent {\r\n constructor(props) {\r\n super(props);\r\n\r\n //this.onDeleteProduct = this.onDeleteProduct.bind(this);\r\n this.showProductModal = this.showProductModal.bind(this);\r\n this.closeProductModal = this.closeProductModal.bind(this);\r\n }\r\n\r\n showProductModal(event) {\r\n event.stopPropagation();\r\n event.preventDefault();\r\n\r\n const {\r\n localization,\r\n productGroup,\r\n } = this.props;\r\n\r\n if (productGroup.find(pg => pg.inCatalogue)) {\r\n this.props.setModal();\r\n } else {\r\n this.props.setModal();\r\n }\r\n }\r\n closeProductModal(event) {\r\n event.stopPropagation();\r\n event.preventDefault();\r\n\r\n this.props.setModal(null);\r\n this.props.clearEpixProductDetails();\r\n }\r\n\r\n capitalizeFirstLetter(s) {\r\n s = s.toLowerCase();\r\n return s.charAt(0).toUpperCase() + s.slice(1);\r\n }\r\n\r\n // onDeleteProduct() {\r\n // let {\r\n // productGroup,\r\n // } = this.props;\r\n\r\n // productGroup = productGroup.map(product => ({\r\n // ...product,\r\n // inCatalogue: false\r\n // }));\r\n // this.props.updateChainProducts(productGroup);\r\n // }\r\n\r\n render() {\r\n const {\r\n chains,\r\n localization,\r\n productGroup,\r\n } = this.props;\r\n\r\n let statusColumns;\r\n\r\n if (productGroup.find(pg => pg.inCatalogue)) {\r\n statusColumns = [\r\n \r\n {productGroup.map(product => (\r\n \r\n
\r\n

\r\n
\r\n
\r\n
\r\n ))}\r\n ,\r\n \r\n \r\n {/*
*/}\r\n
\r\n \r\n
\r\n
\r\n ];\r\n } else {\r\n statusColumns = [\r\n \r\n \r\n
\r\n {localization.text(\"chain\", \"epixSortiment\", \"addPrices\")}\r\n
\r\n
\r\n ,\r\n \r\n {/* \r\n
\r\n \r\n
\r\n
*/}\r\n ];\r\n }\r\n\r\n const product = productGroup[0];\r\n\r\n return (\r\n \r\n
\r\n
\r\n \r\n \r\n
\r\n {product.imageUrl && (\r\n
\r\n
\r\n \r\n )}\r\n
\r\n
\r\n
EPD {product.epdNo}
\r\n
{product.productName}
\r\n
\r\n
\r\n \r\n \r\n \r\n
\r\n {product.status}\r\n
\r\n
\r\n \r\n \r\n \r\n
\r\n {product.noOfSalesUnits}\r\n
\r\n
\r\n \r\n \r\n \r\n
\r\n {product.lastChangedDate && moment(product.lastChangedDate).format(\"DD.MM.YY\")}\r\n
\r\n
\r\n \r\n {product.showInvoiceGroup && (\r\n \r\n \r\n
\r\n {this.capitalizeFirstLetter(product.invoiceGroupName)}\r\n
\r\n
\r\n \r\n )}\r\n {statusColumns}\r\n \r\n
\r\n
\r\n );\r\n }\r\n}\r\n\r\nMultiEpixSortimentListItem.propTypes = {\r\n chains: PropTypes.object.isRequired,\r\n clearEpixProductDetails: PropTypes.func.isRequired,\r\n localization: Localization.propTypes.isRequired,\r\n saveButtonText: PropTypes.string,\r\n setModal: PropTypes.func.isRequired,\r\n productGroup: PropTypes.array,\r\n updateChainProducts: PropTypes.func.isRequired,\r\n};\r\n\r\nMultiEpixSortimentListItem.defaultProps = {\r\n};","import \"../../../styles/productView.scss\";\r\nimport \"../../../styles/productViewListItem.scss\";\r\n\r\nimport Loading, { loadingTypes } from \"../../common/components/Loading\";\r\nimport { MultiEpixSortimentListHeader, MultiEpixSortimentListItem } from \"./MultiEpixSortimentListItem.jsx\";\r\n\r\nimport ChainScroll from \"./ChainScroll\";\r\nimport { Localization } from \"../../common/util/localization.jsx\";\r\nimport PropTypes from \"prop-types\";\r\nimport React from \"react\";\r\n\r\nclass MultiEpixSortimentList extends React.PureComponent {\r\n constructor(props) {\r\n super(props);\r\n\r\n this.state = {\r\n width: null,\r\n };\r\n this.containerNode = null;\r\n this.trackScrolling = this.trackScrolling.bind(this);\r\n this.prepareItems = this.prepareItems.bind(this);\r\n }\r\n\r\n trackScrolling() {\r\n const {\r\n isLoading,\r\n loadMoreProducts,\r\n } = this.props;\r\n\r\n //load more products if none is loading\r\n if (isLoading === false && loadMoreProducts) {\r\n loadMoreProducts(50);\r\n }\r\n }\r\n\r\n prepareItems() {\r\n const {\r\n chains,\r\n clearEpixProductDetails,\r\n deviceType,\r\n list,\r\n localization,\r\n isLoading,\r\n setModal,\r\n updateChainProducts\r\n } = this.props;\r\n\r\n const retNodes = [];\r\n\r\n for (let i = 0; i < list.length; i++) {\r\n retNodes[retNodes.length] = (\r\n );\r\n }\r\n if (isLoading) {\r\n retNodes[retNodes.length] =\r\n retNodes[retNodes.length] =\r\n ;\r\n }\r\n return retNodes;\r\n }\r\n\r\n render() {\r\n const {\r\n deviceType,\r\n localization,\r\n height,\r\n style,\r\n list,\r\n } = this.props;\r\n\r\n const nodes = this.prepareItems();\r\n\r\n var listFlattened = Array.prototype.concat.apply([], list);\r\n const showInvoiceGroup = listFlattened.some(li => li.showInvoiceGroup);\r\n\r\n return (\r\n \r\n \r\n \r\n
\r\n \r\n {nodes}\r\n \r\n \r\n );\r\n }\r\n}\r\n\r\nMultiEpixSortimentList.propTypes = {\r\n chains: PropTypes.object.isRequired,\r\n clearEpixProductDetails: PropTypes.func.isRequired,\r\n deviceType: PropTypes.string.isRequired,\r\n height: PropTypes.number,\r\n // If true a loading icon will be displayed\r\n isLoading: PropTypes.bool,\r\n // An array of products to be displayed\r\n list: PropTypes.array.isRequired,\r\n // A function that will load in more items into list\r\n loadMoreProducts: PropTypes.func,\r\n localization: Localization.propTypes.isRequired,\r\n setModal: PropTypes.func.isRequired,\r\n style: PropTypes.object,\r\n updateChainProducts: PropTypes.func.isRequired\r\n};\r\n\r\nexport default MultiEpixSortimentList;\r\n","import { ChainTab, ChainTabList, ChainTabPanel, ChainTabs } from \"./ChainTabs.jsx\";\r\nimport { SubMenu, SubMenuItem } from \"../../common/components/SubMenu.jsx\";\r\n\r\nimport { Localization } from \"../../common/util/localization.jsx\";\r\nimport MultiEpixSortimentList from \"./MultiEpixSortimentList.jsx\";\r\nimport PropTypes from \"prop-types\";\r\nimport React from \"react\";\r\nimport { createReselector } from \"../../common/util/reselect.js\";\r\nimport { iconTypes } from \"../../common/components/Icon.jsx\";\r\nimport { scssVariables } from \"../../common/util/config.jsx\";\r\nimport { withRouter } from \"react-router-dom\";\r\n\r\nclass MultiEpixSortimentCard extends React.PureComponent {\r\n constructor(props) {\r\n super(props);\r\n\r\n this.swallowOnClick = this.swallowOnClick.bind(this);\r\n this.onTabAllClicked = this.onTabAllClicked.bind(this);\r\n this.onTabNewClicked = this.onTabNewClicked.bind(this);\r\n this.calculateInternalPanelHeight = this.calculateInternalPanelHeight.bind(this);\r\n this.onExportCsv = this.onExportCsv.bind(this);\r\n\r\n this.groupProductsReselector = createReselector(chainProducts => {\r\n let group = [];\r\n const groups = [];\r\n\r\n for (const p of chainProducts) {\r\n if (group.length === 0) {\r\n group.push(p.product);\r\n } else if (group[0].productId === p.product.productId) {\r\n group.push(p.product);\r\n } else {\r\n groups.push(group);\r\n group.sort((a, b) => a.chainName - b.chainName);\r\n group = [p.product];\r\n }\r\n }\r\n\r\n if (group.length > 0) {\r\n groups.push(group);\r\n group.sort((a, b) => a.chainName - b.chainName);\r\n }\r\n\r\n return groups;\r\n });\r\n }\r\n\r\n onTabAllClicked() {\r\n this.props.editMultiEpixFilter({\r\n onlyNews: false,\r\n });\r\n }\r\n\r\n onTabNewClicked() {\r\n this.props.editMultiEpixFilter({\r\n onlyNews: true,\r\n });\r\n }\r\n\r\n swallowOnClick(event) {\r\n event.stopPropagation();\r\n event.preventDefault();\r\n }\r\n\r\n onExportCsv() {\r\n\r\n const {\r\n multiEpixSortiment,\r\n exportCsv,\r\n } = this.props;\r\n\r\n exportCsv(multiEpixSortiment);\r\n }\r\n\r\n calculateInternalPanelHeight() {\r\n let tabPanelHeight = this.props.height;\r\n\r\n // Remove height of tab panel\r\n tabPanelHeight -= parseInt(scssVariables.menuHeightWithBorder);\r\n return tabPanelHeight;\r\n }\r\n\r\n render() {\r\n const {\r\n chains,\r\n clearEpixProductDetails,\r\n currentView,\r\n deviceType,\r\n height,\r\n loadMoreSearchResults,\r\n localization,\r\n setModal,\r\n multiEpixSortiment,\r\n updateChainProducts,\r\n width,\r\n } = this.props;\r\n const tabPanelHeight = this.calculateInternalPanelHeight();\r\n\r\n const groupedProducts = this.groupProductsReselector(multiEpixSortiment.allProducts);\r\n\r\n return (\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n );\r\n }\r\n}\r\n\r\nMultiEpixSortimentCard.propTypes = {\r\n chains: PropTypes.object.isRequired,\r\n clearEpixProductDetails: PropTypes.func.isRequired,\r\n currentView: PropTypes.string,\r\n deviceType: PropTypes.string.isRequired,\r\n editMultiEpixFilter: PropTypes.func.isRequired,\r\n height: PropTypes.number.isRequired,\r\n history: PropTypes.object.isRequired,\r\n loadMoreSearchResults: PropTypes.func.isRequired,\r\n localization: Localization.propTypes.isRequired,\r\n location: PropTypes.object.isRequired,\r\n setModal: PropTypes.func.isRequired,\r\n multiEpixSortiment: PropTypes.object.isRequired,\r\n updateChainProducts: PropTypes.func.isRequired,\r\n width: PropTypes.number.isRequired,\r\n exportCsv : PropTypes.func.isRequired,\r\n};\r\n\r\nMultiEpixSortimentCard.defaultProps = {\r\n currentView: \"all\",\r\n};\r\nexport default withRouter(MultiEpixSortimentCard);\r\n","import \"../../../styles/page/order.scss\";\r\n\r\nimport { TitleTab, TitleTabs } from \"../../common/components/TitleTabs.jsx\";\r\n\r\nimport ContentWrapper from \"../../common/components/ContentWrapper\";\r\nimport { Localization } from \"../../common/util/localization.jsx\";\r\nimport MultiEpixSortimentCard from \"./MultiEpixSortimentCard.jsx\";\r\nimport PropTypes from \"prop-types\";\r\nimport React from \"react\";\r\nimport SingleChainSearchBar from \"./SingleChainSearchBar.jsx\";\r\nimport { scssVariables } from \"../../common/util/config.jsx\";\r\nimport { withRouter } from \"react-router-dom\";\r\n\r\nclass MultiEpixPage extends React.PureComponent {\r\n constructor(props) {\r\n super(props);\r\n\r\n this.calculateProductDisplayHeight = this.calculateProductDisplayHeight.bind(this);\r\n this.calculateProductDisplayWidth = this.calculateProductDisplayWidth.bind(this);\r\n this.loadMoreSearchResults = this.loadMoreSearchResults.bind(this);\r\n this.onEditFilter = this.onEditFilter.bind(this);\r\n }\r\n\r\n UNSAFE_componentWillMount() {\r\n const {\r\n clearMultiEpixSortiment,\r\n loadChains,\r\n prepareQueryOptions,\r\n } = this.props;\r\n\r\n loadChains();\r\n clearMultiEpixSortiment();\r\n prepareQueryOptions();\r\n }\r\n\r\n calculateProductDisplayHeight() {\r\n const {\r\n deviceType,\r\n height,\r\n } = this.props;\r\n let productDisplayHeight = height;\r\n\r\n // Page padding\r\n productDisplayHeight -= parseInt(scssVariables[`${deviceType}ContentPadding`]) * 2;\r\n\r\n if (deviceType === \"xs\") {\r\n productDisplayHeight -= parseInt(scssVariables.menuHeightWithBorder);\r\n } else {\r\n // Title tab height\r\n productDisplayHeight -= parseInt(scssVariables.cardMargin) * 2;\r\n productDisplayHeight -= parseInt(scssVariables.titleTabHeight);\r\n\r\n // Search bar height\r\n productDisplayHeight -= parseInt(scssVariables.cardMargin) * 2;\r\n productDisplayHeight -= parseInt(scssVariables.menuHeightWithBorder);\r\n }\r\n\r\n // Product display padding\r\n productDisplayHeight -= parseInt(scssVariables.cardMargin) * 2;\r\n\r\n return productDisplayHeight;\r\n }\r\n\r\n calculateProductDisplayWidth() {\r\n const {\r\n deviceType,\r\n width,\r\n } = this.props;\r\n\r\n let productDisplayWidth = width;\r\n if (deviceType === \"xs\") {\r\n // Page padding\r\n productDisplayWidth -= parseInt(scssVariables[`${deviceType}ContentPadding`]) * 2;\r\n\r\n // Product display padding\r\n productDisplayWidth -= parseInt(scssVariables.cardMargin) * 2;\r\n } else {\r\n // Page padding\r\n productDisplayWidth -= parseInt(scssVariables[`${deviceType}ContentPadding`]); // No padding on the right side(Attached to it)\r\n\r\n // Product display padding\r\n productDisplayWidth -= parseInt(scssVariables.cardMargin) * 2;\r\n }\r\n\r\n return productDisplayWidth;\r\n }\r\n\r\n onEditFilter(...args) {\r\n const {\r\n editMultiEpixFilter,\r\n flowControl,\r\n } = this.props;\r\n flowControl(async () => {\r\n await editMultiEpixFilter(...args);\r\n });\r\n }\r\n\r\n loadMoreSearchResults() {\r\n const {\r\n deviceType,\r\n loadMoreMultiEpixSortiment,\r\n } = this.props;\r\n const productDisplayHeight = this.calculateProductDisplayHeight();\r\n const rowsToLoad = 4 * (Math.floor(productDisplayHeight / parseInt(scssVariables.productItemHeight)) + 2);\r\n // rowsToLoad * itemsPerRow\r\n switch (deviceType) {\r\n case \"xs\":\r\n case \"sm\":\r\n this.props.flowControl(async () => { await loadMoreMultiEpixSortiment(rowsToLoad * 2); });\r\n break;\r\n case \"md\":\r\n this.props.flowControl(async () => { await loadMoreMultiEpixSortiment(rowsToLoad * 4); });\r\n break;\r\n case \"lg\":\r\n this.props.flowControl(async () => { await loadMoreMultiEpixSortiment(rowsToLoad * 6); });\r\n break;\r\n default:\r\n this.props.flowControl(async () => { await loadMoreMultiEpixSortiment(rowsToLoad * 8); });\r\n break;\r\n }\r\n }\r\n\r\n render() {\r\n const {\r\n chains,\r\n clearEpixProductDetails,\r\n deviceType,\r\n editMultiEpixFilter,\r\n height,\r\n localization,\r\n setModal,\r\n setDropDown,\r\n multiEpixSortiment,\r\n updateChainProducts,\r\n exportCsv,\r\n } = this.props;\r\n\r\n const productDisplayHeight = this.calculateProductDisplayHeight();\r\n const productDisplayWidth = this.calculateProductDisplayWidth();\r\n\r\n // const availableTabs = {\r\n // all: true,\r\n // new: true,\r\n // };\r\n\r\n const filter = {\r\n onlyNews: false,\r\n productGroupId: null,\r\n supplierId: null,\r\n };\r\n\r\n return (\r\n \r\n \r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n
\r\n );\r\n }\r\n}\r\n\r\nMultiEpixPage.propTypes = {\r\n chains: PropTypes.object.isRequired,\r\n clearEpixProductDetails: PropTypes.func.isRequired,\r\n clearMultiEpixSortiment: PropTypes.func.isRequired,\r\n deviceType: PropTypes.string.isRequired,\r\n editMultiEpixFilter: PropTypes.func.isRequired,\r\n flowControl: PropTypes.func.isRequired,\r\n height: PropTypes.number.isRequired,\r\n loadChains: PropTypes.func.isRequired,\r\n loadMoreMultiEpixSortiment: PropTypes.func.isRequired,\r\n localization: Localization.propTypes.isRequired,\r\n prepareQueryOptions: PropTypes.func.isRequired,\r\n setModal: PropTypes.func.isRequired,\r\n setDropDown: PropTypes.func.isRequired,\r\n multiEpixSortiment: PropTypes.object.isRequired,\r\n updateChainProducts: PropTypes.func.isRequired,\r\n width: PropTypes.number.isRequired,\r\n exportCsv: PropTypes.func.isRequired,\r\n};\r\n\r\nexport default withRouter(MultiEpixPage);\r\n","import { clearEpixProductDetails, clearMultiEpixSortiment, editMultiEpixFilter, loadMoreMultiEpixSortiment, prepareQueryOptions, updateChainProducts } from \"../actions/multiEpixSortiment\";\r\nimport { exportCsv, loadChains } from \"../actions/multiChainSortiment\";\r\nimport { setDropDown, setModal } from \"../../common/actions/modal\";\r\n\r\nimport MultiEpixPage from \"../components/MultiEpixPage.jsx\";\r\nimport { connect } from \"react-redux\";\r\nimport { createBoundFunction } from \"../../common/util/reselect.js\";\r\nimport { createFlowControl } from \"../../common/util/flowControl\";\r\nimport { createLocalization } from \"../../common/util/localization.jsx\";\r\nimport { scssVariables } from \"../../common/util/config.jsx\";\r\n\r\nconst mapStateToProps = () => {\r\n const flowControl = createFlowControl();\r\n const flowControlCounter = createFlowControl();\r\n\r\n return (state) => ({\r\n chains: state.multiChainSortiment.chains,\r\n deviceType: state.view.deviceType,\r\n flowControl: flowControl,\r\n flowControlCounter: flowControlCounter,\r\n height: state.view.innerHeight - parseInt(scssVariables.menuHeight),\r\n localization: createLocalization(state),\r\n multiEpixSortiment: state.multiEpixSortiment,\r\n width: state.view.innerWidth,\r\n });\r\n};\r\n\r\nconst mapDispatchToProps = {\r\n clearEpixProductDetails,\r\n clearMultiEpixSortiment,\r\n editMultiEpixFilter,\r\n loadChains,\r\n loadMoreMultiEpixSortiment,\r\n prepareQueryOptions,\r\n setModal,\r\n setDropDown,\r\n updateChainProducts,\r\n exportCsv,\r\n};\r\n\r\nconst myLoadMoreMultiEpixSortiment = createBoundFunction();\r\nconst myEditMultiEpixFilter = createBoundFunction();\r\n\r\nconst mergeProps = (stateProps, dispatchProps, ownProps) => ({\r\n ...stateProps,\r\n ...dispatchProps,\r\n ...ownProps,\r\n loadMoreMultiEpixSortiment: myLoadMoreMultiEpixSortiment((noOfProducts) => dispatchProps.loadMoreMultiEpixSortiment(stateProps.multiEpixSortiment, stateProps.productImage, noOfProducts)),\r\n editMultiEpixFilter: myEditMultiEpixFilter((change) => dispatchProps.editMultiEpixFilter(change,\r\n myLoadMoreMultiEpixSortiment((noOfProducts) => dispatchProps.loadMoreMultiEpixSortiment(stateProps.multiEpixSortiment, stateProps.productImage, noOfProducts))\r\n )),\r\n});\r\n\r\nexport default connect(mapStateToProps, mapDispatchToProps, mergeProps)(MultiEpixPage);\r\n","import \"../../../../styles/OrderProducListCard.scss\";\r\n\r\nimport Icon, { iconColor, iconTypes } from \"../../../common/components/Icon\";\r\nimport { Tag, tagTypes } from \"../../../common/components/Tag\";\r\n\r\nimport CounterField from \"../../../common/components/CounterField\";\r\nimport { Localization } from \"../../../common/util/localization.jsx\";\r\nimport ProductView from \"../product/ProductView\";\r\nimport PropTypes from \"prop-types\";\r\nimport React from \"react\";\r\nimport { scssVariables } from \"../../../common/util/config.jsx\";\r\nimport { withRouter } from \"react-router-dom\";\r\n\r\nclass MyListCard extends React.PureComponent {\r\n constructor(props){\r\n super(props);\r\n\r\n this.state = {\r\n expanded: false,\r\n };\r\n\r\n this.expand = this.expand.bind(this);\r\n this.collapse = this.collapse.bind(this);\r\n this.onClickEdit = this.onClickEdit.bind(this);\r\n this.onClickAddAll = this.onClickAddAll.bind(this);\r\n this.onClickBarcode = this.onClickBarcode.bind(this);\r\n }\r\n\r\n expand(){\r\n this.setState({\r\n expanded: true,\r\n });\r\n }\r\n collapse(){\r\n this.setState({\r\n expanded: false,\r\n });\r\n }\r\n onClickEdit() {\r\n this.props.history.push(`/order/lists/edit/${this.props.listId}`);\r\n }\r\n onClickAddAll() {\r\n this.props.addMyListToOrder(this.props.products);\r\n }\r\n onClickBarcode() {\r\n const {\r\n downloadListPdf,\r\n listId,\r\n labelName,\r\n } = this.props;\r\n\r\n downloadListPdf(listId, labelName);\r\n }\r\n\r\n render() {\r\n const {\r\n localization,\r\n activeOrder,\r\n products,\r\n width,\r\n labelName,\r\n deviceType,\r\n addRemoveProductToTemporaryOrder,\r\n setModal,\r\n style,\r\n sortLists,\r\n } = this.props;\r\n //size of left info window \r\n const marginLeft = `${deviceType===\"xs\"?2:(deviceType===\"sm\"?4:16)}px`;\r\n //remaining width removin padding used for card\r\n const widthLeft = width;\r\n\r\n const isTinyDevice = deviceType===\"sm\" || deviceType===\"xs\" || deviceType===\"md\";\r\n const hasWarnings = products.some(p => p.product.notActive === true);\r\n\r\n return (\r\n \r\n \r\n
\r\n {sortLists && (\r\n
\r\n )} \r\n \r\n {isTinyDevice && hasWarnings && (\r\n \r\n \r\n \r\n
\r\n )} \r\n \r\n {!isTinyDevice && (\r\n
\r\n \r\n
\r\n )}\r\n
\r\n {!isTinyDevice && hasWarnings && (\r\n
\r\n \r\n
\r\n )} \r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n {this.state.expanded && (\r\n \r\n )}\r\n \r\n \r\n );\r\n }\r\n}\r\n\r\nMyListCard.propTypes = {\r\n //Required\r\n listId: PropTypes.number.isRequired,\r\n deviceType: PropTypes.string.isRequired,\r\n localization: Localization.propTypes.isRequired,\r\n activeOrder: PropTypes.object.isRequired,\r\n productView: PropTypes.object.isRequired,\r\n addRemoveProductToTemporaryOrder: PropTypes.func.isRequired,\r\n width: PropTypes.number.isRequired,\r\n products: PropTypes.array.isRequired,\r\n labelHeader: PropTypes.string.isRequired,\r\n labelName: PropTypes.string.isRequired,\r\n addMyListToOrder: PropTypes.func.isRequired,\r\n downloadListPdf: PropTypes.func.isRequired,\r\n history: PropTypes.object.isRequired,\r\n setModal: PropTypes.func.isRequired,\r\n style: PropTypes.object,\r\n sortLists: PropTypes.bool.isRequired,\r\n};\r\n\r\nexport default withRouter(MyListCard);","import \"../../../../styles/page/order.scss\";\r\n\r\nimport { DragDropContext, Draggable, Droppable } from \"react-beautiful-dnd\";\r\nimport Icon, { iconColor, iconTypes } from \"../../../common/components/Icon\";\r\nimport {TitleTab, TitleTabs} from \"../../../common/components/TitleTabs.jsx\";\r\n\r\nimport ContentWrapper from \"../../../common/components/ContentWrapper.jsx\";\r\nimport {Localization} from \"../../../common/util/localization.jsx\";\r\nimport MyListCard from \"./MyListCard.jsx\";\r\nimport PropTypes from \"prop-types\";\r\nimport React from \"react\";\r\nimport ShoppingCart from \"../../components/order/ShoppingCart.jsx\";\r\nimport {scssVariables} from \"../../../common/util/config.jsx\";\r\n//import {updateListSortOrder} from \"../../actions/productLists.js\";\r\nimport {withRouter} from \"react-router-dom\";\r\n\r\nclass MyListPage extends React.PureComponent {\r\n constructor(props){\r\n super(props); \r\n this.calculateProductDisplayHeight = this.calculateProductDisplayHeight.bind(this);\r\n this.calculateShoppingCartHeight = this.calculateShoppingCartHeight.bind(this);\r\n this.calculateProductDisplayWidth = this.calculateProductDisplayWidth.bind(this);\r\n this.loadMoreSearchResaults = this.loadMoreSearchResaults.bind(this);\r\n this.createNewList = this.createNewList.bind(this);\r\n this.sortLists = this.sortLists.bind(this);\r\n this.onDragEnd = this.onDragEnd.bind(this);\r\n this.createDraggableLists = this.createDraggableLists.bind(this);\r\n this.createDraggableCards = this.createDraggableCards.bind(this);\r\n this.createCards = this.createCards.bind(this);\r\n }\r\n \r\n UNSAFE_componentWillMount() {\r\n const {\r\n activeOrder,\r\n getMyLists,\r\n initiateCurrentOrder,\r\n getOrderFeeLimits,\r\n getOrderVolumeDiscounts,\r\n } = this.props;\r\n getMyLists();\r\n getOrderFeeLimits();\r\n getOrderVolumeDiscounts();\r\n if( activeOrder && activeOrder.loading==false && activeOrder.shipmentId==null) {\r\n initiateCurrentOrder();\r\n }\r\n }\r\n onDragEnd(result) {\r\n const {\r\n updateListSortOrder,\r\n } = this.props;\r\n\r\n // dropped outside the list\r\n if (!result.destination) {\r\n return;\r\n }\r\n\r\n //swap places\r\n updateListSortOrder(result.source.index, result.destination.index);\r\n }\r\n\r\n createDraggableLists() {\r\n const drag = (\r\n
\r\n \r\n {(provided) => (\r\n \r\n {\r\n this.createDraggableCards()\r\n }\r\n {provided.placeholder}\r\n
\r\n )}\r\n \r\n );\r\n return drag;\r\n }\r\n\r\n createDraggableCards()\r\n {\r\n const {\r\n localization,\r\n productLists,\r\n addRemoveProductToTemporaryOrder,\r\n deviceType,\r\n activeOrder,\r\n productView,\r\n addMyListToOrder,\r\n downloadListPdf,\r\n history,\r\n setModal,\r\n } = this.props;\r\n const productDisplayWidth = this.calculateProductDisplayWidth();\r\n const nodePrd = [];\r\n for(let i=0; i
=0){\r\n nodePrd.push(\r\n \r\n {(provided, snapshot) => (\r\n \r\n \r\n
\r\n )}\r\n \r\n );\r\n }\r\n }\r\n return nodePrd;\r\n }\r\n\r\n createCards()\r\n {\r\n const {\r\n localization,\r\n productLists,\r\n addRemoveProductToTemporaryOrder,\r\n deviceType,\r\n activeOrder,\r\n productView,\r\n addMyListToOrder,\r\n downloadListPdf,\r\n history,\r\n setModal,\r\n } = this.props;\r\n const productDisplayWidth = this.calculateProductDisplayWidth();\r\n const nodePrd = [];\r\n for(let i=0; i=0){\r\n nodePrd.push(\r\n \r\n );\r\n }\r\n }\r\n return nodePrd;\r\n }\r\n\r\n calculateProductDisplayHeight() {\r\n const {\r\n deviceType,\r\n height,\r\n } = this.props;\r\n let productDisplayHeight = height;\r\n \r\n //page padding\r\n productDisplayHeight -= parseInt(scssVariables[`${deviceType}ContentPadding`])*2;\r\n\r\n if( deviceType===\"xs\" ) {\r\n //shopping cart in menu form\r\n productDisplayHeight -= parseInt(scssVariables.menuHeightWithBorder);\r\n } else {\r\n //title tab height\r\n productDisplayHeight -= parseInt(scssVariables.cardMargin)*2;\r\n productDisplayHeight -= parseInt(scssVariables.titleTabHeight);\r\n //searchbar height\r\n productDisplayHeight -= parseInt(scssVariables.cardMargin)*2;\r\n productDisplayHeight -= parseInt(scssVariables.menuHeightWithBorder);\r\n }\r\n //product display padding\r\n productDisplayHeight -= parseInt(scssVariables.cardMargin)*2;\r\n\r\n return productDisplayHeight;\r\n }\r\n calculateProductDisplayWidth() {\r\n const {\r\n deviceType,\r\n width,\r\n } = this.props;\r\n\r\n const isTinyDevice = deviceType==\"xs\" || deviceType==\"sm\";\r\n\r\n let productDisplayWidth = width;\r\n if( deviceType===\"xs\" ) {\r\n //page padding\r\n productDisplayWidth -= parseInt(scssVariables[`${deviceType}ContentPadding`])*2;\r\n //product display padding\r\n productDisplayWidth -= parseInt(scssVariables.cardMargin)*2;\r\n } else {\r\n //page padding\r\n productDisplayWidth -= parseInt(scssVariables[`${deviceType}ContentPadding`]);//no padding on the right side(Attached to it)\r\n //page padding\r\n productDisplayWidth -= parseInt(isTinyDevice ? scssVariables.shoppingCartWidthTiny : scssVariables.shoppingCartWidth);\r\n //product display padding\r\n productDisplayWidth -= parseInt(scssVariables.cardMargin)*2;\r\n }\r\n\r\n return productDisplayWidth;\r\n }\r\n calculateShoppingCartHeight() {\r\n const {\r\n deviceType,\r\n height,\r\n } = this.props;\r\n let productDisplayHeight = height;\r\n \r\n //page padding\r\n productDisplayHeight -= parseInt(scssVariables[`${deviceType}ContentPadding`])*2;\r\n //product display margin\r\n productDisplayHeight -= parseInt(scssVariables.cardMargin)*2;\r\n\r\n return productDisplayHeight;\r\n }\r\n\r\n loadMoreSearchResaults() {\r\n const {\r\n deviceType,\r\n loadMoreSearchedProducts,\r\n } = this.props;\r\n const productDisplayHeight = this.calculateProductDisplayHeight();\r\n const rowsToLoad = (Math.floor(productDisplayHeight/parseInt(scssVariables.productItemHeight))+2);\r\n // rowsToLoad * itemsPerRow\r\n switch(deviceType){\r\n case \"xs\":\r\n case \"sm\":\r\n loadMoreSearchedProducts( rowsToLoad*2 );\r\n break;\r\n case \"md\":\r\n loadMoreSearchedProducts( rowsToLoad*4 );\r\n break;\r\n case \"lg\":\r\n loadMoreSearchedProducts( rowsToLoad*6 );\r\n break;\r\n default:\r\n loadMoreSearchedProducts( rowsToLoad*8 );\r\n break;\r\n }\r\n }\r\n\r\n createNewList(){\r\n this.props.createNewMyList(this.props.history);\r\n }\r\n sortLists(){\r\n this.props.setMyListsSortingMode(!this.props.sortLists);\r\n }\r\n\r\n render(){\r\n const {\r\n deviceType,\r\n localization,\r\n activeOrder,\r\n addRemoveProductToTemporaryOrder,\r\n height,\r\n width,\r\n submitOrder,\r\n deliveryDates,\r\n setActiveOrder,\r\n moveUnconfirmedLinesToNextOrder,\r\n setModal,\r\n setDropDown,\r\n orderFeeLimits,\r\n orderVolumeDiscounts,\r\n newSeasonDistrDates,\r\n showFreshFood,\r\n sortLists,\r\n } = this.props;\r\n const shoppingCartHeight = this.calculateShoppingCartHeight();\r\n\r\n const isTinyDevice = deviceType==\"xs\" || deviceType==\"sm\";\r\n\r\n return deviceType==\"xs\" ? (\r\n \r\n \r\n
\r\n \r\n \r\n
\r\n {sortLists ? this.createDraggableLists() : this.createCards()}\r\n
\r\n
\r\n \r\n ) : (\r\n \r\n \r\n
\r\n \r\n \r\n \r\n \r\n { showFreshFood && (\r\n \r\n )} \r\n \r\n {sortLists ? this.createDraggableLists() : this.createCards()}\r\n \r\n \r\n
\r\n
\r\n \r\n
\r\n
\r\n \r\n );\r\n }\r\n}\r\n\r\nMyListPage.propTypes = {\r\n //Required\r\n deviceType: PropTypes.string.isRequired,\r\n localization: Localization.propTypes.isRequired,\r\n setOrderProductView: PropTypes.func.isRequired,\r\n productView: PropTypes.object.isRequired,\r\n activeOrder: PropTypes.object.isRequired,\r\n addRemoveProductToTemporaryOrder: PropTypes.func.isRequired,\r\n editQueryFilter: PropTypes.func.isRequired,\r\n height: PropTypes.number.isRequired,\r\n width: PropTypes.number.isRequired,\r\n loadMoreSearchedProducts: PropTypes.func.isRequired,\r\n productQuery: PropTypes.object.isRequired,\r\n submitOrder: PropTypes.func.isRequired,\r\n deliveryDates: PropTypes.array.isRequired,\r\n setActiveOrder: PropTypes.func.isRequired,\r\n productLists: PropTypes.object.isRequired,\r\n getMyLists: PropTypes.func.isRequired,\r\n createNewMyList: PropTypes.func.isRequired,\r\n addMyListToOrder: PropTypes.func.isRequired,\r\n downloadListPdf: PropTypes.func.isRequired,\r\n history: PropTypes.object.isRequired,\r\n initiateCurrentOrder: PropTypes.func.isRequired,\r\n moveUnconfirmedLinesToNextOrder: PropTypes.func.isRequired,\r\n setModal: PropTypes.func.isRequired,\r\n setDropDown: PropTypes.func.isRequired,\r\n getOrderFeeLimits: PropTypes.func.isRequired,\r\n orderFeeLimits: PropTypes.array.isRequired,\r\n getOrderVolumeDiscounts: PropTypes.func.isRequired,\r\n orderVolumeDiscounts: PropTypes.array.isRequired,\r\n newSeasonDistrDates: PropTypes.array.isRequired,\r\n showFreshFood: PropTypes.bool.isRequired,\r\n updateListSortOrder: PropTypes.func.isRequired,\r\n sortLists: PropTypes.bool.isRequired,\r\n setMyListsSortingMode: PropTypes.func.isRequired,\r\n};\r\n\r\nexport default withRouter(MyListPage);","import {addMyListToOrder, createNewMyList, downloadListPdf, getMyLists, setMyListsSortingMode, updateListSortOrder} from \"../actions/productLists.js\";\r\nimport {addRemoveProductToTemporaryOrder, getOrderFeeLimits, getOrderVolumeDiscounts, moveUnconfirmedLinesToNextOrder, setActiveOrder, submitOrder} from \"../actions/order.js\";\r\nimport {editQueryFilter, loadMoreSearchedProducts} from \"../actions/productQuery.js\";\r\nimport {setDropDown, setModal} from \"../../common/actions/modal.js\";\r\n\r\nimport MyListPage from \"../components/order/MyListPage.jsx\";\r\nimport {connect} from \"react-redux\";\r\nimport {createBoundFunction} from \"../../common/util/reselect.js\";\r\nimport {createLocalization} from \"../../common/util/localization.jsx\";\r\nimport {initiateCurrentOrder} from \"../actions/worker.js\";\r\nimport {scssVariables} from \"../../common/util/config.jsx\";\r\nimport {setOrderProductView} from \"../actions/order.js\";\r\n\r\nconst mapStateToProps = () => {\r\n return (state) => ({\r\n localization: createLocalization(state),\r\n authentication: state.authentication,\r\n productView: state.order.productView,\r\n deviceType: state.view.deviceType,\r\n productQuery: state.productQuery,\r\n activeOrder: state.order.active,\r\n productImage: state.productImage,\r\n width: state.view.innerWidth,\r\n deliveryDates: state.delivery.dates.deliveryDates || [],\r\n height: state.view.innerHeight-parseInt(scssVariables.menuHeight),\r\n productLists: state.productLists,\r\n orderFeeLimits: state.order.orderFeeLimits,\r\n orderVolumeDiscounts: state.order.orderVolumeDiscounts,\r\n newSeasonDistrDates : state.authentication.newSeasonDistrDates || [],\r\n showFreshFood: state.authentication.showFreshFood,\r\n sortLists: state.productLists.customListsSorting,\r\n });\r\n};\r\n\r\nconst mapDispatchToProps = {\r\n setOrderProductView,\r\n loadMoreSearchedProducts,\r\n editQueryFilter,\r\n addRemoveProductToTemporaryOrder,\r\n submitOrder,\r\n setActiveOrder,\r\n getMyLists,\r\n createNewMyList,\r\n addMyListToOrder,\r\n downloadListPdf,\r\n initiateCurrentOrder,\r\n moveUnconfirmedLinesToNextOrder,\r\n setModal,\r\n setDropDown,\r\n getOrderFeeLimits,\r\n getOrderVolumeDiscounts,\r\n updateListSortOrder,\r\n setMyListsSortingMode,\r\n};\r\n\r\nconst myAddRemoveProductToTemporaryOrder = createBoundFunction();\r\nconst myLoadMoreSearchedProducts = createBoundFunction();\r\nconst myEditQueryFilter = createBoundFunction();\r\nconst mySubmitOrder = createBoundFunction();\r\nconst mySetActiveOrder = createBoundFunction();\r\nconst myAddMyListToOrder = createBoundFunction();\r\nconst myMoveUnconfirmedLinesToNextOrder = createBoundFunction();\r\nconst myDownloadListPdf = createBoundFunction();\r\n\r\nconst mergeProps = (stateProps, dispatchProps, ownProps) => ({\r\n ...stateProps,\r\n ...dispatchProps,\r\n ...ownProps,\r\n addRemoveProductToTemporaryOrder: myAddRemoveProductToTemporaryOrder((product, qty, salesLineId) => dispatchProps.addRemoveProductToTemporaryOrder(stateProps.activeOrder, product, qty, salesLineId)),\r\n moveUnconfirmedLinesToNextOrder: myMoveUnconfirmedLinesToNextOrder(() => dispatchProps.moveUnconfirmedLinesToNextOrder(stateProps.deliveryDates, stateProps.activeOrder)),\r\n loadMoreSearchedProducts: myLoadMoreSearchedProducts((noOfProducts) => dispatchProps.loadMoreSearchedProducts(stateProps.productQuery, stateProps.productImage, noOfProducts)),\r\n submitOrder: mySubmitOrder(() => dispatchProps.submitOrder(stateProps.activeOrder)),\r\n setActiveOrder: mySetActiveOrder((shipmentId, distributionRouteId, deliveryDate) => dispatchProps.setActiveOrder(shipmentId, distributionRouteId, deliveryDate)),\r\n editQueryFilter: myEditQueryFilter( (change) => dispatchProps.editQueryFilter(stateProps.productQuery, stateProps.productImage, change, \r\n myLoadMoreSearchedProducts((noOfProducts) => dispatchProps.loadMoreSearchedProducts(stateProps.productQuery, stateProps.productImage, noOfProducts))\r\n )),\r\n downloadListPdf: myDownloadListPdf((myListId, listName) => dispatchProps.downloadListPdf(stateProps.authentication.token, myListId, listName)),\r\n addMyListToOrder: myAddMyListToOrder((myList) => dispatchProps.addMyListToOrder(myList, stateProps.activeOrder)),\r\n});\r\n\r\nexport default connect(mapStateToProps, mapDispatchToProps, mergeProps)(MyListPage);","import \"../../../../styles/page/order.scss\";\r\n\r\nimport { TitleTab, TitleTabs } from \"../../../common/components/TitleTabs\";\r\n\r\nimport AllProductPage from \"../product/AllProductPage\";\r\nimport CounterField from \"../../../common/components/CounterField\";\r\nimport {Localization} from \"../../../common/util/localization.jsx\";\r\nimport ProductPage from \"../product/ProductPage\";\r\nimport PropTypes from \"prop-types\";\r\nimport React from \"react\";\r\nimport ShoppingCart from \"./ShoppingCart\";\r\nimport {scssVariables} from \"../../../common/util/config\";\r\nimport {withRouter} from \"react-router-dom\";\r\n\r\nclass OrderProductsPage extends React.PureComponent {\r\n constructor(props){\r\n super(props);\r\n\r\n this.state = {\r\n view: this.props.startView,\r\n };\r\n\r\n this.onClickSwapPage = this.onClickSwapPage.bind(this);\r\n this.calculateShoppingCartHeight = this.calculateShoppingCartHeight.bind(this);\r\n }\r\n\r\n UNSAFE_componentWillMount() {\r\n const {\r\n initiateCurrentOrder,\r\n activeOrder,\r\n clearQuery,\r\n prepareQueryOptions,\r\n getBoughtProducts,\r\n getNewProducts,\r\n getOrderFeeLimits,\r\n getOrderVolumeDiscounts,\r\n } = this.props;\r\n\r\n if( activeOrder && activeOrder.loading==false) {\r\n initiateCurrentOrder();\r\n }\r\n clearQuery();\r\n prepareQueryOptions();\r\n getBoughtProducts();\r\n getNewProducts();\r\n getOrderFeeLimits();\r\n getOrderVolumeDiscounts();\r\n }\r\n\r\n UNSAFE_componentWillReceiveProps(nextProps) {\r\n if( this.state.view !== nextProps.startView) {\r\n this.setState({\r\n view: !nextProps.startView || nextProps.startView===\"\" ? \"card\" : nextProps.startView,\r\n });\r\n }\r\n }\r\n\r\n onClickSwapPage(event, view) {\r\n this.props.history.push(`/order/products/${view?view:\"\"}`);\r\n }\r\n\r\n calculateShoppingCartHeight() {\r\n const {\r\n deviceType,\r\n height,\r\n } = this.props;\r\n let productDisplayHeight = height;\r\n \r\n //page padding\r\n productDisplayHeight -= parseInt(scssVariables[`${deviceType}ContentPadding`])*2;\r\n //product display margin\r\n productDisplayHeight -= parseInt(scssVariables.cardMargin)*2;\r\n\r\n return productDisplayHeight;\r\n }\r\n\r\n render(){\r\n const {\r\n clearQuery,\r\n deviceType,\r\n localization,\r\n setOrderProductView,\r\n productView,\r\n activeOrder,\r\n addRemoveProductToTemporaryOrder,\r\n height,\r\n width,\r\n loadMoreSearchedProducts,\r\n productQuery,\r\n submitOrder,\r\n deliveryDates,\r\n setActiveOrder,\r\n productLists,\r\n moveUnconfirmedLinesToNextOrder,\r\n editQueryFilter,\r\n flowControl,\r\n setModal,\r\n setDropDown,\r\n orderFeeLimits,\r\n orderVolumeDiscounts,\r\n newSeasonDistrDates,\r\n showFreshFood,\r\n } = this.props;\r\n const shoppingCartHeight = this.calculateShoppingCartHeight();\r\n\r\n return this.state.view==\"card\" ? (\r\n }\r\n titleTabs={\r\n \r\n \r\n \r\n { showFreshFood && (\r\n \r\n )} \r\n }\r\n cart={}\r\n />\r\n ) : (\r\n }\r\n titleTabs={\r\n \r\n \r\n \r\n { showFreshFood && (\r\n \r\n )} \r\n }\r\n cart={}\r\n />\r\n );\r\n }\r\n}\r\n\r\nOrderProductsPage.propTypes = {\r\n //Required\r\n deviceType: PropTypes.string.isRequired,\r\n localization: Localization.propTypes.isRequired,\r\n setOrderProductView: PropTypes.func.isRequired,\r\n productView: PropTypes.object.isRequired,\r\n activeOrder: PropTypes.object.isRequired,\r\n addRemoveProductToTemporaryOrder: PropTypes.func.isRequired,\r\n editQueryFilter: PropTypes.func.isRequired,\r\n clearQuery: PropTypes.func.isRequired,\r\n height: PropTypes.number.isRequired,\r\n width: PropTypes.number.isRequired,\r\n loadMoreSearchedProducts: PropTypes.func.isRequired,\r\n productQuery: PropTypes.object.isRequired,\r\n deliveryDates: PropTypes.array.isRequired,\r\n setActiveOrder: PropTypes.func.isRequired,\r\n productLists: PropTypes.object.isRequired,\r\n startView: PropTypes.string.isRequired,\r\n submitOrder: PropTypes.func.isRequired,\r\n initiateCurrentOrder: PropTypes.func.isRequired,\r\n history: PropTypes.object.isRequired,\r\n moveUnconfirmedLinesToNextOrder: PropTypes.func.isRequired,\r\n flowControl: PropTypes.func.isRequired,\r\n setModal: PropTypes.func.isRequired,\r\n setDropDown: PropTypes.func.isRequired,\r\n prepareQueryOptions: PropTypes.func.isRequired,\r\n getBoughtProducts: PropTypes.func.isRequired,\r\n getNewProducts: PropTypes.func.isRequired,\r\n getOrderFeeLimits: PropTypes.func.isRequired,\r\n orderFeeLimits: PropTypes.array.isRequired,\r\n getOrderVolumeDiscounts: PropTypes.func.isRequired,\r\n orderVolumeDiscounts: PropTypes.array.isRequired,\r\n newSeasonDistrDates: PropTypes.array.isRequired,\r\n showFreshFood: PropTypes.bool.isRequired,\r\n};\r\n\r\nexport default withRouter(OrderProductsPage);","import {addRemoveProductToTemporaryOrder, getOrderFeeLimits, getOrderVolumeDiscounts, moveUnconfirmedLinesToNextOrder, setActiveOrder, submitOrder} from \"../actions/order.js\";\r\nimport {clearQuery, editQueryFilter, loadMoreSearchedProducts, prepareQueryOptions} from \"../actions/productQuery.js\";\r\nimport {getBoughtProducts, getNewProducts} from \"../actions/productLists.js\";\r\nimport {setDropDown, setModal} from \"../../common/actions/modal\";\r\n\r\nimport OrderProductsPage from \"../components/order/OrderProductsPage.jsx\";\r\nimport {connect} from \"react-redux\";\r\nimport {createBoundFunction} from \"../../common/util/reselect.js\";\r\nimport {createFlowControl} from \"../../common/util/flowControl\";\r\nimport {createLocalization} from \"../../common/util/localization.jsx\";\r\nimport {initiateCurrentOrder} from \"../actions/worker.js\";\r\nimport {scssVariables} from \"../../common/util/config.jsx\";\r\nimport {setOrderProductView} from \"../actions/order.js\";\r\n\r\nconst mapStateToProps = () => {\r\n const flowControl = createFlowControl();\r\n const flowControlCounter = createFlowControl();\r\n\r\n return (state, ownProps) => ({\r\n startView: ownProps.match.params.view || \"card\",\r\n localization: createLocalization(state),\r\n productView: state.order.productView,\r\n deviceType: state.view.deviceType,\r\n productQuery: state.productQuery,\r\n flowControl: flowControl,\r\n flowControlCounter: flowControlCounter,\r\n activeOrder: state.order.active,\r\n productImage: state.productImage,\r\n width: state.view.innerWidth,\r\n deliveryDates: state.delivery.dates.deliveryDates || [],\r\n height: state.view.innerHeight-parseInt(scssVariables.menuHeight),\r\n productLists: state.productLists,\r\n orderFeeLimits: state.order.orderFeeLimits,\r\n orderVolumeDiscounts: state.order.orderVolumeDiscounts,\r\n newSeasonDistrDates : state.authentication.newSeasonDistrDates || [],\r\n showFreshFood: state.authentication.showFreshFood,\r\n });\r\n};\r\n\r\nconst mapDispatchToProps = {\r\n setOrderProductView,\r\n loadMoreSearchedProducts,\r\n editQueryFilter,\r\n clearQuery,\r\n addRemoveProductToTemporaryOrder,\r\n submitOrder,\r\n setActiveOrder,\r\n initiateCurrentOrder,\r\n moveUnconfirmedLinesToNextOrder,\r\n setModal,\r\n setDropDown,\r\n prepareQueryOptions,\r\n getBoughtProducts,\r\n getNewProducts,\r\n getOrderFeeLimits,\r\n getOrderVolumeDiscounts,\r\n};\r\n\r\nconst myAddRemoveProductToTemporaryOrder = createBoundFunction();\r\nconst myLoadMoreSearchedProducts = createBoundFunction();\r\nconst myEditQueryFilter = createBoundFunction();\r\nconst mySubmitOrder = createBoundFunction();\r\nconst mySetActiveOrder = createBoundFunction();\r\n\r\nconst mergeProps = (stateProps, dispatchProps, ownProps) => ({\r\n ...stateProps,\r\n ...dispatchProps,\r\n ...ownProps,\r\n addRemoveProductToTemporaryOrder: myAddRemoveProductToTemporaryOrder((product, qty, salesLineId) => dispatchProps.addRemoveProductToTemporaryOrder(stateProps.activeOrder, product, qty, salesLineId)),\r\n loadMoreSearchedProducts: myLoadMoreSearchedProducts((noOfProducts) => dispatchProps.loadMoreSearchedProducts(stateProps.productQuery, stateProps.productImage, noOfProducts)),\r\n submitOrder: mySubmitOrder(() => dispatchProps.submitOrder(stateProps.activeOrder)),\r\n setActiveOrder: mySetActiveOrder((shipmentId, distributionRouteId, deliveryDate, waitForReservation) => dispatchProps.setActiveOrder(shipmentId, distributionRouteId, deliveryDate, waitForReservation)),\r\n editQueryFilter: myEditQueryFilter( (change) => dispatchProps.editQueryFilter(stateProps.productQuery, stateProps.productImage, change, \r\n myLoadMoreSearchedProducts((noOfProducts) => dispatchProps.loadMoreSearchedProducts(stateProps.productQuery, stateProps.productImage, noOfProducts))\r\n )),\r\n});\r\n\r\nexport default connect(mapStateToProps, mapDispatchToProps, mergeProps)(OrderProductsPage);","import ContentWrapper from \"./ContentWrapper.jsx\";\r\nimport React from \"react\";\r\n\r\nclass Page404 extends React.PureComponent {\r\n render(){\r\n return (\r\n \r\n \r\n Side ikke funnet 404\r\n
\r\n \r\n );\r\n }\r\n}\r\n\r\nexport default Page404;","import \"../../../styles/kjedeweb/singleChainProductListItem.scss\";\r\n\r\nimport CheckBox from \"../../common/components/CheckBox\";\r\nimport FuturePriceItem from \"./FuturePriceComponent.jsx\";\r\nimport { Localization } from \"../../common/util/localization.jsx\";\r\nimport PropTypes from \"prop-types\";\r\nimport React from \"react\";\r\nimport ResponsiveColumn from \"../../common/components/ResponsiveColumn\";\r\nimport ResponsiveRows from \"../../common/components/ResponsiveRows\";\r\nimport SingleChainProductModal from \"./SingleChainProductModal\";\r\nimport moment from \"moment\";\r\nimport { toLocaleFixed } from \"../../common/util/localization.jsx\";\r\n\r\nexport class SingleChainSortimentListHeader extends React.PureComponent {\r\n render() {\r\n const {\r\n localization,\r\n multiSelect,\r\n showInvoiceGroup,\r\n } = this.props;\r\n\r\n return (\r\n \r\n
\r\n {multiSelect && (\r\n
\r\n )}\r\n
\r\n
\r\n \r\n \r\n {localization.text(\"chain\", \"chainSortiment\", \"productAndStatus\")}\r\n
\r\n \r\n \r\n \r\n {localization.text(\"chain\", \"chainSortiment\", \"productStatus\")}\r\n
\r\n \r\n \r\n \r\n {localization.text(\"chain\", \"chainSortiment\", \"noOfSalesUnits\")}\r\n
\r\n \r\n \r\n \r\n {localization.text(\"chain\", \"chainSortiment\", \"netPrice\")}\r\n
\r\n \r\n \r\n \r\n {localization.text(\"chain\", \"chainSortiment\", \"netPricePerUnit\")}\r\n
\r\n \r\n \r\n \r\n {localization.text(\"chain\", \"chainSortiment\", \"adminChargePercent\")}\r\n
\r\n \r\n \r\n \r\n {localization.text(\"chain\", \"chainSortiment\", \"changed\")}\r\n
\r\n \r\n {showInvoiceGroup && (\r\n \r\n \r\n {localization.text(\"chain\", \"chainSortiment\", \"invoiceGroup\")}\r\n
\r\n \r\n )}\r\n \r\n
\r\n
\r\n
\r\n );\r\n }\r\n}\r\n\r\nSingleChainSortimentListHeader.propTypes = {\r\n localization: Localization.propTypes.isRequired,\r\n multiSelect: PropTypes.bool,\r\n showInvoiceGroup : PropTypes.bool,\r\n};\r\n\r\nexport class SingleChainSortimentListItem extends React.PureComponent {\r\n constructor(props) {\r\n super(props);\r\n\r\n this.showProductModal = this.showProductModal.bind(this);\r\n this.closeProductModal = this.closeProductModal.bind(this);\r\n this.onClickSelect = this.onClickSelect.bind(this);\r\n }\r\n\r\n onClickSelect(change) {\r\n this.props.editSelectedProduct({\r\n [this.props.product.productId]: change[this.props.product.productId] ? this.props.product : undefined,\r\n });\r\n }\r\n\r\n showProductModal(event) {\r\n event.stopPropagation();\r\n event.preventDefault();\r\n\r\n const {\r\n localization,\r\n product,\r\n } = this.props;\r\n\r\n const title = localization.text(\"chain\", \"productDetail\");\r\n const saveButtonText = localization.text(\"chain\", \"save\");\r\n this.props.setModal();\r\n }\r\n\r\n closeProductModal(event) {\r\n event.stopPropagation();\r\n event.preventDefault();\r\n\r\n this.props.setModal(null);\r\n this.props.clearChainProductDetails();\r\n }\r\n\r\n capitalizeFirstLetter(s) {\r\n s = s.toLowerCase();\r\n return s.charAt(0).toUpperCase() + s.slice(1);\r\n }\r\n\r\n render() {\r\n const {\r\n product,\r\n selected,\r\n multiSelect,\r\n } = this.props;\r\n\r\n return (\r\n \r\n
\r\n {multiSelect && (\r\n
\r\n \r\n
\r\n )}\r\n
\r\n
\r\n \r\n \r\n
\r\n {product.imageUrl && (\r\n
\r\n
\r\n \r\n )}\r\n
\r\n
\r\n
EPD {product.epdNo}
\r\n
{product.productName}
\r\n\r\n
\r\n
\r\n
{product.inCatalogue ? \"Åpen\" : \"Stengt\"}\r\n
\r\n {/*
\r\n {product.inCatalogue && (
)}\r\n {product.inCatalogue ? \"I varekatalog\" : \"Ikke i varekatalog\"}\r\n
*/} \r\n
\r\n
\r\n
\r\n \r\n \r\n
\r\n \r\n
\r\n {product.status}\r\n
\r\n
\r\n \r\n
\r\n \r\n
\r\n {product.noOfSalesUnits}\r\n
\r\n
\r\n \r\n
\r\n \r\n
\r\n {toLocaleFixed(product.currentNetPrice,2)}\r\n
\r\n
\r\n \r\n
\r\n \r\n
\r\n {toLocaleFixed(product.currentNetPricePerSalesUnit,3)}\r\n
\r\n
\r\n \r\n
\r\n \r\n \r\n
\r\n \r\n
\r\n {product.lastChangedDate && moment(product.lastChangedDate).format(\"DD.MM.YY\")}\r\n
\r\n
\r\n \r\n {product.showInvoiceGroup && (\r\n
\r\n \r\n
\r\n {this.capitalizeFirstLetter(product.invoiceGroupName)}\r\n
\r\n
\r\n \r\n )}\r\n \r\n
\r\n \r\n
\r\n );\r\n }\r\n}\r\n\r\nSingleChainSortimentListItem.propTypes = {\r\n clearChainProductDetails: PropTypes.func.isRequired,\r\n localization: Localization.propTypes.isRequired,\r\n product: PropTypes.object,\r\n setModal: PropTypes.func.isRequired,\r\n selected: PropTypes.object.isRequired,\r\n editSelectedProduct: PropTypes.func.isRequired,\r\n multiSelect: PropTypes.bool.isRequired,\r\n};\r\n\r\nSingleChainSortimentListItem.defaultProps = {\r\n};","import \"../../../styles/productView.scss\";\r\nimport \"../../../styles/productViewListItem.scss\";\r\n\r\nimport Loading, { loadingTypes } from \"../../common/components/Loading\";\r\nimport { SingleChainSortimentListHeader, SingleChainSortimentListItem } from \"./SingleChainSortimentListItem.jsx\";\r\n\r\nimport ChainScroll from \"./ChainScroll\";\r\nimport { Localization } from \"../../common/util/localization.jsx\";\r\nimport PropTypes from \"prop-types\";\r\nimport React from \"react\";\r\n\r\nclass SingleChainSortimentList extends React.PureComponent {\r\n constructor(props) {\r\n super(props);\r\n\r\n this.state = {\r\n width: null,\r\n };\r\n this.containerNode = null;\r\n\r\n this.trackScrolling = this.trackScrolling.bind(this);\r\n this.prepareItems = this.prepareItems.bind(this);\r\n }\r\n\r\n trackScrolling() {\r\n const {\r\n isLoading,\r\n loadMoreProducts,\r\n } = this.props;\r\n\r\n //load more products if none is loading\r\n if (isLoading === false && loadMoreProducts) {\r\n loadMoreProducts(50);\r\n }\r\n }\r\n\r\n prepareItems() {\r\n const {\r\n clearChainProductDetails,\r\n deviceType,\r\n list,\r\n localization,\r\n isLoading,\r\n setModal,\r\n multiSelect,\r\n editSelectedProduct,\r\n selected,\r\n } = this.props;\r\n\r\n const retNodes = [];\r\n\r\n for (let i = 0; i < list.length; i++) {\r\n retNodes[retNodes.length] = (\r\n
);\r\n }\r\n if (isLoading) {\r\n retNodes[retNodes.length] =\r\n retNodes[retNodes.length] =\r\n
;\r\n }\r\n return retNodes;\r\n }\r\n\r\n render() {\r\n const {\r\n deviceType,\r\n localization,\r\n height,\r\n style,\r\n multiSelect,\r\n list,\r\n } = this.props;\r\n\r\n const nodes = this.prepareItems();\r\n\r\n const showInvoiceGroup = list.some(li => li.product.showInvoiceGroup);\r\n\r\n return (\r\n
\r\n \r\n \r\n
\r\n \r\n {nodes}\r\n \r\n \r\n );\r\n }\r\n}\r\n\r\nSingleChainSortimentList.propTypes = {\r\n clearChainProductDetails: PropTypes.func.isRequired,\r\n deviceType: PropTypes.string.isRequired,\r\n height: PropTypes.number,\r\n // If true a loading icon will be displayed\r\n isLoading: PropTypes.bool,\r\n // An array of products to be displayed\r\n list: PropTypes.array.isRequired,\r\n // A function that will load in more items into list\r\n loadMoreProducts: PropTypes.func,\r\n localization: Localization.propTypes.isRequired,\r\n setModal: PropTypes.func.isRequired,\r\n style: PropTypes.object,\r\n // If more then one product can be selected\r\n multiSelect: PropTypes.bool.isRequired,\r\n editSelectedProduct: PropTypes.func.isRequired,\r\n selected: PropTypes.object.isRequired,\r\n};\r\n\r\nexport default SingleChainSortimentList;\r\n","import { ChainTab, ChainTabList, ChainTabPanel, ChainTabs } from \"./ChainTabs.jsx\";\r\nimport Icon, { iconTypes } from \"../../common/components/Icon.jsx\";\r\nimport { SubMenu, SubMenuItem } from \"../../common/components/SubMenu.jsx\";\r\n\r\nimport { Localization } from \"../../common/util/localization.jsx\";\r\nimport MultiProductModal from \"./MultiProductModal.jsx\";\r\nimport PropTypes from \"prop-types\";\r\nimport React from \"react\";\r\nimport SingleChainSortimentList from \"./SingleChainSortimentList.jsx\";\r\nimport { scssVariables } from \"../../common/util/config.jsx\";\r\nimport { withRouter } from \"react-router-dom\";\r\n\r\nclass SingleChainSortimentCard extends React.PureComponent {\r\n constructor(props) {\r\n super(props);\r\n\r\n this.state = {\r\n multiSelectOn: false,\r\n };\r\n\r\n this.swallowOnClick = this.swallowOnClick.bind(this);\r\n this.onTabAllClicked = this.onTabAllClicked.bind(this);\r\n this.onTabNewClicked = this.onTabNewClicked.bind(this);\r\n this.onMultiSelectClick = this.onMultiSelectClick.bind(this);\r\n this.onEditMultiSelect = this.onEditMultiSelect.bind(this);\r\n this.calculateInternalPanelHeight = this.calculateInternalPanelHeight.bind(this);\r\n this.closeProductModal = this.closeProductModal.bind(this);\r\n this.onExportCsv = this.onExportCsv.bind(this);\r\n }\r\n\r\n closeProductModal(event) {\r\n event.stopPropagation();\r\n event.preventDefault();\r\n\r\n this.props.setModal(null);\r\n this.props.clearChainProductDetails();\r\n }\r\n\r\n onTabAllClicked() {\r\n const path = this.props.location.pathname;\r\n //replace only whats after the last / with the new path\r\n this.props.history.replace(`${path.substr(0, path.lastIndexOf(\"/\"))}/all`);\r\n this.props.editSingleChainFilter({\r\n onlyNews: false,\r\n });\r\n }\r\n\r\n onTabNewClicked() {\r\n const path = this.props.location.pathname;\r\n //replace only whats after the last / with the new path\r\n this.props.history.replace(`${path.substr(0, path.lastIndexOf(\"/\"))}/new`);\r\n this.props.editSingleChainFilter({\r\n onlyNews: true,\r\n });\r\n }\r\n\r\n onMultiSelectClick() {\r\n if( this.state.multiSelectOn ){\r\n this.props.clearSelectedProducts();\r\n }\r\n this.setState({\r\n multiSelectOn: !this.state.multiSelectOn,\r\n });\r\n }\r\n\r\n onEditMultiSelect() {\r\n const {\r\n localization,\r\n singleChainSortiment,\r\n } = this.props;\r\n\r\n const title = localization.text(\"chain\", \"productDetail\");\r\n const saveButtonText = localization.text(\"chain\", \"save\");\r\n this.props.setModal(
);\r\n }\r\n\r\n swallowOnClick(event) {\r\n event.stopPropagation();\r\n event.preventDefault();\r\n }\r\n\r\n onExportCsv() {\r\n const {\r\n singleChainSortiment,\r\n exportCsv,\r\n } = this.props;\r\n\r\n exportCsv(singleChainSortiment);\r\n }\r\n\r\n\r\n calculateInternalPanelHeight() {\r\n let tabPanelHeight = this.props.height;\r\n\r\n // Remove height of tab panel\r\n tabPanelHeight -= parseInt(scssVariables.menuHeightWithBorder);\r\n return tabPanelHeight;\r\n }\r\n\r\n render() {\r\n const {\r\n clearChainProductDetails,\r\n currentView,\r\n deviceType,\r\n height,\r\n loadMoreSearchResults,\r\n localization,\r\n setModal,\r\n singleChainSortiment,\r\n width,\r\n editSelectedProduct,\r\n } = this.props;\r\n const tabPanelHeight = this.calculateInternalPanelHeight();\r\n let anyProductsSelected = false;\r\n for(const key in singleChainSortiment.selected) {\r\n if( singleChainSortiment.selected.hasOwnProperty(key) && singleChainSortiment.selected[key] ){\r\n anyProductsSelected = true;\r\n break;\r\n }\r\n }\r\n\r\n return (\r\n
\r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n {anyProductsSelected && (\r\n \r\n \r\n \r\n {localization.text(\"chain\", \"editSelected\")}\r\n
\r\n \r\n )}\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n );\r\n }\r\n}\r\n\r\nSingleChainSortimentCard.propTypes = {\r\n clearChainProductDetails: PropTypes.func.isRequired,\r\n currentView: PropTypes.string,\r\n deviceType: PropTypes.string.isRequired,\r\n editSingleChainFilter: PropTypes.func.isRequired,\r\n height: PropTypes.number.isRequired,\r\n history: PropTypes.object.isRequired,\r\n loadMoreSearchResults: PropTypes.func.isRequired,\r\n localization: Localization.propTypes.isRequired,\r\n location: PropTypes.object.isRequired,\r\n setModal: PropTypes.func.isRequired,\r\n singleChainSortiment: PropTypes.object.isRequired,\r\n width: PropTypes.number.isRequired,\r\n editSelectedProduct: PropTypes.func.isRequired,\r\n clearSelectedProducts: PropTypes.func.isRequired,\r\n exportCsv : PropTypes.func.isRequired,\r\n};\r\n\r\nSingleChainSortimentCard.defaultProps = {\r\n currentView: \"all\",\r\n};\r\nexport default withRouter(SingleChainSortimentCard);\r\n","import \"../../../styles/page/order.scss\";\r\n\r\nimport { TitleTab, TitleTabs } from \"../../common/components/TitleTabs.jsx\";\r\n\r\nimport ContentWrapper from \"../../common/components/ContentWrapper\";\r\nimport { Localization } from \"../../common/util/localization.jsx\";\r\nimport PropTypes from \"prop-types\";\r\nimport React from \"react\";\r\nimport SingleChainSearchBar from \"./SingleChainSearchBar.jsx\";\r\nimport SingleChainSortimentCard from \"./SingleChainSortimentCard.jsx\";\r\nimport { scssVariables } from \"../../common/util/config.jsx\";\r\nimport { withRouter } from \"react-router-dom\";\r\n\r\nclass SingleChainPage extends React.PureComponent {\r\n constructor(props) {\r\n super(props);\r\n\r\n this.calculateProductDisplayHeight = this.calculateProductDisplayHeight.bind(this);\r\n this.calculateProductDisplayWidth = this.calculateProductDisplayWidth.bind(this);\r\n this.loadMoreSearchResults = this.loadMoreSearchResults.bind(this);\r\n this.onEditFilter = this.onEditFilter.bind(this);\r\n }\r\n\r\n UNSAFE_componentWillMount() {\r\n const {\r\n clearSingleChainSortiment,\r\n prepareQueryOptions,\r\n getInvoiceGroups,\r\n } = this.props;\r\n\r\n clearSingleChainSortiment();\r\n prepareQueryOptions();\r\n getInvoiceGroups();\r\n }\r\n\r\n calculateProductDisplayHeight() {\r\n const {\r\n deviceType,\r\n height,\r\n } = this.props;\r\n let productDisplayHeight = height;\r\n\r\n // Page padding\r\n productDisplayHeight -= parseInt(scssVariables[`${deviceType}ContentPadding`]) * 2;\r\n\r\n if (deviceType === \"xs\") {\r\n productDisplayHeight -= parseInt(scssVariables.menuHeightWithBorder);\r\n } else {\r\n // Title tab height\r\n productDisplayHeight -= parseInt(scssVariables.cardMargin) * 2;\r\n productDisplayHeight -= parseInt(scssVariables.titleTabHeight);\r\n\r\n // Search bar height\r\n productDisplayHeight -= parseInt(scssVariables.cardMargin) * 2;\r\n productDisplayHeight -= parseInt(scssVariables.menuHeightWithBorder);\r\n }\r\n\r\n // Product display padding\r\n productDisplayHeight -= parseInt(scssVariables.cardMargin) * 2;\r\n\r\n return productDisplayHeight;\r\n }\r\n\r\n calculateProductDisplayWidth() {\r\n const {\r\n deviceType,\r\n width,\r\n } = this.props;\r\n\r\n let productDisplayWidth = width;\r\n if (deviceType === \"xs\") {\r\n // Page padding\r\n productDisplayWidth -= parseInt(scssVariables[`${deviceType}ContentPadding`]) * 2;\r\n\r\n // Product display padding\r\n productDisplayWidth -= parseInt(scssVariables.cardMargin) * 2;\r\n } else {\r\n // Page padding\r\n productDisplayWidth -= parseInt(scssVariables[`${deviceType}ContentPadding`]); // No padding on the right side(Attached to it)\r\n\r\n // Product display padding\r\n productDisplayWidth -= parseInt(scssVariables.cardMargin) * 2;\r\n }\r\n\r\n return productDisplayWidth;\r\n }\r\n\r\n onEditFilter(...args) {\r\n const {\r\n editSingleChainFilter,\r\n flowControl,\r\n } = this.props;\r\n flowControl(async () => {\r\n await editSingleChainFilter(...args);\r\n });\r\n }\r\n\r\n loadMoreSearchResults() {\r\n const {\r\n deviceType,\r\n loadMoreSingleChainSortiment,\r\n } = this.props;\r\n const productDisplayHeight = this.calculateProductDisplayHeight();\r\n const rowsToLoad = (Math.floor(productDisplayHeight / parseInt(scssVariables.productItemHeight)) + 2);\r\n // rowsToLoad * itemsPerRow\r\n switch (deviceType) {\r\n case \"xs\":\r\n case \"sm\":\r\n this.props.flowControl(async () => { await loadMoreSingleChainSortiment(rowsToLoad * 2); });\r\n break;\r\n case \"md\":\r\n this.props.flowControl(async () => { await loadMoreSingleChainSortiment(rowsToLoad * 4); });\r\n break;\r\n case \"lg\":\r\n this.props.flowControl(async () => { await loadMoreSingleChainSortiment(rowsToLoad * 6); });\r\n break;\r\n default:\r\n this.props.flowControl(async () => { await loadMoreSingleChainSortiment(rowsToLoad * 8); });\r\n break;\r\n }\r\n }\r\n\r\n render() {\r\n const {\r\n clearChainProductDetails,\r\n deviceType,\r\n editSingleChainFilter,\r\n height,\r\n localization,\r\n setModal,\r\n setDropDown,\r\n singleChainSortiment,\r\n editSelectedProduct,\r\n clearSelectedProducts,\r\n exportCsv,\r\n } = this.props;\r\n\r\n const productDisplayHeight = this.calculateProductDisplayHeight();\r\n const productDisplayWidth = this.calculateProductDisplayWidth();\r\n\r\n const filter = {\r\n onlyNews: this.props.startView === \"new\",\r\n productGroupId: null,\r\n supplierId: null,\r\n };\r\n\r\n return (\r\n
\r\n \r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n
\r\n );\r\n }\r\n}\r\n\r\nSingleChainPage.propTypes = {\r\n clearChainProductDetails: PropTypes.func.isRequired,\r\n clearSingleChainSortiment: PropTypes.func.isRequired,\r\n deviceType: PropTypes.string.isRequired,\r\n editSingleChainFilter: PropTypes.func.isRequired,\r\n flowControl: PropTypes.func.isRequired,\r\n height: PropTypes.number.isRequired,\r\n loadMoreSingleChainSortiment: PropTypes.func.isRequired,\r\n localization: Localization.propTypes.isRequired,\r\n prepareQueryOptions: PropTypes.func.isRequired,\r\n setModal: PropTypes.func.isRequired,\r\n setDropDown: PropTypes.func.isRequired,\r\n singleChainSortiment: PropTypes.object.isRequired,\r\n startView: PropTypes.string.isRequired,\r\n width: PropTypes.number.isRequired,\r\n editSelectedProduct: PropTypes.func.isRequired,\r\n clearSelectedProducts: PropTypes.func.isRequired,\r\n getInvoiceGroups: PropTypes.func.isRequired,\r\n exportCsv: PropTypes.func.isRequired,\r\n};\r\n\r\nexport default withRouter(SingleChainPage);\r\n","import { clearChainProductDetails, clearSelectedProducts, clearSingleChainSortiment, editSelectedProduct, editSingleChainFilter, getInvoiceGroups, loadMoreSingleChainSortiment, prepareQueryOptions, updateChainProducts } from \"../actions/singleChainSortiment\";\r\nimport { setDropDown, setModal } from \"../../common/actions/modal\";\r\n\r\nimport SingleChainPage from \"../components/SingleChainPage.jsx\";\r\nimport { connect } from \"react-redux\";\r\nimport { createBoundFunction } from \"../../common/util/reselect.js\";\r\nimport { createFlowControl } from \"../../common/util/flowControl\";\r\nimport { createLocalization } from \"../../common/util/localization.jsx\";\r\nimport { exportCsv } from \"../actions/multiChainSortiment\";\r\n\r\nimport { scssVariables } from \"../../common/util/config.jsx\";\r\n\r\nconst mapStateToProps = () => {\r\n const flowControl = createFlowControl();\r\n const flowControlCounter = createFlowControl();\r\n\r\n return (state, ownProps) => ({\r\n deviceType: state.view.deviceType,\r\n flowControl: flowControl,\r\n flowControlCounter: flowControlCounter,\r\n height: state.view.innerHeight - parseInt(scssVariables.menuHeight),\r\n localization: createLocalization(state),\r\n singleChainSortiment: state.singleChainSortiment,\r\n startView: ownProps.match.params.view || \"all\",\r\n width: state.view.innerWidth,\r\n });\r\n};\r\n\r\nconst mapDispatchToProps = {\r\n clearChainProductDetails,\r\n clearSingleChainSortiment,\r\n editSingleChainFilter,\r\n loadMoreSingleChainSortiment,\r\n prepareQueryOptions,\r\n setModal,\r\n setDropDown,\r\n updateChainProducts,\r\n editSelectedProduct,\r\n clearSelectedProducts,\r\n getInvoiceGroups,\r\n exportCsv,\r\n};\r\n\r\nconst myLoadMoreSingleChainSortiment = createBoundFunction();\r\nconst myEditSingleChainFilter = createBoundFunction();\r\n\r\nconst mergeProps = (stateProps, dispatchProps, ownProps) => ({\r\n ...stateProps,\r\n ...dispatchProps,\r\n ...ownProps,\r\n loadMoreSingleChainSortiment: myLoadMoreSingleChainSortiment((noOfProducts) => dispatchProps.loadMoreSingleChainSortiment(stateProps.singleChainSortiment, stateProps.productImage, noOfProducts)),\r\n editSingleChainFilter: myEditSingleChainFilter((change) => dispatchProps.editSingleChainFilter(change,\r\n myLoadMoreSingleChainSortiment((noOfProducts) => dispatchProps.loadMoreSingleChainSortiment(stateProps.singleChainSortiment, stateProps.productImage, noOfProducts))\r\n )),\r\n});\r\n\r\nexport default connect(mapStateToProps, mapDispatchToProps, mergeProps)(SingleChainPage);\r\n","import { getApi, getEncodedSearchString, postApi } from \"../../common/actions/net.js\";\r\nimport { getExistingProductImage, loadProductImage } from \"../../kundeweb/actions/productImage.js\";\r\nimport { messageType, pushSystemMessage } from \"../../common/actions/systemMessage.js\";\r\nimport Logger from \"../../common/util/Logger.js\";\r\n\r\nexport const SET_SINGLE_EPIX_SORTIMENT = \"SET_SINGLE_EPIX_SORTIMENT\";\r\nexport const ADD_SINGLE_EPIX_SORTIMENT = \"ADD_SINGLE_EPIX_SORTIMENT\";\r\nexport const SET_QUERY_PRODUCT_IMAGE_URL = \"SET_QUERY_PRODUCT_IMAGE_URL\";\r\nexport const SINGLE_EPIX_SORTIMENT_IS_LOADING = \"SINGLE_EPIX_SORTIMENT_IS_LOADING\";\r\nexport const SINGLE_EPIX_QUERY_DONE_LOADING = \"SINGLE_EPIX_QUERY_DONE_LOADING\";\r\nexport const SINGLE_EPIX_QUERY_FAILED_LOADING = \"SINGLE_EPIX_QUERY_DONE_LOADING\";\r\nexport const SINGLE_EPIX_QUERY_ALL_LOADED = \"SINGLE_EPIX_QUERY_ALL_LOADED\";\r\nexport const EDIT_SINGLE_EPIX_FILTER = \"EDIT_SINGLE_EPIX_FILTER\";\r\nexport const CLEAR_SINGLE_EPIX_SORTIMENT = \"CLEAR_SINGLE_EPIX_SORTIMENT\";\r\nexport const SET_SINGLE_EPIX_SORTIMENT_FILTER = \"SET_SINGLE_EPIX_SORTIMENT_FILTER\";\r\n\r\nexport const SET_SINGLE_EPIX_PRODUCT_DETAIL = \"SET_SINGLE_EPIX_PRODUCT_DETAIL\";\r\nexport const CLEAR_SINGLE_EPIX_PRODUCT_DETAIL = \"CLEAR_SINGLE_EPIX_PRODUCT_DETAIL\";\r\nexport const UPDATE_SINGLE_EPIX_PRODUCT_LIST = \"UPDATE_SINGLE_EPIX_PRODUCT_LIST\";\r\nexport const SET_INVOICE_GROUPS = \"SET_INVOICE_GROUPS\";\r\nexport const SET_QUERY_OPTION = \"SET_QUERY_OPTION\";\r\n\r\nconst setQueryProductImageUrl = (index, imageUrl) => ({\r\n type: SET_QUERY_PRODUCT_IMAGE_URL,\r\n index,\r\n imageUrl\r\n});\r\n\r\nconst setSingleEpixSortimentIsLoading = () => ({\r\n type: SINGLE_EPIX_SORTIMENT_IS_LOADING\r\n});\r\nconst setSingleEpixSortimentDoneLoading = () => ({\r\n type: SINGLE_EPIX_QUERY_DONE_LOADING\r\n});\r\nconst setSingleEpixSortimentFailedLoading = () => ({\r\n type: SINGLE_EPIX_QUERY_FAILED_LOADING\r\n});\r\n\r\nconst setSingleEpixSortimentAllLoaded = () => ({\r\n type: SINGLE_EPIX_QUERY_ALL_LOADED\r\n});\r\n\r\n/**\r\n * Downloads more single chain Epix sortiment items\r\n * @param {object} singleEpixSortiment\r\n * @param {object} productImage\r\n * @param {number} noOfProducts\r\n * @returns {func}\r\n */\r\nexport function loadMoreSingleEpixSortiment(singleEpixSortiment, productImage, noOfProducts = 50) {\r\n return async (dispatch, getState) => {\r\n try {\r\n //make sure there is something new to load\r\n if (singleEpixSortiment.allResultsLoaded) {\r\n return;\r\n }\r\n\r\n //start collection new lines\r\n dispatch(setSingleEpixSortimentIsLoading());\r\n\r\n const startIndex = singleEpixSortiment.allProducts.length;\r\n\r\n // Load in more products\r\n const { payload } = await dispatch(\r\n getApi(\"Chain/ProductsFreeTextQuery\", {\r\n chainType: getState().authentication.chainType,\r\n onlyAvailableForChain: false,\r\n noOfProducts: noOfProducts,\r\n startIndex: startIndex,\r\n freeText: getEncodedSearchString(singleEpixSortiment.chainFilter.searchString),\r\n supplierId: singleEpixSortiment.chainFilter.supplierId ? singleEpixSortiment.chainFilter.supplierId : undefined,\r\n productGroupId: singleEpixSortiment.chainFilter.productGroupId ? singleEpixSortiment.chainFilter.productGroupId : undefined,\r\n InvoiceGroup: singleEpixSortiment.chainFilter.invoiceGroupId ? singleEpixSortiment.chainFilter.invoiceGroupId : undefined,\r\n ProductStatus: singleEpixSortiment.chainFilter.productStatus >= 0 ? singleEpixSortiment.chainFilter.productStatus : undefined,\r\n onlyNews: singleEpixSortiment.chainFilter.onlyNews,\r\n })\r\n );\r\n\r\n // Check if all data has been loaded\r\n if (payload.products.length != noOfProducts) {\r\n dispatch(setSingleEpixSortimentAllLoaded());\r\n }\r\n\r\n // Insert existing images\r\n for (let i = 0; i < payload.products.length; i++) {\r\n payload.products[i].imageUrl = getExistingProductImage(payload.products[i].productId);\r\n }\r\n // Convert to default layout\r\n const prdList = payload.products.map(prd => {\r\n return { product: prd };\r\n });\r\n\r\n // Store query results\r\n await dispatch({ type: ADD_SINGLE_EPIX_SORTIMENT, allProducts: prdList });\r\n\r\n // Download all images not already inserted\r\n for (let index = 0; index < prdList.length; index++) {\r\n if (!prdList[index].product.imageUrl || prdList[index].product.imageUrl.length === 0) {\r\n const callback = imageUrl => dispatch(setQueryProductImageUrl(startIndex + index, imageUrl));\r\n dispatch(loadProductImage(productImage, prdList[index].product.productId, prdList[index].product.imageFileName, callback));\r\n }\r\n }\r\n\r\n dispatch(setSingleEpixSortimentDoneLoading());\r\n } catch (error) {\r\n dispatch(setSingleEpixSortimentFailedLoading());\r\n dispatch(pushSystemMessage(error && error.message || \"Søket mislyktes\", messageType.error));\r\n Logger.error(error);\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Changes the query filter\r\n * @param {object} change\r\n * @param {func} callback // function will be called when the state has been updated\r\n * @returns {func}\r\n */\r\nexport function editSingleEpixFilter(change, callback) {\r\n return async dispatch => {\r\n await dispatch({\r\n type: EDIT_SINGLE_EPIX_FILTER,\r\n change\r\n });\r\n\r\n try {\r\n dispatch(setSingleEpixSortimentIsLoading());\r\n await callback();\r\n } catch (error) {\r\n Logger.error(error);\r\n } finally {\r\n dispatch(setSingleEpixSortimentDoneLoading());\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Clears the single chain Epix sortiment\r\n * @returns {func}\r\n */\r\nexport function clearSingleEpixSortiment() {\r\n return async dispatch => {\r\n dispatch({\r\n type: CLEAR_SINGLE_EPIX_SORTIMENT\r\n });\r\n };\r\n}\r\n\r\n/**\r\n * Sets the single chain Epix sortiment filter \"OnlyAvailableForChain\" flag\r\n * @param {object} change\r\n * @returns {func}\r\n */\r\nexport function setSingleEpixSortimentFilter(change) {\r\n return async dispatch => {\r\n dispatch({\r\n type: SET_SINGLE_EPIX_SORTIMENT_FILTER,\r\n change\r\n });\r\n };\r\n}\r\n\r\n/**\r\n * Changes the query filter\r\n * @returns {func}\r\n */\r\nexport function prepareQueryOptions() {\r\n return async (dispatch, getState) => {\r\n const state = getState();\r\n const payload = await dispatch(getApi(\"Chain/FilterOptionsQuery\", {\r\n chainType: state.authentication.chainType}));\r\n dispatch({\r\n type: SET_QUERY_OPTION,\r\n productGroups: payload ? payload.payload.productGroups : null,\r\n productSuppliers: payload ? payload.payload.suppliers : null\r\n });\r\n };\r\n}\r\n\r\n/**\r\n * Gets product details for the given product id\r\n * @param {number} chainId\r\n * @param {string} productId\r\n * @param {string} imageUrl\r\n * @returns {function.
}\r\n */\r\nexport function getSingleEpixProductDetail(chainId, productId, imageUrl) {\r\n return async dispatch => {\r\n try {\r\n // Call webApi to make Products details request\r\n const { payload: productDetail } = await dispatch(getApi(\"Chain/ProductsDetailQuery\", { chainId, productId }));\r\n productDetail.imageUrl = imageUrl;\r\n\r\n dispatch({\r\n type: SET_SINGLE_EPIX_PRODUCT_DETAIL,\r\n productDetail\r\n });\r\n } catch (error) {\r\n dispatch(pushSystemMessage(error && error.message || \"Lasting av varedetaljer mislyktes\", messageType.error));\r\n Logger.error(error);\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Clears chain product detail modal\r\n * @returns {function.}\r\n */\r\nexport function clearEpixProductDetails() {\r\n return async dispatch => {\r\n try {\r\n dispatch({\r\n type: CLEAR_SINGLE_EPIX_PRODUCT_DETAIL\r\n });\r\n } catch (error) {\r\n Logger.error(error);\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Gets invoice groups\r\n * @returns {function.}\r\n */\r\nexport function getInvoiceGroups() {\r\n return async dispatch => {\r\n try {\r\n // Call webApi to get a list of invoice groups\r\n const { payload: invoiceGroups } = await dispatch(getApi(\"Chain/InvoiceGroupsQuery\"));\r\n\r\n dispatch({\r\n type: SET_INVOICE_GROUPS,\r\n invoiceGroups\r\n });\r\n } catch (error) {\r\n dispatch(pushSystemMessage(error && error.message || \"Lasting av fakturagruppe mislyktes\", messageType.error));\r\n Logger.error(error);\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Commit product changes\r\n * @param {number} chainType\r\n * @param {array} products\r\n * @returns {func}\r\n */\r\nexport function updateChainProducts(chainType, products) {\r\n return async dispatch => {\r\n try {\r\n // dispatch({\r\n // type: UPDATE_PRODUCTS,\r\n // committing: true,\r\n // });\r\n\r\n const payload = await dispatch(\r\n postApi(\"Chain/UpdateChainProductsCommand\", {\r\n chainType: chainType,\r\n productsToUpdate: products.map(p => {\r\n return {\r\n chainId: p.chainId,\r\n productId: p.productId,\r\n isAvailable: p.isAvailable,\r\n inCatalogue: p.inCatalogue,\r\n invoiceGroupId: p.invoiceGroupId,\r\n sortimentCode: p.sortimentCode,\r\n futureEndPrice: p.futureEndPrice,\r\n futureEndPriceDate: p.futureEndPriceDate,\r\n futureAdminCharge: p.futureAdminCharge,\r\n futureAdminChargeDate: p.futureAdminChargeDate\r\n };\r\n })\r\n })\r\n );\r\n\r\n if (payload && payload.message === \"OK\") {\r\n dispatch(pushSystemMessage(\"Varer ble oppdatert!\", messageType.message));\r\n // history.push(\"/dashboard\");\r\n // dispatch({\r\n // type: CLEAR_CLAIM,\r\n // });\r\n\r\n // Call reducer that updates the product in the list from free text search\r\n dispatch({ type: UPDATE_SINGLE_EPIX_PRODUCT_LIST, products });\r\n } else {\r\n dispatch(pushSystemMessage(payload && payload.displayMessage || \"Kan ikke oppdatere varer\", messageType.error));\r\n }\r\n } catch (error) {\r\n dispatch(pushSystemMessage(error && error.message || \"Kan ikke oppdatere varer\", messageType.error));\r\n Logger.error(error);\r\n } finally {\r\n // dispatch({\r\n // type: UPDATE_PRODUCTS,\r\n // committing: false,\r\n // });\r\n }\r\n };\r\n}\r\n","import \"../../../styles/kjedeweb/singleChainProductListItem.scss\";\r\n\r\nimport Icon, { iconTypes } from \"../../common/components/Icon.jsx\";\r\n\r\nimport FuturePriceItem from \"./FuturePriceComponent\";\r\nimport { Localization } from \"../../common/util/localization.jsx\";\r\nimport PropTypes from \"prop-types\";\r\nimport React from \"react\";\r\nimport ResponsiveColumn from \"../../common/components/ResponsiveColumn\";\r\nimport ResponsiveRows from \"../../common/components/ResponsiveRows\";\r\nimport SingleChainProductModal from \"./SingleChainProductModal\";\r\nimport moment from \"moment\";\r\nimport { toLocaleFixed } from \"../../common/util/localization.jsx\";\r\n\r\nexport class SingleEpixSortimentListHeader extends React.PureComponent {\r\n render() {\r\n const {\r\n localization,\r\n showInvoiceGroup,\r\n } = this.props;\r\n\r\n return (\r\n \r\n
\r\n \r\n \r\n {localization.text(\"chain\", \"chainSortiment\", \"productAndStatus\")}\r\n
\r\n \r\n \r\n \r\n {localization.text(\"chain\", \"chainSortiment\", \"productStatus\")}\r\n
\r\n \r\n \r\n \r\n {localization.text(\"chain\", \"chainSortiment\", \"noOfSalesUnits\")}\r\n
\r\n \r\n \r\n \r\n {localization.text(\"chain\", \"chainSortiment\", \"changed\")}\r\n
\r\n \r\n {showInvoiceGroup && (\r\n \r\n \r\n {localization.text(\"chain\", \"chainSortiment\", \"invoiceGroup\")}\r\n
\r\n \r\n )}\r\n \r\n \r\n {localization.text(\"chain\", \"chainSortiment\", \"netPrice\")}\r\n
\r\n \r\n \r\n \r\n {localization.text(\"chain\", \"chainSortiment\", \"netPricePerUnit\")}\r\n
\r\n \r\n \r\n \r\n {localization.text(\"chain\", \"chainSortiment\", \"adminChargePercent\")}\r\n
\r\n \r\n \r\n \r\n
\r\n \r\n \r\n
\r\n );\r\n }\r\n}\r\n\r\nSingleEpixSortimentListHeader.propTypes = {\r\n localization: Localization.propTypes.isRequired,\r\n showInvoiceGroup : PropTypes.bool,\r\n};\r\n\r\nexport class SingleEpixSortimentListItem extends React.PureComponent {\r\n constructor(props) {\r\n super(props);\r\n\r\n //this.onDeleteProduct = this.onDeleteProduct.bind(this);\r\n this.showProductModal = this.showProductModal.bind(this);\r\n this.closeProductModal = this.closeProductModal.bind(this);\r\n }\r\n\r\n showProductModal(event) {\r\n event.stopPropagation();\r\n event.preventDefault();\r\n\r\n const {\r\n localization,\r\n product,\r\n } = this.props;\r\n\r\n if (product.inCatalogue === true) {\r\n this.props.setModal();\r\n } else {\r\n this.props.setModal();\r\n }\r\n }\r\n closeProductModal(event) {\r\n event.stopPropagation();\r\n event.preventDefault();\r\n\r\n this.props.setModal(null);\r\n this.props.clearEpixProductDetails();\r\n }\r\n\r\n capitalizeFirstLetter(s) {\r\n s = s.toLowerCase();\r\n return s.charAt(0).toUpperCase() + s.slice(1);\r\n }\r\n\r\n // onDeleteProduct() {\r\n // let {\r\n // product,\r\n // } = this.props;\r\n\r\n // product = {\r\n // ...product,\r\n // inCatalogue: false\r\n // };\r\n // this.props.updateChainProducts(product.chainType, [product]);\r\n // }\r\n\r\n render() {\r\n const {\r\n localization,\r\n product,\r\n } = this.props;\r\n\r\n let priceColumns;\r\n\r\n if (product.inCatalogue === true) {\r\n priceColumns = [\r\n \r\n \r\n {toLocaleFixed(product.currentNetPrice,2)}\r\n
\r\n ,\r\n \r\n \r\n { toLocaleFixed(product.currentNetPricePerSalesUnit,3)}\r\n
\r\n ,\r\n // Endcus price will be inserted here conditionally (ref code below)\r\n \r\n \r\n ,\r\n \r\n \r\n {/*
*/}\r\n
\r\n \r\n
\r\n
\r\n \r\n ];\r\n } else {\r\n priceColumns = [\r\n \r\n \r\n
\r\n {localization.text(\"chain\", \"epixSortiment\", \"addPrices\")}\r\n
\r\n
\r\n ,\r\n \r\n {/* \r\n
\r\n \r\n
\r\n
*/}\r\n ];\r\n }\r\n\r\n return (\r\n \r\n
\r\n
\r\n \r\n \r\n
\r\n {product.imageUrl && (\r\n
\r\n
\r\n \r\n )}\r\n
\r\n
\r\n
EPD {product.epdNo}
\r\n
{product.productName}
\r\n\r\n
\r\n
\r\n
{product.inCatalogue ? \"Åpen\" : \"Stengt\"}\r\n
\r\n {/*
\r\n {product.inCatalogue && (
)}\r\n {product.inCatalogue ? \"I varekatalog\" : \"Ikke i varekatalog\"}\r\n
*/}\r\n
\r\n
\r\n
\r\n \r\n
\r\n \r\n
\r\n {product.status}\r\n
\r\n
\r\n \r\n
\r\n \r\n
\r\n {product.noOfSalesUnits}\r\n
\r\n
\r\n \r\n
\r\n \r\n
\r\n {product.lastChangedDate && moment(product.lastChangedDate).format(\"DD.MM.YY\")}\r\n
\r\n
\r\n \r\n {product.showInvoiceGroup && (\r\n
\r\n \r\n
\r\n {this.capitalizeFirstLetter(product.invoiceGroupName)}\r\n
\r\n
\r\n \r\n )}\r\n {priceColumns}\r\n \r\n
\r\n \r\n );\r\n }\r\n}\r\n\r\nSingleEpixSortimentListItem.propTypes = {\r\n clearEpixProductDetails: PropTypes.func.isRequired,\r\n localization: Localization.propTypes.isRequired,\r\n saveButtonText: PropTypes.string,\r\n setModal: PropTypes.func.isRequired,\r\n product: PropTypes.object,\r\n updateChainProducts: PropTypes.func.isRequired,\r\n};\r\n\r\nSingleEpixSortimentListItem.defaultProps = {\r\n};","import \"../../../styles/productView.scss\";\r\nimport \"../../../styles/productViewListItem.scss\";\r\n\r\nimport Loading, { loadingTypes } from \"../../common/components/Loading\";\r\nimport { SingleEpixSortimentListHeader, SingleEpixSortimentListItem } from \"./SingleEpixSortimentListItem.jsx\";\r\n\r\nimport ChainScroll from \"./ChainScroll\";\r\nimport { Localization } from \"../../common/util/localization.jsx\";\r\nimport PropTypes from \"prop-types\";\r\nimport React from \"react\";\r\n\r\nclass SingleEpixSortimentList extends React.PureComponent {\r\n constructor(props) {\r\n super(props);\r\n\r\n this.state = {\r\n width: null,\r\n };\r\n this.containerNode = null;\r\n this.trackScrolling = this.trackScrolling.bind(this);\r\n this.prepareItems = this.prepareItems.bind(this);\r\n }\r\n\r\n trackScrolling() {\r\n const {\r\n isLoading,\r\n loadMoreProducts,\r\n } = this.props;\r\n\r\n //load more products if none is loading\r\n if (isLoading === false && loadMoreProducts) {\r\n loadMoreProducts(50);\r\n }\r\n }\r\n\r\n prepareItems() {\r\n const {\r\n clearEpixProductDetails,\r\n deviceType,\r\n list,\r\n localization,\r\n isLoading,\r\n setModal,\r\n updateChainProducts,\r\n } = this.props;\r\n\r\n const retNodes = [];\r\n\r\n for (let i = 0; i < list.length; i++) {\r\n retNodes[retNodes.length] = (\r\n
);\r\n }\r\n if (isLoading) {\r\n retNodes[retNodes.length] =\r\n retNodes[retNodes.length] =\r\n
;\r\n }\r\n return retNodes;\r\n }\r\n\r\n render() {\r\n const {\r\n deviceType,\r\n localization,\r\n height,\r\n style,\r\n list,\r\n } = this.props;\r\n\r\n const nodes = this.prepareItems();\r\n\r\n const showInvoiceGroup = list.some(li => li.product.showInvoiceGroup);\r\n\r\n return (\r\n
\r\n \r\n \r\n
\r\n \r\n {nodes}\r\n \r\n \r\n );\r\n }\r\n}\r\n\r\nSingleEpixSortimentList.propTypes = {\r\n clearEpixProductDetails: PropTypes.func.isRequired,\r\n deviceType: PropTypes.string.isRequired,\r\n height: PropTypes.number,\r\n // If true a loading icon will be displayed\r\n isLoading: PropTypes.bool,\r\n // An array of products to be displayed\r\n list: PropTypes.array.isRequired,\r\n // A function that will load in more items into list\r\n loadMoreProducts: PropTypes.func,\r\n localization: Localization.propTypes.isRequired,\r\n setModal: PropTypes.func.isRequired,\r\n style: PropTypes.object,\r\n updateChainProducts: PropTypes.func.isRequired,\r\n};\r\n\r\nexport default SingleEpixSortimentList;\r\n","import { ChainTab, ChainTabList, ChainTabPanel, ChainTabs } from \"./ChainTabs.jsx\";\r\nimport { SubMenu, SubMenuItem } from \"../../common/components/SubMenu.jsx\";\r\n\r\nimport { Localization } from \"../../common/util/localization.jsx\";\r\nimport PropTypes from \"prop-types\";\r\nimport React from \"react\";\r\nimport SingleEpixSortimentList from \"./SingleEpixSortimentList.jsx\";\r\nimport { iconTypes } from \"../../common/components/Icon.jsx\";\r\nimport { scssVariables } from \"../../common/util/config.jsx\";\r\nimport { withRouter } from \"react-router-dom\";\r\n\r\nclass SingleEpixSortimentCard extends React.PureComponent {\r\n constructor(props) {\r\n super(props);\r\n\r\n this.swallowOnClick = this.swallowOnClick.bind(this);\r\n this.onTabAllClicked = this.onTabAllClicked.bind(this);\r\n this.onTabNewClicked = this.onTabNewClicked.bind(this);\r\n this.calculateInternalPanelHeight = this.calculateInternalPanelHeight.bind(this);\r\n this.onExportCsv = this.onExportCsv.bind(this);\r\n }\r\n\r\n onTabAllClicked() {\r\n const path = this.props.location.pathname;\r\n //replace only whats after the last / with the new path\r\n this.props.history.replace(`${path.substr(0, path.lastIndexOf(\"/\"))}/all`);\r\n this.props.editSingleEpixFilter({\r\n onlyNews: false,\r\n });\r\n }\r\n\r\n onTabNewClicked() {\r\n const path = this.props.location.pathname;\r\n //replace only whats after the last / with the new path\r\n this.props.history.replace(`${path.substr(0, path.lastIndexOf(\"/\"))}/new`);\r\n this.props.editSingleEpixFilter({\r\n onlyNews: true,\r\n });\r\n }\r\n\r\n swallowOnClick(event) {\r\n event.stopPropagation();\r\n event.preventDefault();\r\n }\r\n\r\n onExportCsv() {\r\n const {\r\n singleEpixSortiment,\r\n exportCsv,\r\n } = this.props;\r\n\r\n exportCsv(singleEpixSortiment);\r\n }\r\n\r\n calculateInternalPanelHeight() {\r\n let tabPanelHeight = this.props.height;\r\n\r\n // Remove height of tab panel\r\n tabPanelHeight -= parseInt(scssVariables.menuHeightWithBorder);\r\n return tabPanelHeight;\r\n }\r\n\r\n render() {\r\n const {\r\n clearEpixProductDetails,\r\n currentView,\r\n deviceType,\r\n height,\r\n loadMoreSearchResults,\r\n localization,\r\n setModal,\r\n singleEpixSortiment,\r\n updateChainProducts,\r\n width,\r\n } = this.props;\r\n const tabPanelHeight = this.calculateInternalPanelHeight();\r\n\r\n return (\r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n );\r\n }\r\n}\r\n\r\nSingleEpixSortimentCard.propTypes = {\r\n clearEpixProductDetails: PropTypes.func.isRequired,\r\n currentView: PropTypes.string,\r\n deviceType: PropTypes.string.isRequired,\r\n editSingleEpixFilter: PropTypes.func.isRequired,\r\n height: PropTypes.number.isRequired,\r\n history: PropTypes.object.isRequired,\r\n loadMoreSearchResults: PropTypes.func.isRequired,\r\n localization: Localization.propTypes.isRequired,\r\n location: PropTypes.object.isRequired,\r\n setModal: PropTypes.func.isRequired,\r\n singleEpixSortiment: PropTypes.object.isRequired,\r\n updateChainProducts: PropTypes.func.isRequired,\r\n width: PropTypes.number.isRequired,\r\n exportCsv : PropTypes.func.isRequired,\r\n};\r\n\r\nSingleEpixSortimentCard.defaultProps = {\r\n currentView: \"all\",\r\n};\r\nexport default withRouter(SingleEpixSortimentCard);\r\n","import \"../../../styles/page/order.scss\";\r\n\r\nimport { TitleTab, TitleTabs } from \"../../common/components/TitleTabs.jsx\";\r\n\r\nimport ContentWrapper from \"../../common/components/ContentWrapper\";\r\nimport { Localization } from \"../../common/util/localization.jsx\";\r\nimport PropTypes from \"prop-types\";\r\nimport React from \"react\";\r\nimport SingleChainSearchBar from \"./SingleChainSearchBar.jsx\";\r\nimport SingleEpixSortimentCard from \"./SingleEpixSortimentCard.jsx\";\r\nimport { scssVariables } from \"../../common/util/config.jsx\";\r\nimport { withRouter } from \"react-router-dom\";\r\n\r\nclass SingleEpixPage extends React.PureComponent {\r\n constructor(props) {\r\n super(props);\r\n\r\n this.calculateProductDisplayHeight = this.calculateProductDisplayHeight.bind(this);\r\n this.calculateProductDisplayWidth = this.calculateProductDisplayWidth.bind(this);\r\n this.loadMoreSearchResults = this.loadMoreSearchResults.bind(this);\r\n this.onEditFilter = this.onEditFilter.bind(this);\r\n }\r\n\r\n UNSAFE_componentWillMount() {\r\n const {\r\n clearSingleEpixSortiment,\r\n prepareQueryOptions,\r\n } = this.props;\r\n\r\n clearSingleEpixSortiment();\r\n prepareQueryOptions();\r\n }\r\n\r\n calculateProductDisplayHeight() {\r\n const {\r\n deviceType,\r\n height,\r\n } = this.props;\r\n let productDisplayHeight = height;\r\n\r\n // Page padding\r\n productDisplayHeight -= parseInt(scssVariables[`${deviceType}ContentPadding`]) * 2;\r\n\r\n if (deviceType === \"xs\") {\r\n productDisplayHeight -= parseInt(scssVariables.menuHeightWithBorder);\r\n } else {\r\n // Title tab height\r\n productDisplayHeight -= parseInt(scssVariables.cardMargin) * 2;\r\n productDisplayHeight -= parseInt(scssVariables.titleTabHeight);\r\n\r\n // Search bar height\r\n productDisplayHeight -= parseInt(scssVariables.cardMargin) * 2;\r\n productDisplayHeight -= parseInt(scssVariables.menuHeightWithBorder);\r\n }\r\n\r\n // Product display padding\r\n productDisplayHeight -= parseInt(scssVariables.cardMargin) * 2;\r\n\r\n return productDisplayHeight;\r\n }\r\n\r\n calculateProductDisplayWidth() {\r\n const {\r\n deviceType,\r\n width,\r\n } = this.props;\r\n\r\n let productDisplayWidth = width;\r\n if (deviceType === \"xs\") {\r\n // Page padding\r\n productDisplayWidth -= parseInt(scssVariables[`${deviceType}ContentPadding`]) * 2;\r\n\r\n // Product display padding\r\n productDisplayWidth -= parseInt(scssVariables.cardMargin) * 2;\r\n } else {\r\n // Page padding\r\n productDisplayWidth -= parseInt(scssVariables[`${deviceType}ContentPadding`]); // No padding on the right side(Attached to it)\r\n\r\n // Product display padding\r\n productDisplayWidth -= parseInt(scssVariables.cardMargin) * 2;\r\n }\r\n\r\n return productDisplayWidth;\r\n }\r\n\r\n onEditFilter(...args) {\r\n const {\r\n editSingleEpixFilter,\r\n flowControl,\r\n } = this.props;\r\n flowControl(async () => {\r\n await editSingleEpixFilter(...args);\r\n });\r\n }\r\n\r\n loadMoreSearchResults() {\r\n const {\r\n deviceType,\r\n loadMoreSingleEpixSortiment,\r\n } = this.props;\r\n const productDisplayHeight = this.calculateProductDisplayHeight();\r\n const rowsToLoad = (Math.floor(productDisplayHeight / parseInt(scssVariables.productItemHeight)) + 2);\r\n // rowsToLoad * itemsPerRow\r\n switch (deviceType) {\r\n case \"xs\":\r\n case \"sm\":\r\n this.props.flowControl(async () => { await loadMoreSingleEpixSortiment(rowsToLoad * 2); });\r\n break;\r\n case \"md\":\r\n this.props.flowControl(async () => { await loadMoreSingleEpixSortiment(rowsToLoad * 4); });\r\n break;\r\n case \"lg\":\r\n this.props.flowControl(async () => { await loadMoreSingleEpixSortiment(rowsToLoad * 6); });\r\n break;\r\n default:\r\n this.props.flowControl(async () => { await loadMoreSingleEpixSortiment(rowsToLoad * 8); });\r\n break;\r\n }\r\n }\r\n\r\n render() {\r\n const {\r\n clearEpixProductDetails,\r\n deviceType,\r\n editSingleEpixFilter,\r\n height,\r\n localization,\r\n setModal,\r\n setDropDown,\r\n singleEpixSortiment,\r\n updateChainProducts,\r\n exportCsv,\r\n } = this.props;\r\n\r\n const productDisplayHeight = this.calculateProductDisplayHeight();\r\n const productDisplayWidth = this.calculateProductDisplayWidth();\r\n\r\n const filter = {\r\n onlyNews: this.props.startView === \"new\",\r\n productGroupId: null,\r\n supplierId: null,\r\n };\r\n\r\n return (\r\n
\r\n \r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n
\r\n );\r\n }\r\n}\r\n\r\nSingleEpixPage.propTypes = {\r\n clearEpixProductDetails: PropTypes.func.isRequired,\r\n clearSingleEpixSortiment: PropTypes.func.isRequired,\r\n deviceType: PropTypes.string.isRequired,\r\n editSingleEpixFilter: PropTypes.func.isRequired,\r\n flowControl: PropTypes.func.isRequired,\r\n height: PropTypes.number.isRequired,\r\n loadMoreSingleEpixSortiment: PropTypes.func.isRequired,\r\n localization: Localization.propTypes.isRequired,\r\n prepareQueryOptions: PropTypes.func.isRequired,\r\n setModal: PropTypes.func.isRequired,\r\n setDropDown: PropTypes.func.isRequired,\r\n startView: PropTypes.string.isRequired,\r\n singleEpixSortiment: PropTypes.object.isRequired,\r\n updateChainProducts: PropTypes.func.isRequired,\r\n width: PropTypes.number.isRequired,\r\n exportCsv: PropTypes.func.isRequired,\r\n};\r\n\r\nexport default withRouter(SingleEpixPage);\r\n","import { clearEpixProductDetails, clearSingleEpixSortiment, editSingleEpixFilter, loadMoreSingleEpixSortiment, prepareQueryOptions, updateChainProducts } from \"../actions/singleEpixSortiment\";\r\nimport { setDropDown, setModal } from \"../../common/actions/modal\";\r\n\r\nimport SingleEpixPage from \"../components/SingleEpixPage.jsx\";\r\nimport { connect } from \"react-redux\";\r\nimport { createBoundFunction } from \"../../common/util/reselect.js\";\r\nimport { createFlowControl } from \"../../common/util/flowControl\";\r\nimport { createLocalization } from \"../../common/util/localization.jsx\";\r\nimport { exportCsv } from \"../actions/multiChainSortiment\";\r\nimport { scssVariables } from \"../../common/util/config.jsx\";\r\n\r\nconst mapStateToProps = () => {\r\n const flowControl = createFlowControl();\r\n const flowControlCounter = createFlowControl();\r\n\r\n return (state, ownProps) => ({\r\n deviceType: state.view.deviceType,\r\n flowControl: flowControl,\r\n flowControlCounter: flowControlCounter,\r\n height: state.view.innerHeight - parseInt(scssVariables.menuHeight),\r\n localization: createLocalization(state),\r\n singleEpixSortiment: state.singleEpixSortiment,\r\n startView: ownProps.match.params.view || \"all\",\r\n width: state.view.innerWidth,\r\n });\r\n};\r\n\r\nconst mapDispatchToProps = {\r\n clearEpixProductDetails,\r\n clearSingleEpixSortiment,\r\n editSingleEpixFilter,\r\n loadMoreSingleEpixSortiment,\r\n prepareQueryOptions,\r\n updateChainProducts,\r\n setModal,\r\n setDropDown,\r\n exportCsv,\r\n};\r\n\r\nconst myLoadMoreSingleEpixSortiment = createBoundFunction();\r\nconst myEditSingleEpixFilter = createBoundFunction();\r\n\r\nconst mergeProps = (stateProps, dispatchProps, ownProps) => ({\r\n ...stateProps,\r\n ...dispatchProps,\r\n ...ownProps,\r\n loadMoreSingleEpixSortiment: myLoadMoreSingleEpixSortiment((noOfProducts) => dispatchProps.loadMoreSingleEpixSortiment(stateProps.singleEpixSortiment, stateProps.productImage, noOfProducts)),\r\n editSingleEpixFilter: myEditSingleEpixFilter((change) => dispatchProps.editSingleEpixFilter(change,\r\n myLoadMoreSingleEpixSortiment((noOfProducts) => dispatchProps.loadMoreSingleEpixSortiment(stateProps.singleEpixSortiment, stateProps.productImage, noOfProducts))\r\n )),\r\n});\r\n\r\nexport default connect(mapStateToProps, mapDispatchToProps, mergeProps)(SingleEpixPage);\r\n","import {Redirect, Route, Switch} from \"react-router-dom\";\r\nimport {isLoggedIn, logOut, validateAndRefreshToken} from \"../../common/actions/authentication.js\";\r\n\r\nimport AccountSettingsContainer from \"../containers/AccountSettingsContainer.jsx\";\r\nimport CampaignsContainer from \"../containers/CampaignsContainer.jsx\";\r\nimport ComponentsColor from \"../../common/components/ComponentsColor.jsx\";\r\nimport ComponentsShowCase from \"../../common/components/ComponentsShowCase.jsx\";\r\nimport DashboardContainer from \"../../kundeweb/containers/dashboardContainer.jsx\";\r\nimport DominosContainer from \"../../dominosweb/containers/DominosContainer.jsx\";\r\nimport EditMyListContainer from \"../containers/EditMyListContainer.jsx\";\r\nimport FreshFoodTemplateContainer from \"../containers/FreshFoodTemplateContainer.jsx\";\r\n\r\nimport HelpFaqContainer from \"../containers/HelpFaqContainer.jsx\";\r\nimport HistoryClaimContainer from \"../containers/history/HistoryClaimContainer.jsx\";\r\nimport HistoryTabsContainer from \"../containers/history/HistoryTabsContainer.jsx\";\r\nimport HubOverviewContainer from \"../../hubweb/containers/HubOverviewContainer.jsx\";\r\nimport HubProductionContainer from \"../../hubweb/containers/HubProductionContainer.jsx\";\r\nimport MultiChainContainer from \"../../kjedeweb/containers/MultiChainContainer.jsx\";\r\nimport MultiEpixContainer from \"../../kjedeweb/containers/MultiEpixContainer.jsx\";\r\nimport MyListContainer from \"../containers/MyListContainer.jsx\";\r\nimport OrderProductsContainer from \"../containers/OrderProductsContainer.jsx\";\r\nimport Page404 from \"../../common/components/Page404.jsx\";\r\nimport PropTypes from \"prop-types\";\r\nimport React from \"react\";\r\nimport SingleChainContainer from \"../../kjedeweb/containers/SingleChainContainer.jsx\";\r\nimport SingleEpixContainer from \"../../kjedeweb/containers/SingleEpixContainer.jsx\";\r\nimport {checkIfWebSiteIsClosed} from \"../../common/actions/authentication.js\";\r\nimport {connect} from \"react-redux\";\r\nimport {loadAndShowLatestMustReadNotification} from \"../../common/actions/notifications.js\";\r\n\r\n\r\nimport {setCurrentLanguage} from \"../../common/actions/userSettings.js\";\r\nimport {withRouter} from \"react-router-dom\";\r\n\r\nconst mapStateToProps = state => ({\r\n authentication: state.authentication,\r\n deviceType: state.view.deviceType,\r\n localization: state.localization,\r\n});\r\nconst mapDispatchToProps = {\r\n validateAndRefreshToken,\r\n loadAndShowLatestMustReadNotification,\r\n checkIfWebSiteIsClosed,\r\n logOut,\r\n setCurrentLanguage\r\n};\r\nclass Routing extends React.Component{\r\n componentDidMount() {\r\n const minimumRemainingTokenValidityInSeconds = 60 * 5;\r\n this.validatingInterval = setInterval(() => this.props.validateAndRefreshToken(minimumRemainingTokenValidityInSeconds,this.props.history), 30000);\r\n\r\n if(!this.props.authentication.isChainLogin && !this.props.authentication.isHubLogin && !this.props.authentication.isDominosLogin)\r\n {\r\n this.loadNotificationsInterval = setInterval(() => {\r\n if (isLoggedIn(this.props.authentication)) {\r\n this.props.loadAndShowLatestMustReadNotification();\r\n }\r\n }, 3 * 60 * 1000);\r\n \r\n if (isLoggedIn(this.props.authentication)) {\r\n this.props.loadAndShowLatestMustReadNotification();\r\n }\r\n } \r\n\r\n if( !this.props.localization.hasData ){\r\n this.props.setCurrentLanguage(\"no\");\r\n }\r\n\r\n // Set scan interval for web site closing\r\n this.webSitePollInterval = setInterval(() => {\r\n this.props.checkIfWebSiteIsClosed();\r\n },60 * 1000);\r\n \r\n }\r\n componentWillUnmount() {\r\n clearInterval(this.validatingInterval);\r\n clearInterval(this.loadNotificationsInterval);\r\n }\r\n render(){\r\n const {\r\n authentication,\r\n deviceType,\r\n history,\r\n logOut\r\n } = this.props;\r\n\r\n if( !isLoggedIn(authentication) ){\r\n return
;\r\n }\r\n\r\n if ((authentication.isChainLogin || authentication.isHubLogin || authentication.isDominosLogin) && (deviceType === \"xs\" || deviceType === \"sm\" || deviceType === \"md\")) {\r\n return (\r\n \r\n
\r\n
\r\n
\r\n
Denne websiden støtter bare stasjonære datamaskiner.
\r\n {/* eslint-disable-next-line react/jsx-no-bind */}\r\n \r\n \r\n
\r\n
\r\n );\r\n }\r\n\r\n return (authentication.isHubLogin ? (\r\n
\r\n \r\n \r\n \r\n \r\n ) : (\r\n authentication.isDominosLogin ? (\r\n
\r\n \r\n \r\n \r\n ) : (\r\n authentication.isChainLogin ? (\r\n authentication.chainIds.length > 1 ? (\r\n
\r\n \r\n \r\n \r\n \r\n ) : (\r\n
\r\n \r\n \r\n \r\n \r\n )) : (\r\n
\r\n \r\n \r\n \r\n \r\n {(process.env.NODE_ENV !== \"production\") && (\r\n \r\n )}\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n {(process.env.NODE_ENV !== \"production\") && (\r\n \r\n )}\r\n {(process.env.NODE_ENV !== \"production\") && (\r\n \r\n )}\r\n \r\n \r\n {(process.env.NODE_ENV !== \"production\") && (\r\n \r\n )}\r\n \r\n \r\n ))));\r\n }\r\n}\r\nRouting.propTypes = {\r\n authentication: PropTypes.object.isRequired,\r\n deviceType: PropTypes.string.isRequired,\r\n validateAndRefreshToken: PropTypes.func.isRequired,\r\n setCurrentLanguage: PropTypes.func.isRequired,\r\n history: PropTypes.object.isRequired,\r\n localization: PropTypes.object,\r\n logOut: PropTypes.func.isRequired,\r\n loadAndShowLatestMustReadNotification: PropTypes.func.isRequired,\r\n checkIfWebSiteIsClosed: PropTypes.func.isRequired\r\n};\r\n\r\nexport default withRouter(connect(mapStateToProps, mapDispatchToProps)(Routing));","import \"../../../styles/systemMessage.scss\";\r\n\r\nimport Icon, { iconTypes } from \"./Icon\";\r\nimport { messageType, removeSystemMessage } from \"../actions/systemMessage.js\";\r\n\r\nimport PropTypes from \"prop-types\";\r\nimport React from \"react\";\r\nimport { connect } from \"react-redux\";\r\n\r\nclass Message extends React.Component{\r\n constructor(props){\r\n super(props);\r\n\r\n this.onCloseMessage = this.onCloseMessage.bind(this);\r\n this.onMouseEnterHandler = this.onMouseEnterHandler.bind(this);\r\n this.onMouseLeaveHandler = this.onMouseLeaveHandler.bind(this);\r\n\r\n this.state = {\r\n timer: setTimeout( this.onCloseMessage, 10000 ),\r\n };\r\n }\r\n onMouseEnterHandler() {\r\n if( this.state.timer ) {\r\n clearTimeout(this.state.timer);\r\n this.setState({\r\n timer: null,\r\n });\r\n }\r\n }\r\n onMouseLeaveHandler() {\r\n if( this.state.timer ) {\r\n clearTimeout(this.state.timer);\r\n }\r\n this.setState({\r\n timer: setTimeout( this.onCloseMessage, 10000 )\r\n });\r\n }\r\n onCloseMessage() {\r\n this.props.removeSystemMessage(this.props.index);\r\n }\r\n render() {\r\n const {message, position, type} = this.props;\r\n return (\r\n
\r\n
\r\n {message}\r\n
\r\n
\r\n \r\n
\r\n
\r\n );\r\n }\r\n}\r\n\r\nMessage.propTypes = {\r\n removeSystemMessage: PropTypes.func.isRequired,\r\n index: PropTypes.number.isRequired,\r\n message: PropTypes.string.isRequired,\r\n type: PropTypes.string.isRequired,\r\n position: PropTypes.number.isRequired,\r\n};\r\n\r\n\r\n\r\nconst mapStateToProps = state => {\r\n return {\r\n messages: state.systemMessage.messages,\r\n };\r\n};\r\nconst mapDispatchToProps = {\r\n removeSystemMessage,\r\n};\r\n/**\r\n * Returnerar Icon node med icon kod inkluderad\r\n * @param {object} props\r\n * @returns {node}\r\n */\r\nfunction SystemMessage({messages, removeSystemMessage}) {\r\n const nodes = [];\r\n for(let i=messages.length-1; i>=0; i--){\r\n nodes.push(\r\n
\r\n );\r\n }\r\n return nodes;\r\n}\r\n\r\nSystemMessage.propTypes = {\r\n removeSystemMessage: PropTypes.func.isRequired,\r\n messages: PropTypes.array,\r\n};\r\n\r\nexport default connect(mapStateToProps, mapDispatchToProps)(SystemMessage);","import {BrowserRouter, Route, Switch} from \"react-router-dom\";\r\n\r\nimport ChangePasswordContainer from \"../../common/containers/ChangePasswordContainer.jsx\";\r\nimport ForgotPasswordContainer from \"../../common/containers/ForgotPasswordContainer.jsx\";\r\nimport LoginContainer from \"../../common/containers/LoginContainer.jsx\";\r\nimport React from \"react\";\r\nimport Router from \"./router.jsx\";\r\nimport SystemMessage from \"../../common/components/SystemMessage.jsx\";\r\nimport {wwwPrefix} from \"../../common/util/config.jsx\";\r\n\r\nexport default class RootRouter extends React.Component{\r\n constructor(props) {\r\n super(props);\r\n this.state = {\r\n fatalError: false,\r\n fatalInfo: undefined,\r\n };\r\n }\r\n componentDidCatch(error, info) {\r\n const infoStr = `${((error && error.message) || \"\")}\\n\\n ${((error && error.stack) || \"\")} \\n${((info && info.componentStack) || \"\")}`;\r\n if(infoStr.includes(\"https://reactjs.org/docs/error-decoder.html?invariant=130&args[]=undefined&args[]=\")) {\r\n this.setState({\r\n fatalError: true,\r\n fatalInfo: `Kan vara denna plugin som orsakar problemet: plugin-transform-react-constant-elements\\n\\nElement type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined.\\n\\n${infoStr}`\r\n });\r\n } else {\r\n this.setState({\r\n fatalError: true,\r\n fatalInfo: infoStr\r\n });\r\n }\r\n }\r\n render() {\r\n if(this.state.fatalError) {\r\n return (\r\n \r\n \r\n Fatal error
\r\n \r\n
\r\n Log out button{/*TODO: fix one? */}\r\n \r\n );\r\n }\r\n return (\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n );\r\n }\r\n}","import CryptoJS from \"crypto-js\";\r\nimport {static as Immutable} from \"seamless-immutable\";\r\n\r\nconst LOCAL_STORAGE_UPDATED_IN_OTHER_TAB = \"LOCAL_STORAGE_UPDATED_IN_OTHER_TAB\";\r\n\r\n/**\r\n * Action creator for when the browser signals that local storage has been updated in another browser tab.\r\n * @param {string} nameInStorage\r\n * @param {string} encryptedData\r\n * @return {{type: string, nameInStorage: string, encryptedData: string}}\r\n */\r\nexport function localStorageUpdatedInOtherTab(nameInStorage, encryptedData) {\r\n return {\r\n type: LOCAL_STORAGE_UPDATED_IN_OTHER_TAB,\r\n nameInStorage,\r\n encryptedData\r\n };\r\n}\r\n\r\nconst SALT = \"kiha3268sdUIASDlkn5349\";\r\n\r\nconst getSecret = (flush) => {\r\n let publicKey = localStorage.getItem(\"publicKey\");\r\n if (flush || !publicKey) {\r\n localStorage.clear();\r\n publicKey = CryptoJS.SHA256(`iouwerknvdasoiwueqrnvdasnkjaer:${new Date().toDateString()}`);\r\n localStorage.setItem(\"publicKey\", publicKey);\r\n }\r\n\r\n return `${publicKey}${SALT}`;\r\n};\r\n\r\n/**\r\n * Wraps a reducer function which, if the state has been changed on any of the keys which are specified for storage, stores the new state in localStorage.\r\n * Loads the default state (for instance on page load) from the store.\r\n * @param {Function} reducer\r\n * @param {Function} defaultState\r\n * @param {string} nameInStorage\r\n * @param {string[]} rootKeysToStore\r\n * @return {Function}\r\n */\r\nexport function localStorageWritingReducer(reducer, defaultState, nameInStorage, rootKeysToStore) {\r\n return (state, action) => {\r\n if (action.type == LOCAL_STORAGE_UPDATED_IN_OTHER_TAB && nameInStorage === action.nameInStorage) {\r\n let newData;\r\n try {\r\n newData = JSON.parse(CryptoJS.AES.decrypt(action.encryptedData, getSecret()).toString(CryptoJS.enc.Utf8));\r\n return Immutable.merge(state || defaultState(), newData, {deep: true});\r\n } catch (error) {\r\n throw new Error(\"Could not parse local storage data passed from other tab.\");\r\n }\r\n }\r\n\r\n if (!state) {\r\n let storedData;\r\n try {\r\n storedData = JSON.parse(CryptoJS.AES.decrypt(localStorage.getItem(nameInStorage), getSecret()).toString(CryptoJS.enc.Utf8));\r\n } catch (error) {\r\n storedData = {};\r\n } finally {\r\n state = Immutable.merge(defaultState(), storedData, {deep: true});\r\n }\r\n }\r\n const newState = reducer(state, action);\r\n\r\n if (rootKeysToStore.some(k => newState[k] !== state[k])) {\r\n const toStore = Object.assign({}, ...rootKeysToStore.map(k => ({\r\n [k]: newState[k]\r\n })));\r\n localStorage.setItem(nameInStorage, CryptoJS.AES.encrypt(JSON.stringify(toStore), getSecret()).toString());\r\n }\r\n\r\n return newState;\r\n };\r\n}\r\n\r\nconst resetVolatile = data => {\r\n if (Array.isArray(data)) {\r\n for (const elem of data) {\r\n resetVolatile(elem);\r\n }\r\n } else if (data && (typeof data === \"object\")) {\r\n for (const key in data) {\r\n const value = data[key];\r\n if (key.startsWith(\"volatile\")) {\r\n if (typeof value === \"boolean\") {\r\n data[key] = false;\r\n } else {\r\n data[key] = undefined;\r\n }\r\n } else {\r\n resetVolatile(value);\r\n }\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Wraps a reducer function which, if the state has been changed on any of the keys which are specified for storage, stores the new state in sessionStorage.\r\n * Loads the default state (for instance on page load) from the store.\r\n * @param {Function} reducer\r\n * @param {Function} defaultState\r\n * @param {string} nameInStorage\r\n * @return {Function}\r\n */\r\nexport function sessionStorageWritingReducer(reducer, defaultState, nameInStorage) {\r\n return (state, action) => {\r\n if (!state) {\r\n let storedData;\r\n try {\r\n storedData = JSON.parse(sessionStorage[nameInStorage]);\r\n resetVolatile(storedData);\r\n } catch (error) {\r\n storedData = {};\r\n } finally {\r\n state = Immutable.merge(defaultState(), storedData, {deep: true});\r\n }\r\n }\r\n const newState = reducer(state, action);\r\n if (newState != state) {\r\n try {\r\n sessionStorage[nameInStorage] = JSON.stringify(newState);\r\n } catch (error) {\r\n sessionStorage.clear();\r\n }\r\n }\r\n\r\n return newState;\r\n };\r\n}\r\n","import * as authentication from \"../actions/authentication\";\r\n\r\nimport {static as Immutable} from \"seamless-immutable\";\r\nimport {localStorageWritingReducer} from \"../util/storage\";\r\n\r\nconst defaultState = () => {\r\n return Immutable({\r\n loginForm: {\r\n original: {},\r\n changes: []\r\n },\r\n loggingIn: false,\r\n token: undefined,\r\n tokenValidUntil: undefined,\r\n signedInAs: undefined,\r\n refreshing: false,\r\n languageId: undefined,\r\n serverName: undefined,\r\n email: undefined,\r\n chainType: undefined,\r\n isAdmin: false,\r\n isImpersonated: false,\r\n chainIds: [],\r\n pickupTobaccoDefault: true,\r\n freightChargePickupTobacco: null,\r\n isBlockedCustomer: false,\r\n webEditOnlyTobacco: false,\r\n webSiteClosed: false,\r\n webSiteClosedMessage: \"\",\r\n userConfirmedWebSiteClosedMessage: false,\r\n newSeasonDistrDates: [],\r\n showFreshFood: false,\r\n });\r\n};\r\n\r\nconst reducer = (state = defaultState(), action) => {\r\n switch (action.type) {\r\n case authentication.LOGGING_IN:\r\n return Immutable.set(state, \"loggingIn\", true);\r\n case authentication.LOGIN_ATTEMPT_ENDED:\r\n return Immutable.set(state, \"loggingIn\", false);\r\n case authentication.LOGGED_IN: \r\n return Immutable.merge(state, {\r\n loggingIn: false,\r\n token: action.token,\r\n refreshToken: action.refreshToken,\r\n tokenValidUntil: action.tokenValidUntil,\r\n signedInAs: action.signedInAs,\r\n languageId: action.languageId,\r\n serverName: action.serverName,\r\n email: action.email,\r\n isChainLogin:action.isChainLogin,\r\n isHubLogin:action.isHubLogin,\r\n isDominosLogin:action.isDominosLogin,\r\n hubId:action.hubId,\r\n chainType: action.chainType,\r\n loginForm: defaultState().loginForm,\r\n isAdmin: action.isAdmin,\r\n isImpersonated: action.isImpersonated,\r\n chainIds: action.chainIds,\r\n pickupTobaccoDefault: action.pickupTobaccoDefault,\r\n freightChargePickupTobacco: action.freightChargePickupTobacco,\r\n isBlockedCustomer: action.isBlockedCustomer,\r\n webEditOnlyTobacco: action.webEditOnlyTobacco,\r\n webSiteClosed : false,\r\n webSiteClosedMessage : \"\", \r\n userConfirmedWebSiteClosedMessage: false,\r\n newSeasonDistrDates : action.newSeasonDistrDates,\r\n seasonMessageConfirmed : false,\r\n showFreshFood : action.showFreshFood,\r\n });\r\n case authentication.REFRESHING_TOKEN:\r\n return Immutable.merge(state, {\r\n refreshing: true\r\n });\r\n case authentication.REFRESHED_TOKEN:\r\n return Immutable.merge(state, {\r\n refreshing: false,\r\n token: action.token,\r\n refreshToken: action.refreshToken,\r\n tokenValidUntil: action.tokenValidUntil\r\n });\r\n case authentication.FAILED_TO_REFRESH_TOKEN:\r\n return Immutable.merge(state, {\r\n refreshing: false\r\n });\r\n case authentication.LOGGED_OUT:\r\n return defaultState();\r\n case authentication.SET_WEBSITE_STATUS_RESULTS:\r\n return Immutable.merge(state, {\r\n webSiteClosed: action.webIsClosed,\r\n webSiteClosedMessage: action.message,\r\n });\r\n case authentication.SET_WEBSITE_MESSAGE_CONFIRMED:\r\n return Immutable.merge(state, {\r\n userConfirmedWebSiteClosedMessage: true,\r\n });\r\n case authentication.SET_SEASON_MESSAGE_CONFIRMED:\r\n return Immutable.merge(state, {\r\n seasonMessageConfirmed : true\r\n });\r\n default:\r\n return state;\r\n }\r\n};\r\n\r\nexport default localStorageWritingReducer(reducer, defaultState, \"app_authentication\", \r\n [\"token\", \"refreshToken\", \"tokenValidUntil\", \"serverName\", \"signedInAs\", \"languageId\", \"email\", \"isChainLogin\", \"isHubLogin\", \"isDominosLogin\", \r\n \"hubId\", \"chainType\", \"isAdmin\", \"isImpersonate\", \"chainIds\", \"pickupTobaccoDefault\", \"freightChargePickupTobacco\", \r\n \"isBlockedCustomer\",\"webEditOnlyTobacco\", \"webSiteClosed\", \"webSiteClosedMessage\", \"userConfirmedWebSiteClosedMessage\", \"newSeasonDistrDates\", \"seasonMessageConfirmed\", \"showFreshFood\"]);\r\n\r\n","import * as authentication from \"../actions/authentication\";\r\nimport * as localization from \"../actions/localization.js\";\r\n\r\nimport {static as Immutable} from \"seamless-immutable\";\r\n\r\nconst defaultState = () => {\r\n return Immutable({\r\n downloading: false,\r\n hasData: false,\r\n data: {}\r\n });\r\n};\r\n\r\n/**\r\n * Localization reducer\r\n * @param {Object} state\r\n * @param {{type: string}} action\r\n * @return {*}\r\n */\r\nexport default function (state = defaultState(), action) {\r\n switch (action.type) {\r\n case localization.DOWNLOADING_LOCALIZATION:\r\n return Immutable.merge(state, {\r\n downloading: true,\r\n hasData: false\r\n });\r\n case localization.DOWNLOADED_LOCALIZATION:\r\n return Immutable.merge(state, {\r\n downloading: false,\r\n hasData: true,\r\n data: Immutable(action.data)\r\n });\r\n case localization.FAILED_TO_DOWNLOAD_LOCALIZATION:\r\n return Immutable.merge(state, {\r\n downloading: false,\r\n hasData: false\r\n });\r\n case authentication.LOGGED_OUT:\r\n return defaultState();\r\n default:\r\n return state;\r\n }\r\n}","import * as authentication from \"../actions/authentication\";\r\nimport * as modal from \"../actions/modal.js\";\r\n\r\nimport Immutable from \"seamless-immutable\";\r\n\r\nconst defaultState = () => {\r\n return Immutable({\r\n modal: null,\r\n dropDown: [],\r\n });\r\n};\r\n\r\n/**\r\n * View reducer\r\n * @param {Object} state\r\n * @param {{type: string}} action\r\n * @return {*}\r\n */\r\nexport default function(state = defaultState(), action) {\r\n switch(action.type) {\r\n case modal.SET_MODAL:\r\n return state.merge({\r\n modal: action.modal,\r\n });\r\n case modal.ADD_DROPDOWN:\r\n return state.merge({\r\n dropDown: state.dropDown.concat(action.dropDown),\r\n });\r\n case modal.POP_DROPDOWN:\r\n return state.merge({\r\n dropDown: state.dropDown.filter( (item, index) => index+1!==state.dropDown.length ),\r\n });\r\n case modal.CLEAR_MODAL_DROPDOWNS:\r\n case authentication.LOGGED_OUT:\r\n return defaultState();\r\n default:\r\n return state;\r\n }\r\n}","import authenticationReducer from \"./authenticationReducer.js\";\r\nimport localizationReducer from \"./localizationReducer.js\";\r\nimport modalReducer from \"./modalReducer\";\r\nimport userSettingsReducer from \"./userSettingsReducer\";\r\n\r\nexport default {\r\n authentication: authenticationReducer,\r\n localization: localizationReducer,\r\n userSettings: userSettingsReducer,\r\n modal: modalReducer,\r\n};","import * as userSettings from \"../actions/userSettings.js\";\r\n\r\nimport {static as Immutable} from \"seamless-immutable\";\r\nimport {localStorageWritingReducer} from \"../util/storage.js\";\r\n\r\nconst defaultState = () => {\r\n return Immutable({\r\n currentLanguage: \"no\", // Systemets förvalda språk (Se index.html)\r\n currentOwner: undefined,\r\n currentReceivingPoint: undefined,\r\n systemInfo: {\r\n country: undefined,\r\n currency: 127,\r\n dateFormat: 2,\r\n decimalSeparator: \".\",\r\n language: undefined,\r\n nofDecimalsAmount: 2,\r\n nofDecimalsAreaM2: 2,\r\n nofDecimalsVolumeL: 3,\r\n nofDecimalsVolumeM3: 2,\r\n nofDecimalsWeightG: 1,\r\n nofDecimalsWeightKg: 3,\r\n nofSignificantDigits: 15,\r\n thousandSeparator: false,\r\n timeFormat: 1,\r\n timeFormatSecs: 4,\r\n timeZone: 5\r\n }\r\n });\r\n};\r\n\r\nconst reducer = (state, action) => {\r\n switch (action.type) {\r\n\r\n case userSettings.SET_CURRENT_LANGUAGE:\r\n return Immutable.merge(state, {\r\n currentLanguage: action.language\r\n });\r\n default:\r\n return state;\r\n }\r\n};\r\n\r\nexport default localStorageWritingReducer(reducer, defaultState, \"app_userSettings\", [\"currentLanguage\", \"currentWagon\", \"currentReceivingPoint\"]);","import * as authentication from \"../../common/actions/authentication\";\r\nimport * as customer from \"../actions/customer.js\";\r\n\r\nimport Immutable from \"seamless-immutable\";\r\n\r\nconst defaultState = () => {\r\n return Immutable({\r\n chainCustomer: null,\r\n chainId: null,\r\n customerId: \"\",\r\n customerName: \"\",\r\n email: \"\",\r\n logoImageFileName: \"\",\r\n mobile: \"\",\r\n mobile2: \"\",\r\n status: null,\r\n streetAddress: \"\",\r\n logoUrl: \"\",\r\n saving: false\r\n });\r\n};\r\n\r\n/**\r\n * View reducer\r\n * @param {Object} state\r\n * @param {{type: string}} action\r\n * @return {*}\r\n */\r\nexport default function(state = defaultState(), action) {\r\n switch(action.type) {\r\n case customer.SET_CUSTOMER_INFO:\r\n return state.merge({\r\n ...action.customerInfo\r\n });\r\n case customer.SET_CUSTOMER_LOGO:\r\n return state.merge({\r\n logoUrl: action.logoUrl\r\n });\r\n case customer.CONTACT_INFORMATION_SAVING:\r\n return state.merge({\r\n saving: true\r\n });\r\n case customer.CONTACT_INFORMATION_SAVED:\r\n return state.merge({\r\n saving: false,\r\n contact: action.contact,\r\n email: action.email,\r\n mobile: action.mobile,\r\n contact2: action.contact2,\r\n email2: action.email2,\r\n mobile2: action.mobile2\r\n });\r\n case customer.CONTACT_INFORMATION_FAILED:\r\n return state.merge({\r\n saving: false\r\n });\r\n case authentication.LOGGED_OUT:\r\n return defaultState();\r\n default:\r\n return state;\r\n }\r\n}","import * as authentication from \"../../common/actions/authentication\";\r\nimport * as customerSubscriptions from \"../actions/customerSubscriptions.js\";\r\n\r\nimport Immutable from \"seamless-immutable\";\r\n\r\nconst defaultState = () => {\r\n return Immutable({\r\n subscriptions: [\r\n // {\r\n // \"subscriptionType\": 0,\r\n // \"web\": true,\r\n // \"email\": true,\r\n // \"sms\": true\r\n // }\r\n ],\r\n mailAddressInvoice: \"\",\r\n mailAddressMonthReport: \"\",\r\n mailAddressDeliveryNote: \"\",\r\n loading: false,\r\n saving: false\r\n });\r\n};\r\n\r\n/**\r\n * Customer subscriptions reducer\r\n * @param {Object} state\r\n * @param {{type: string}} action\r\n * @return {*}\r\n */\r\nexport default function(state = defaultState(), action) {\r\n switch(action.type) {\r\n case customerSubscriptions.CUSTOMER_SUBSCRIPTIONS_LOADING:\r\n return state.merge({\r\n loading: true\r\n });\r\n case customerSubscriptions.CUSTOMER_SUBSCRIPTIONS_LOADED:\r\n return state.merge({\r\n ...action.subscriptions,\r\n loading: false\r\n });\r\n case customerSubscriptions.CUSTOMER_SUBSCRIPTIONS_FAILED:\r\n return state.merge({\r\n loading: false\r\n });\r\n case customerSubscriptions.CUSTOMER_SUBSCRIPTIONS_SAVING:\r\n return state.merge({\r\n saving: true\r\n });\r\n case customerSubscriptions.CUSTOMER_SUBSCRIPTIONS_SAVED:\r\n return state.merge({\r\n ...action.customerSubscriptions,\r\n saving: false\r\n });\r\n case customerSubscriptions.CUSTOMER_SUBSCRIPTIONS_FAILED_SAVE:\r\n return state.merge({\r\n saving: false\r\n });\r\n case authentication.LOGGED_OUT:\r\n return defaultState();\r\n default:\r\n return state;\r\n }\r\n}","import * as authentication from \"../../common/actions/authentication\";\r\nimport * as delivery from \"../actions/delivery.js\";\r\n\r\nimport Immutable from \"seamless-immutable\";\r\n\r\nconst defaultState = () => {\r\n return Immutable({\r\n lastDelivery: {\r\n loading: false,\r\n },\r\n nextDelivery: {\r\n loading: false,\r\n version: 1,\r\n },\r\n dates: {\r\n upcomingDeliveryDates: []\r\n }\r\n });\r\n};\r\n\r\n/**\r\n * View reducer\r\n * @param {Object} state\r\n * @param {{type: string}} action\r\n * @return {*}\r\n */\r\nexport default function(state = defaultState(), action) {\r\n switch(action.type) {\r\n case delivery.SET_LAST_DELIVERY:\r\n return state.merge({\r\n lastDelivery: action.delivery\r\n });\r\n case delivery.SET_LAST_DELIVERY_PRODUCT_IMAGE_URL:\r\n return state.merge({\r\n lastDelivery: {\r\n orderLines: Immutable(state.lastDelivery.orderLines).map(function(obj, index) {\r\n return (index === action.index) ? {\r\n ...obj,\r\n product: {\r\n ...obj.product,\r\n imageUrl:action.imageUrl\r\n }\r\n } : obj;\r\n })\r\n }\r\n }, {\r\n deep: true\r\n });\r\n case delivery.LOADING_LAST_DELIVERY:\r\n return state.merge({\r\n lastDelivery: {\r\n loading: action.loading,\r\n }\r\n }, {\r\n deep: true\r\n });\r\n case delivery.LOADING_NEXT_DELIVERY:\r\n return state.merge({\r\n nextDelivery: {\r\n loading: action.loading,\r\n }\r\n }, {\r\n deep: true\r\n });\r\n case delivery.SET_UPCOMING_DELIVERY_DATES:\r\n return state.merge({\r\n dates: {\r\n deliveryDates: action.deliveryDates,\r\n }\r\n }, {\r\n deep: true\r\n });\r\n case delivery.SET_NEXT_DELIVERY:\r\n return state.merge({\r\n nextDelivery: {\r\n ...action.delivery,\r\n version: state.nextDelivery.version+1,\r\n }\r\n }, {\r\n deep: true\r\n });\r\n case delivery.SET_NEXT_DELIVERY_ORDER_PRODUCT_IMAGE_URL:\r\n return state.merge({\r\n nextDelivery: {\r\n orderLines: Immutable(state.nextDelivery.orderLines).map(function(obj, index) {\r\n return (index === action.index) ? {\r\n ...obj,\r\n product: {\r\n ...obj.product,\r\n imageUrl:action.imageUrl\r\n }\r\n } : obj;\r\n })\r\n }\r\n }, {\r\n deep: true\r\n });\r\n case delivery.SET_NEXT_DELIVERY_UNCONFIRMED_ORDER_PRODUCT_IMAGE_URL:\r\n return state.merge({\r\n nextDelivery: {\r\n unConfirmedOrderLines: Immutable(state.nextDelivery.unConfirmedOrderLines).map(function(obj, index) {\r\n return (index === action.index) ? {\r\n ...obj,\r\n product: {\r\n ...obj.product,\r\n imageUrl:action.imageUrl\r\n }\r\n } : obj;\r\n })\r\n }\r\n }, {\r\n deep: true\r\n });\r\n case delivery.RESET_LAST_DELIVERY:\r\n return state.setIn([\"lastDelivery\"], {loading: false});\r\n case authentication.LOGGED_OUT:\r\n return defaultState();\r\n default:\r\n return state;\r\n }\r\n}","import * as authentication from \"../../common/actions/authentication\";\r\nimport * as getorders from \"../actions/dominosActions.js\";\r\n\r\nimport Immutable from \"seamless-immutable\";\r\n\r\nconst defaultState = () => {\r\n return Immutable({\r\n creating: false,\r\n loading: false,\r\n customers : {\r\n untreatedCustomers : [],\r\n treatedCustomers : [],\r\n },\r\n });\r\n};\r\n\r\n/**\r\n * Dominos reducer\r\n * @param {Object} state\r\n * @param {{type: string}} action\r\n * @return {*}\r\n */\r\nexport default function(state = defaultState(), action) {\r\n switch (action.type) {\r\n case getorders.SET_DOMINOS_ORDERS:\r\n return state.merge({\r\n customers: action.payload,\r\n });\r\n case getorders.SET_NO_OF_DOLLIES:\r\n {\r\n // Try to find the customer \r\n var index = state.customers.untreatedCustomers.findIndex( (c) => c.salesOrderId===action.salesOrderId);\r\n\r\n if(index !== -1)\r\n {\r\n return Immutable.setIn(state, [\"customers\",\"untreatedCustomers\", index], action.customer);\r\n } \r\n else \r\n {\r\n index = state.customers.treatedCustomers.findIndex( (c) => c.salesOrderId===action.salesOrderId);\r\n return Immutable.setIn(state, [\"customers\",\"treatedCustomers\", index], action.customer);\r\n }\r\n \r\n }\r\n case getorders.SELECT_CUSTOMER:\r\n {\r\n // Try to find the customer \r\n var indexCus = state.customers.untreatedCustomers.findIndex( (c) => c.salesOrderId===action.salesOrderId);\r\n\r\n if(indexCus !== -1)\r\n {\r\n return Immutable.setIn(state, [\"customers\",\"untreatedCustomers\", indexCus], action.customer);\r\n } \r\n else \r\n {\r\n indexCus = state.customers.treatedCustomers.findIndex( (c) => c.salesOrderId===action.salesOrderId);\r\n return Immutable.setIn(state, [\"customers\",\"treatedCustomers\", indexCus], action.customer);\r\n }\r\n \r\n }\r\n case getorders.CREATE_LABELS:\r\n return Immutable.setIn(state, [\"creating\"], action.creating);\r\n case getorders.LOADING:\r\n return Immutable.setIn(state, [\"loading\"], action.loading);\r\n case authentication.LOGGED_OUT:\r\n return defaultState();\r\n default:\r\n return state;\r\n }\r\n}\r\n","import * as authentication from \"../../common/actions/authentication\";\r\nimport * as history from \"../actions/history.js\";\r\n\r\nimport Immutable from \"seamless-immutable\";\r\n\r\nconst defaultState = () => {\r\n return Immutable({\r\n documents: {\r\n isLoading: false,\r\n allResultsLoaded: false,\r\n filter: {\r\n historyType: history.HISTORY_TYPES.ALL,\r\n searchString: \"\"\r\n },\r\n results: [],\r\n },\r\n tobacco: {\r\n loading: false,\r\n submitting: false,\r\n trySubmit: false,\r\n pickUpByEngrospartner: null,\r\n description: \"\",\r\n bagSupplier: [],\r\n unconfirmedComplaintId: null,\r\n sentToEp: false,\r\n },\r\n tobaccoDocuments: {\r\n isLoading: false,\r\n allResultsLoaded: false,\r\n filter: {\r\n searchString: \"\"\r\n },\r\n results: [],\r\n },\r\n lastInvoiceForProduct: {},\r\n claim: {\r\n claim: true,\r\n committing: false,\r\n description: \"\",\r\n lines: [],\r\n attachments: [],\r\n },\r\n invoices: {},\r\n });\r\n};\r\n\r\n/**\r\n * View reducer\r\n * @param {Object} state\r\n * @param {{type: string}} action\r\n * @return {*}\r\n */\r\nexport default function(state = defaultState(), action) {\r\n switch(action.type) {\r\n case history.EDIT_DOCUMENT_HISTORY_QUERY:\r\n return Immutable.merge(state, {\r\n documents: {\r\n ...action.change\r\n }\r\n }, {\r\n deep: true\r\n });\r\n case history.ADD_DOCUMENTS_HISTORY_QUERY_RESULTS:\r\n return Immutable.setIn(state, [\"documents\", \"results\"], state.documents.results.concat(action.results));\r\n case history.CLEAR_DOCUMENTS_HISTORY_QUERY_RESULTS:\r\n return Immutable.setIn(state, [\"documents\", \"results\"], []);\r\n case history.ADD_TOBACCO_BAG:\r\n {\r\n const supplierIndex = state.tobacco.bagSupplier.findIndex( (ele) => ele.supplierId === action.supplierId );\r\n if( supplierIndex>=0 ) {\r\n return Immutable.setIn(state, [\"tobacco\", \"bagSupplier\", supplierIndex, \"bags\"], state.tobacco.bagSupplier[supplierIndex].bags.concat({\r\n bagNumber: action.bagNumber,\r\n bagNumberValidated: action.bagNumberValidated,\r\n bagNumberEditable: action.bagNumberEditable,\r\n lines: []\r\n }));\r\n } else {\r\n return Immutable.setIn(state, [\"tobacco\", \"bagSupplier\"], state.tobacco.bagSupplier.concat({\r\n supplierName: action.supplierName,\r\n supplierId: action.supplierId,\r\n bags: [{\r\n bagNumber: action.bagNumber,\r\n bagNumberValidated: action.bagNumberValidated,\r\n bagNumberEditable: action.bagNumberEditable,\r\n lines: [],\r\n }]\r\n }));\r\n }\r\n }\r\n case history.EDIT_TOBACCO_BAG:\r\n {\r\n const supplierIndex = state.tobacco.bagSupplier.findIndex( (ele) => ele.supplierId === action.supplierId );\r\n \r\n return Immutable.setIn(state, [\"tobacco\", \"bagSupplier\", supplierIndex, \"bags\", action.bagIndex], {\r\n ...state.tobacco.bagSupplier[supplierIndex].bags[action.bagIndex],\r\n ...action.change\r\n });\r\n }\r\n case history.ADD_ITEM_TO_TOBACCO_BAG:\r\n {\r\n const supplierIndex = state.tobacco.bagSupplier.findIndex( (ele) => ele.supplierId === action.product.supplierId );\r\n const bagIndex = state.tobacco.bagSupplier[supplierIndex].bags.length-1;\r\n \r\n if( state.tobacco.bagSupplier[supplierIndex].bags[bagIndex].lines.some( (ele) => ele.product.productId===action.product.productId) ){\r\n return Immutable.setIn(state, [\"tobacco\", \"bagSupplier\", supplierIndex, \"bags\", bagIndex, \"lines\"], state.tobacco.bagSupplier[supplierIndex].bags[bagIndex].lines.map( (ele) => ele.product.productId!==action.product.productId ? ele : {\r\n product: action.product,\r\n wishedQtySalesUnits: action.value, \r\n }));\r\n } else {\r\n return Immutable.setIn(state, [\"tobacco\", \"bagSupplier\", supplierIndex, \"bags\", bagIndex, \"lines\"], state.tobacco.bagSupplier[supplierIndex].bags[bagIndex].lines.concat({\r\n product: action.product,\r\n wishedQtySalesUnits: action.value,\r\n }));\r\n }\r\n }\r\n case history.REMOVE_ITEM_FROM_TOBACCO_BAG:\r\n {\r\n const supplierIndex = state.tobacco.bagSupplier.findIndex( (ele) => ele.supplierId === action.product.supplierId );\r\n const supplierToChange = state.tobacco.bagSupplier[supplierIndex];\r\n const bagIndex = supplierToChange.bags.length-1;\r\n const bagToChange = supplierToChange.bags[bagIndex];\r\n\r\n const newLines = bagToChange.lines.filter( (ele) => ele.product.productId!==action.product.productId );\r\n\r\n if(newLines.length > 0 || bagToChange.bagNumber !== \"\")\r\n return Immutable.setIn(state, [\"tobacco\", \"bagSupplier\", supplierIndex, \"bags\", bagIndex, \"lines\"], newLines);\r\n else {\r\n\r\n // bag is empty - and no bag number is given: remove it from state if no bag number is given\r\n const newBags = supplierToChange.bags.filter(bag => bag!==bagToChange);\r\n \r\n if(newBags.length > 0) {\r\n return Immutable.setIn(state, [\"tobacco\", \"bagSupplier\", supplierIndex, \"bags\"], newBags);\r\n }\r\n else {\r\n // If last bag for supplier remove supplier as well\r\n const newSuppliers = state.tobacco.bagSupplier.filter(sup => sup!==supplierToChange);\r\n return Immutable.setIn(state, [\"tobacco\", \"bagSupplier\"], newSuppliers);\r\n }\r\n \r\n }\r\n }\r\n case history.EDIT_TOBACCO:\r\n return Immutable.merge(state, {\r\n tobacco: {\r\n ...action.change\r\n }\r\n }, {\r\n deep: true\r\n });\r\n case history.ADD_SAVEDTOBACCO_RETURN_RESULTS:\r\n return Immutable.setIn(state, [\"tobacco\"], {\r\n description: action.result.description,\r\n pickUpByEngrospartner: action.result.pickUpByEngrospartner,\r\n unconfirmedComplaintId: action.result.unconfirmedComplaintId,\r\n sentToEP: action.result.sentToEP,\r\n bagSupplier: action.result.suppliers,\r\n suppliers: state.tobacco.suppliers,\r\n });\r\n case history.SET_TOBACCO_UNCONFIRMEDCOMPLAINTID:\r\n return Immutable.setIn(state, [\"tobacco\", \"unconfirmedComplaintId\"], action.unconfirmedComplaintId);\r\n case history.CLEAR_SUPPLIER:\r\n return Immutable.setIn(state, [\"tobacco\", \"bagSupplier\"], state.tobacco.bagSupplier.filter( (ele) => ele.supplierId !== action.supplierId));\r\n case history.ADD_INVOICE_ID_TO_LIST:\r\n return Immutable.setIn(state, [\"lastInvoiceForProduct\",action.productId], action.invoiceId);\r\n case history.CLEAR_CLAIM:\r\n return Immutable.setIn(state, [\"claim\"], {\r\n claim: true,\r\n committing: false,\r\n description: \"\",\r\n lines: [],\r\n attachments: [],\r\n });\r\n case history.ADD_TO_CLAIM_SALES_UNITS:\r\n {\r\n const index = state.claim.lines.findIndex( (item) => item.product.productId === action.product.productId );\r\n if( index>=0 ) {\r\n if( state.claim.lines[index].claimQtySalesUnits==0 && state.claim.lines[index].claimQtyWarehouseUnits==0 && action.qty===0)\r\n {\r\n return Immutable.setIn(state, [\"claim\", \"lines\"], state.claim.lines.filter( (ele) => ele.product.productId!==action.product.productId ));\r\n }\r\n return Immutable.setIn(state, [\"claim\", \"lines\", index], ({\r\n ...state.claim.lines[index],\r\n product: action.product,\r\n claimQtySalesUnits: action.qty,\r\n }));\r\n } else {\r\n return Immutable.setIn(state, [\"claim\", \"lines\"], state.claim.lines.concat({\r\n product: action.product,\r\n claimQtySalesUnits: action.qty,\r\n claimQtyWarehouseUnits: 0,\r\n }));\r\n }\r\n }\r\n case history.REMOVE_FROM_CLAIM_SALES_UNITS:\r\n {\r\n const index = state.claim.lines.findIndex( (item) => item.product.productId === action.product.productId );\r\n if( state.claim.lines[index].claimQtyWarehouseUnits==0 ){\r\n return Immutable.setIn(state, [\"claim\", \"lines\"], state.claim.lines.filter( (ele) => ele.product.productId!==action.product.productId ));\r\n } else {\r\n return Immutable.setIn(state, [\"claim\", \"lines\", index], ({\r\n ...state.claim.lines[index],\r\n product: action.product,\r\n claimQtySalesUnits: 0,\r\n }));\r\n }\r\n }\r\n case history.ADD_TO_CLAIM_WAREHOUSE_UNITS:\r\n {\r\n const index = state.claim.lines.findIndex( (item) => item.product.productId === action.product.productId );\r\n if( index>=0 ) {\r\n\r\n if( state.claim.lines[index].claimQtySalesUnits==0 && state.claim.lines[index].claimQtyWarehouseUnits==0 && action.qty===0)\r\n {\r\n return Immutable.setIn(state, [\"claim\", \"lines\"], state.claim.lines.filter( (ele) => ele.product.productId!==action.product.productId ));\r\n }\r\n return Immutable.setIn(state, [\"claim\", \"lines\", index], ({\r\n ...state.claim.lines[index],\r\n product: action.product,\r\n claimQtyWarehouseUnits: action.qty,\r\n }));\r\n } else {\r\n return Immutable.setIn(state, [\"claim\", \"lines\"], state.claim.lines.concat({\r\n product: action.product,\r\n claimQtyWarehouseUnits: action.qty,\r\n claimQtySalesUnits: 0,\r\n }));\r\n }\r\n }\r\n case history.REMOVE_FROM_CLAIM_WAREHOUSE_UNITS:\r\n {\r\n const index = state.claim.lines.findIndex( (item) => item.product.productId === action.product.productId );\r\n if( state.claim.lines[index].claimQtySalesUnits==0){\r\n return Immutable.setIn(state, [\"claim\", \"lines\"], state.claim.lines.filter( (ele) => ele.product.productId!==action.product.productId ));\r\n } else {\r\n return Immutable.setIn(state, [\"claim\", \"lines\", index], ({\r\n ...state.claim.lines[index],\r\n product: action.product,\r\n claimQtyWarehouseUnits: 0,\r\n }));\r\n }\r\n }\r\n case history.EDIT_CLAIM:\r\n return Immutable.setIn(state, [\"claim\"], {\r\n ...state.claim,\r\n ...action.change,\r\n });\r\n case history.EDIT_CLAIM_ITEM:\r\n {\r\n const index = state.claim.lines.findIndex( (item) => item.product.productId === action.productId );\r\n if( index>=0 ) {\r\n return Immutable.setIn(state, [\"claim\", \"lines\", index], ({\r\n ...state.claim.lines[index],\r\n ...action.change,\r\n }));\r\n }\r\n return state;\r\n }\r\n case history.SET_INVOICE_DETAILS:\r\n return Immutable.setIn(state, [\"invoices\",action.invoiceId], action.invoice);\r\n case history.EDIT_TOBACCO_DOCUMENTS_HISTORY_QUERY:\r\n return Immutable.merge(state, {\r\n tobaccoDocuments: {\r\n ...action.change\r\n }\r\n }, {\r\n deep: true\r\n });\r\n case history.ADD_TOBACCO_DOCUMENTS_HISTORY_RESULTS:\r\n return Immutable.setIn(state, [\"tobaccoDocuments\", \"results\"], state.tobaccoDocuments.results.concat(action.results));\r\n case history.CLEAR_TOBACCO_DOCUMENTS_HISTORY_RESULTS:\r\n return Immutable.setIn(state, [\"tobaccoDocuments\", \"results\"], []);\r\n case authentication.LOGGED_OUT:\r\n return defaultState();\r\n default:\r\n return state;\r\n }\r\n}","import * as authentication from \"../../common/actions/authentication\";\r\nimport * as hubOverview from \"../actions/hubOverview.js\";\r\nimport * as hubProduction from \"../actions/hubProduction.js\";\r\n\r\nimport Immutable from \"seamless-immutable\";\r\n\r\nconst defaultState = () => {\r\n return Immutable({\r\n overview : {\r\n currentWeekProductionDates: [],\r\n nextWeekProductionDates: [],\r\n currentWeekNo : undefined,\r\n nextWeekNo: undefined,\r\n },\r\n customerProductionList : [],\r\n editedCustomer : { \r\n customerId : \"\",\r\n products : []\r\n },\r\n hubProducts : [],\r\n productsSorting: false,\r\n customersSorting: false,\r\n });\r\n};\r\n\r\n/**\r\n * Fresh food hub reducer\r\n * @param {Object} state\r\n * @param {{type: string}} action\r\n * @return {*}\r\n */\r\nexport default function(state = defaultState(), action) {\r\n switch (action.type) {\r\n case hubOverview.SET_HUB_OVERVIEW:\r\n return state.merge({\r\n overview: action.payload\r\n });\r\n case hubProduction.SET_HUB_PRODUCTION: \r\n return state.merge({\r\n customerProductionList: action.payload\r\n });\r\n case hubProduction.SET_HUB_PRODUCTS: \r\n return state.merge({\r\n hubProducts: action.payload\r\n });\r\n case hubOverview.SET_SORTING_PRODUCTS:\r\n return state.merge({\r\n productsSorting: action.sorting,\r\n }, {\r\n deep: true\r\n });\r\n case hubOverview.SET_SORTING_CUSTOMERS:\r\n return state.merge({\r\n customersSorting: action.sorting,\r\n }, {\r\n deep: true\r\n });\r\n case hubOverview.SORT_HUB_PRODUCTS:\r\n {\r\n const products = action.thisWeek ?\r\n state.overview.currentWeekProductionDates[action.dateIndex].plannedProductsForDate :\r\n state.overview.nextWeekProductionDates[action.dateIndex].plannedProductsForDate;\r\n\r\n const arr = Immutable.asMutable(products);\r\n const itemToMove = arr[action.index1];\r\n arr.splice(action.index1,1);\r\n arr.splice(action.index2,0,itemToMove);\r\n\r\n return Immutable.setIn(state, [\"overview\", action.thisWeek ? \"currentWeekProductionDates\" : \"nextWeekProductionDates\", action.dateIndex, \"plannedProductsForDate\"], arr);\r\n }\r\n case hubOverview.SORT_HUB_CUSTOMERS:\r\n {\r\n const customers = action.thisWeek ?\r\n state.overview.currentWeekProductionDates[action.dateIndex].customers :\r\n state.overview.nextWeekProductionDates[action.dateIndex].customers;\r\n\r\n const arr = Immutable.asMutable(customers);\r\n const itemToMove = arr[action.index1];\r\n arr.splice(action.index1,1);\r\n arr.splice(action.index2,0,itemToMove);\r\n\r\n return Immutable.setIn(state, [\"overview\", action.thisWeek ? \"currentWeekProductionDates\" : \"nextWeekProductionDates\", action.dateIndex, \"customers\"], arr);\r\n }\r\n case hubProduction.SET_HUB_PRODUCTION_NEW_PRODUCT:\r\n {\r\n // Try to find the customer \r\n const index = state.customerProductionList.findIndex( (cus) => cus.customerId===action.customerId);\r\n\r\n if(index !== -1)\r\n {\r\n // Add new product\r\n return Immutable.setIn(state, [\"customerProductionList\", index, \"products\"], [action.product].concat(state.customerProductionList[index].products)); \r\n }\r\n else return state;\r\n } \r\n case hubProduction.SET_HUB_PRODUCTION_NEW_CUSTOMER:\r\n return state.merge({\r\n editedCustomer : {\r\n customerId : action.customerId,\r\n products : []\r\n }\r\n }); \r\n case hubProduction.SET_HUB_PRODUCTION_NEWQTY:\r\n {\r\n // Try to find the product \r\n const index = state.editedCustomer.products.findIndex( (product) => product.productId===action.product.productId);\r\n\r\n if(index === -1)\r\n {\r\n // Add new product\r\n return Immutable.setIn(state, [\"editedCustomer\", \"products\"], [action.product].concat(state.editedCustomer.products));\r\n }\r\n else {\r\n // Update qty of existing\r\n return Immutable.setIn(state, [\"editedCustomer\", \"products\", index], action.product);\r\n }\r\n }\r\n case hubProduction.CLEAR_HUB_PRODUCTION_NEWQTY: \r\n return state.merge(\r\n {\r\n editedCustomer : { \r\n ...state.editedCustomer,\r\n products : []\r\n },\r\n },\r\n {\r\n deep: true\r\n }\r\n );\r\n // case hubProduction.SET_HUB_PRODUCTION_NEWQTY:\r\n // return state.merge({\r\n // customerProductionList: [...state.customerProductionList.map(customer => \r\n // (customer.customerId === action.customerId ? {\r\n // ...customer,\r\n // products: [customer.products.map(product => product.productId === action.productId ? {\r\n // ... product,\r\n // unconfirmedQty : action.value\r\n // } : product)]\r\n // } : customer))]\r\n // }); \r\n case authentication.LOGGED_OUT:\r\n return defaultState();\r\n default:\r\n return state;\r\n }\r\n}\r\n","import moment from \"moment\";\r\n\r\n/**\r\n * Merges product changes\r\n * @param {Object} prodInStore\r\n * @param {Object} products\r\n * @return {*}\r\n */\r\nexport function findStoreProduct(prodInStore, products) {\r\n const updatedProduct = products.find(p => p.productId === prodInStore.product.productId && p.chainId === prodInStore.product.chainId);\r\n let priceObj = {};\r\n let adminObj = {};\r\n if( updatedProduct ){\r\n priceObj = updatedProduct.futureEndPriceDate && updatedProduct.futureEndPrice ? ( \r\n moment().isSame(moment(updatedProduct.futureEndPriceDate), \"date\") ? {\r\n //the new price will be set now\r\n currentEndCusPrice: parseFloat(updatedProduct.futureEndPrice),\r\n futureEndPrice: null,\r\n futureEndPriceDate: null,\r\n } : {\r\n //the new price will be set in the future\r\n currentEndCusPrice: updatedProduct.currentEndCusPrice ? parseFloat(updatedProduct.currentEndCusPrice) : prodInStore.product.currentEndCusPrice,\r\n futureEndPrice: updatedProduct.futureEndPrice ? parseFloat(updatedProduct.futureEndPrice) : prodInStore.product.futureEndPrice,\r\n futureEndPriceDate: updatedProduct.futureEndPriceDate ? updatedProduct.futureEndPriceDate : prodInStore.product.futureEndPriceDate,\r\n }\r\n ) : {\r\n currentEndCusPrice: parseFloat(updatedProduct.currentEndCusPrice),\r\n futureEndPrice: null,\r\n futureEndPriceDate: null,\r\n };\r\n adminObj = updatedProduct.futureAdminChargeDate && updatedProduct.futureAdminCharge ? ( \r\n moment().isSame(moment(updatedProduct.futureAdminChargeDate), \"date\") ? {\r\n //the new charge will be set now\r\n adminChargePercent: parseFloat(updatedProduct.futureAdminCharge),\r\n futureAdminCharge: null,\r\n futureAdminChargeDate: null,\r\n } : {\r\n //the new charge will be set in the future\r\n adminChargePercent: updatedProduct.adminChargePercent ? parseFloat(updatedProduct.adminChargePercent) : prodInStore.product.adminChargePercent,\r\n futureAdminCharge: updatedProduct.futureAdminCharge ? parseFloat(updatedProduct.futureAdminCharge) : prodInStore.product.futureAdminCharge,\r\n futureAdminChargeDate: updatedProduct.futureAdminChargeDate ? updatedProduct.futureAdminChargeDate : prodInStore.product.futureAdminChargeDate,\r\n }\r\n ) : {\r\n adminChargePercent: parseFloat(updatedProduct.currentEndCusPrice),\r\n futureAdminCharge: null,\r\n futureAdminChargeDate: null,\r\n };\r\n }\r\n const result =\r\n updatedProduct !== undefined\r\n ? {\r\n ...prodInStore,\r\n product: {\r\n ...prodInStore.product,\r\n invoiceGroupId: updatedProduct.invoiceGroupId,\r\n invoiceGroupName: updatedProduct.invoiceGroupName ? updatedProduct.invoiceGroupName : prodInStore.product.invoiceGroupName,\r\n isAvailable: updatedProduct.isAvailable,\r\n inCatalogue: updatedProduct.inCatalogue,\r\n //\r\n ...priceObj,\r\n ...adminObj,\r\n }\r\n }\r\n : prodInStore;\r\n return result;\r\n}","import * as authentication from \"../../common/actions/authentication\";\r\nimport * as multiChainSortiment from \"../actions/multiChainSortiment.js\";\r\n\r\nimport Immutable from \"seamless-immutable\";\r\nimport {findStoreProduct} from \"../util/storeProductMerger.js\";\r\n\r\nconst defaultState = () => {\r\n return Immutable({\r\n isLoading: false,\r\n allResultsLoaded: false,\r\n resultCountString: \"0\",\r\n chainFilter: {\r\n onlyAvailableForChain: true,\r\n onlyNews: false,\r\n searchString: \"\"\r\n },\r\n chainProducts: [],\r\n newProducts: [],\r\n newProductsLoading: false,\r\n productDetails: {},\r\n invoiceGroups: [],\r\n chains: {},\r\n loadingChains: false,\r\n selected: {},\r\n });\r\n};\r\n\r\n/**\r\n * Multi chain sortiment reducer\r\n * @param {Object} state\r\n * @param {{type: string}} action\r\n * @return {*}\r\n */\r\nexport default function(state = defaultState(), action) {\r\n switch (action.type) {\r\n case multiChainSortiment.SET_MULTI_CHAIN_SORTIMENT:\r\n return state.merge({\r\n resultCountString: `${action.chainProducts.length}${state.allResultsLoaded ? \"\" : \"+\"}`,\r\n chainProducts: action.chainProducts\r\n });\r\n case multiChainSortiment.ADD_MULTI_CHAIN_SORTIMENT:\r\n return state.merge({\r\n resultCountString: `${state.chainProducts.length + action.chainProducts.length}${state.allResultsLoaded ? \"\" : \"+\"}`,\r\n chainProducts: state.chainProducts.concat(action.chainProducts)\r\n });\r\n case multiChainSortiment.UPDATE_MULTI_CHAIN_PRODUCT_LIST:\r\n return state.merge({\r\n chainProducts: state.chainProducts.map(p => findStoreProduct(p, action.products))\r\n });\r\n case multiChainSortiment.SET_QUERY_PRODUCT_IMAGE_URL:\r\n return state.merge(\r\n {\r\n chainProducts: Immutable(state.chainProducts).map(function(obj, index) {\r\n return index === action.index\r\n ? {\r\n product: {\r\n ...obj.product,\r\n imageUrl: action.imageUrl\r\n }\r\n }\r\n : obj;\r\n })\r\n },\r\n {\r\n deep: true\r\n }\r\n );\r\n case multiChainSortiment.MULTI_CHAIN_SORTIMENT_IS_LOADING:\r\n return state.merge({\r\n isLoading: true\r\n });\r\n case multiChainSortiment.MULTI_CHAIN_QUERY_DONE_LOADING:\r\n case multiChainSortiment.MULTI_CHAIN_QUERY_FAILED_LOADING:\r\n return state.merge({\r\n isLoading: false\r\n });\r\n case multiChainSortiment.MULTI_CHAIN_QUERY_ALL_LOADED:\r\n return state.merge({\r\n allResultsLoaded: true,\r\n resultCountString: state.chainProducts.length.toString()\r\n });\r\n case multiChainSortiment.EDIT_MULTI_CHAIN_FILTER:\r\n return state.merge(\r\n {\r\n allResultsLoaded: false,\r\n resultCountString: \"0\",\r\n chainFilter: {\r\n ...action.change\r\n },\r\n chainProducts: []\r\n },\r\n {\r\n deep: true\r\n }\r\n );\r\n case multiChainSortiment.CLEAR_MULTI_CHAIN_SORTIMENT:\r\n return state.merge(\r\n {\r\n chainProducts: []\r\n },\r\n {\r\n deep: true\r\n }\r\n );\r\n case multiChainSortiment.SET_MULTI_CHAIN_SORTIMENT_FILTER:\r\n return state.merge(\r\n {\r\n chainFilter: {\r\n onlyAvailableForChain: {\r\n ...action.change\r\n }\r\n }\r\n },\r\n {\r\n deep: true\r\n }\r\n );\r\n case multiChainSortiment.SET_MULTI_CHAIN_PRODUCT_DETAIL:\r\n return state.merge(\r\n {\r\n productDetails: action.productDetails\r\n },\r\n {\r\n deep: true\r\n }\r\n );\r\n case multiChainSortiment.CLEAR_MULTI_CHAIN_PRODUCT_DETAIL:\r\n return state.merge(\r\n {\r\n productDetails: {}\r\n },\r\n {\r\n deep: false\r\n }\r\n );\r\n case multiChainSortiment.SET_INVOICE_GROUPS:\r\n return state.merge(\r\n {\r\n invoiceGroups: action.invoiceGroups\r\n },\r\n {\r\n deep: true\r\n }\r\n );\r\n case multiChainSortiment.SET_QUERY_OPTION:\r\n return state.merge(\r\n {\r\n productGroups: action.productGroups,\r\n productSuppliers: action.productSuppliers\r\n },\r\n {\r\n deep: true\r\n }\r\n );\r\n case multiChainSortiment.LOADING_NEW_CHAIN_PRODUCTS:\r\n return state.merge(\r\n {\r\n newProductsLoading: action.loading\r\n },\r\n {\r\n deep: true\r\n }\r\n );\r\n case multiChainSortiment.LOADING_CHAINS:\r\n return state.merge({\r\n loadingChains: true\r\n });\r\n case multiChainSortiment.LOADED_CHAINS:\r\n return state.merge({\r\n chains: action.chains,\r\n loadingChains: false\r\n });\r\n case multiChainSortiment.LOADING_CHAINS_FAILED:\r\n return state.merge({\r\n loadingChains: false\r\n });\r\n case multiChainSortiment.SET_MULTI_SELECT:\r\n return state.merge(\r\n {\r\n selected: {\r\n ...action.change,\r\n }\r\n },\r\n {\r\n deep: true\r\n }\r\n );\r\n case multiChainSortiment.CLEAR_MULTI_SELECT:\r\n return state.setIn( [\"selected\"], {});\r\n case authentication.LOGGED_OUT:\r\n return defaultState();\r\n default:\r\n return state;\r\n }\r\n}\r\n","import * as authentication from \"../../common/actions/authentication\";\r\nimport * as multiEpixSortiment from \"../actions/multiEpixSortiment.js\";\r\n\r\nimport Immutable from \"seamless-immutable\";\r\nimport {findStoreProduct} from \"../util/storeProductMerger.js\";\r\n\r\nconst defaultState = () => {\r\n return Immutable({\r\n isLoading: false,\r\n allResultsLoaded: false,\r\n resultCountString: \"0\",\r\n chainFilter: {\r\n onlyAvailableForChain: false,\r\n onlyNews: false,\r\n searchString: \"\"\r\n },\r\n allProducts: [],\r\n newProducts: [],\r\n newProductsLoading: false,\r\n productDetail: {},\r\n invoiceGroups: []\r\n });\r\n};\r\n\r\n/**\r\n * Multi chain Epix sortiment reducer\r\n * @param {Object} state\r\n * @param {{type: string}} action\r\n * @return {*}\r\n */\r\nexport default function(state = defaultState(), action) {\r\n switch (action.type) {\r\n case multiEpixSortiment.SET_MULTI_EPIX_SORTIMENT:\r\n return state.merge({\r\n resultCountString: `${action.allProducts.length}${state.allResultsLoaded ? \"\" : \"+\"}`,\r\n allProducts: action.allProducts\r\n });\r\n case multiEpixSortiment.ADD_MULTI_EPIX_SORTIMENT:\r\n return state.merge({\r\n resultCountString: `${state.allProducts.length + action.allProducts.length}${state.allResultsLoaded ? \"\" : \"+\"}`,\r\n allProducts: state.allProducts.concat(action.allProducts)\r\n });\r\n case multiEpixSortiment.UPDATE_MULTI_EPIX_PRODUCT_LIST:\r\n return state.merge({\r\n allProducts: state.allProducts.map(p => findStoreProduct(p, action.products))\r\n });\r\n case multiEpixSortiment.SET_QUERY_PRODUCT_IMAGE_URL:\r\n return state.merge(\r\n {\r\n allProducts: Immutable(state.allProducts).map(function(obj, index) {\r\n return index === action.index\r\n ? {\r\n product: {\r\n ...obj.product,\r\n imageUrl: action.imageUrl\r\n }\r\n }\r\n : obj;\r\n })\r\n },\r\n {\r\n deep: true\r\n }\r\n );\r\n case multiEpixSortiment.MULTI_EPIX_SORTIMENT_IS_LOADING:\r\n return state.merge({\r\n isLoading: true\r\n });\r\n case multiEpixSortiment.MULTI_EPIX_QUERY_DONE_LOADING:\r\n case multiEpixSortiment.MULTI_EPIX_QUERY_FAILED_LOADING:\r\n return state.merge({\r\n isLoading: false\r\n });\r\n case multiEpixSortiment.MULTI_EPIX_QUERY_ALL_LOADED:\r\n return state.merge({\r\n allResultsLoaded: true,\r\n resultCountString: state.allProducts.length.toString()\r\n });\r\n case multiEpixSortiment.EDIT_MULTI_EPIX_FILTER:\r\n return state.merge(\r\n {\r\n allResultsLoaded: false,\r\n resultCountString: \"0\",\r\n chainFilter: {\r\n ...action.change\r\n },\r\n allProducts: []\r\n },\r\n {\r\n deep: true\r\n }\r\n );\r\n case multiEpixSortiment.CLEAR_MULTI_EPIX_SORTIMENT:\r\n return state.merge(\r\n {\r\n allProducts: []\r\n },\r\n {\r\n deep: true\r\n }\r\n );\r\n case multiEpixSortiment.SET_MULTI_EPIX_SORTIMENT_FILTER:\r\n return state.merge(\r\n {\r\n chainFilter: {\r\n onlyAvailableForChain: {\r\n ...action.change\r\n }\r\n }\r\n },\r\n {\r\n deep: true\r\n }\r\n );\r\n case multiEpixSortiment.SET_MULTI_EPIX_PRODUCT_DETAIL:\r\n return state.merge(\r\n {\r\n productDetail: action.productDetail\r\n },\r\n {\r\n deep: true\r\n }\r\n );\r\n case multiEpixSortiment.CLEAR_MULTI_EPIX_PRODUCT_DETAIL:\r\n return state.merge(\r\n {\r\n productDetail: {}\r\n },\r\n {\r\n deep: true\r\n }\r\n );\r\n case multiEpixSortiment.SET_INVOICE_GROUPS:\r\n return state.merge(\r\n {\r\n invoiceGroups: action.invoiceGroups\r\n },\r\n {\r\n deep: true\r\n }\r\n );\r\n case multiEpixSortiment.SET_QUERY_OPTION:\r\n return state.merge(\r\n {\r\n productGroups: action.productGroups,\r\n productSuppliers: action.productSuppliers\r\n },\r\n {\r\n deep: true\r\n }\r\n );\r\n case multiEpixSortiment.LOADING_NEW_EPIX_PRODUCTS:\r\n return state.merge(\r\n {\r\n newProductsLoading: action.loading\r\n },\r\n {\r\n deep: true\r\n }\r\n );\r\n case authentication.LOGGED_OUT:\r\n return defaultState();\r\n default:\r\n return state;\r\n }\r\n}\r\n","import * as authentication from \"../actions/authentication\";\r\nimport * as notifications from \"../actions/notifications\";\r\n\r\nimport Immutable from \"seamless-immutable\";\r\n\r\nconst defaultState = () => Immutable({\r\n notifications: {\r\n // [{\r\n // \"notificationId\": 0,\r\n // \"fromDate\": \"2019-09-10T12:46:05.744Z\",\r\n // \"toDate\": \"2019-09-10T12:46:05.744Z\",\r\n // \"subject\": \"string\",\r\n // \"body\": \"string\",\r\n // \"displayPopup\": true,\r\n // \"priority\": 0,\r\n // \"confirmedDate\": \"2019-09-10T12:46:05.744Z\",\r\n // \"recipientType\": 0\r\n // }]\r\n },\r\n loading: false\r\n});\r\n\r\n/**\r\n * \r\n * @param {Object} state \r\n * @param {{type: String}} action \r\n * @returns {Object}\r\n */\r\nexport default function(state = defaultState(), action) {\r\n switch (action.type) {\r\n case notifications.NOTIFICATIONS_LOADING:\r\n return state.merge({\r\n loading: true\r\n });\r\n case notifications.NOTIFICATIONS_LOADED:\r\n return state.merge({\r\n loading: false,\r\n notifications: action.notifications\r\n }, {\r\n deep: true\r\n });\r\n case notifications.NOTIFICATIONS_FAILED_TO_LOAD:\r\n return state.merge({\r\n loading: false\r\n });\r\n case notifications.NOTIFICATION_UPDATE_CONFIRMED_DATE:\r\n return state.merge({\r\n notifications: {\r\n [action.notificationId]: {\r\n confirmedDate: action.date,\r\n dismissedOnClient: true\r\n }\r\n }\r\n }, {\r\n deep: true\r\n });\r\n case notifications.NOTIFICATION_DISMISSED:\r\n return state.merge({\r\n notifications: {\r\n [action.notificationId]: {\r\n dismissedOnClient: true\r\n }\r\n }\r\n }, {\r\n deep: true\r\n });\r\n case authentication.LOGGED_OUT:\r\n return defaultState();\r\n default:\r\n return state;\r\n }\r\n}","import * as authentication from \"../../common/actions/authentication\";\r\nimport * as order from \"../actions/order.js\";\r\n\r\nimport Immutable from \"seamless-immutable\";\r\n\r\nconst defaultState = () => {\r\n return Immutable({\r\n active: {\r\n loading: false,\r\n submitting: false,\r\n shipmentId: null,\r\n distributionRouteId: \"\",\r\n deliveryDate: \"\",\r\n },\r\n productView: {\r\n view: \"item\",\r\n category: \"all\"\r\n },\r\n orderFeeLimits: [],\r\n orderVolumeDiscounts: [],\r\n freshFoodTemplateData : \r\n {\r\n products: [],\r\n freshFoodProducts: [],\r\n }\r\n });\r\n};\r\n\r\n/**\r\n * View reducer\r\n * @param {Object} state\r\n * @param {{type: string}} action\r\n * @return {*}\r\n */\r\nexport default function(state = defaultState(), action) {\r\n switch(action.type) {\r\n case order.SET_PRODUCT_ORDER_VIEW:\r\n return state.merge({\r\n productView:{\r\n view: action.value\r\n }\r\n });\r\n case order.SET_ORDER_FEE_LIMITS:\r\n return Immutable.setIn(state, [\"orderFeeLimits\"], action.orderFeeLimits);\r\n case order.SET_ORDER_VOLUME_DISCOUNTS:\r\n return Immutable.setIn(state, [\"orderVolumeDiscounts\"], action.orderVolumeDiscounts);\r\n case order.SET_ACTIVE_ORDER:\r\n return state.merge({\r\n active: {\r\n ...action.activeOrder,\r\n }\r\n });\r\n case order.MERGE_ACTIVE_ORDER:\r\n return state.merge({\r\n active: {\r\n ...state.active,\r\n ...action.activeOrderChange,\r\n }\r\n });\r\n case order.ADD_TO_UNCONFIRMED_ORDER:\r\n if( state.active.unConfirmedOrderLines ){\r\n return Immutable.setIn(state, [\"active\",\"unConfirmedOrderLines\"], [action.line].concat(state.active.unConfirmedOrderLines));\r\n } else {\r\n return Immutable.setIn(state, [\"active\",\"unConfirmedOrderLines\"], [action.line]);\r\n }\r\n case order.REMOVE_FROM_UNCONFIRMED_ORDER:\r\n return Immutable.setIn(state, [\"active\",\"unConfirmedOrderLines\"], Immutable(state.active.unConfirmedOrderLines).filter( (item) => item.product.productId!==action.productId));\r\n case order.UPDATE_UNCONFIRMED_ORDER_LINE:\r\n return Immutable.setIn(state, [\"active\",\"unConfirmedOrderLines\",state.active.unConfirmedOrderLines.findIndex( (item) => item.productId===action.productId)], action.line);\r\n case order.SET_UNCONFIRMED_ORDER_LINE_INFO:\r\n {\r\n const index = state.active.unConfirmedOrderLines ? state.active.unConfirmedOrderLines.findIndex( (item) => item.productId===action.productId) : -1;\r\n return Immutable.setIn(state, [\"active\",\"unConfirmedOrderLines\",index], {\r\n ...action.line,\r\n orderedQty: state.active.unConfirmedOrderLines[index].orderedQty,//we are only updating information\r\n });\r\n }\r\n case order.SET_UNCONFIRMED_ORDER_LINE_LOADING:\r\n {\r\n const index = state.active.unConfirmedOrderLines ? state.active.unConfirmedOrderLines.findIndex( (item) => item.productId===action.productId) : -1;\r\n return Immutable.setIn(state, [\"active\",\"unConfirmedOrderLines\",index,\"loading\"], action.loading);\r\n }\r\n case order.SET_ACTIVE_ORDERED_IMAGE_URL:\r\n return state.merge({\r\n active:{\r\n orderLines: Immutable(state.active.orderLines).map(function(obj, index) {\r\n return (index === action.index) ? {\r\n ...obj,\r\n product: {\r\n ...obj.product,\r\n imageUrl:action.imageUrl\r\n }\r\n } : obj;\r\n })\r\n }\r\n }, {\r\n deep: true\r\n });\r\n case order.SET_ACTIVE_ORDER_LOADING:\r\n return state.merge({\r\n active:{\r\n loading: action.loading,\r\n }\r\n }, {\r\n deep: true\r\n });\r\n case order.SET_ACTIVE_ORDER_SUBMITTING:\r\n return state.merge({\r\n active:{\r\n submitting: action.submitting,\r\n }\r\n }, {\r\n deep: true\r\n });\r\n case order.SET_ACTIVE_UNCONFIRMEDORDER_IMAGE_URL:\r\n return state.merge({\r\n active:{\r\n unConfirmedOrderLines: Immutable(state.active.unConfirmedOrderLines).map(function(obj, index) {\r\n return (index === action.index) ? {\r\n ...obj,\r\n product: {\r\n ...obj.product,\r\n imageUrl:action.imageUrl\r\n }\r\n } : obj;\r\n })\r\n }\r\n }, {\r\n deep: true\r\n });\r\n case order.SET_FRESHFOOD_TEMPLATE:\r\n return state.merge({\r\n freshFoodTemplateData: action.templateData\r\n });\r\n case order.SET_FRESHFOOD_TEMPLATE_UPDATED:\r\n return state.merge({\r\n freshFoodTemplateData: {\r\n products: Immutable(state.freshFoodTemplateData.products).map(function(prd) {\r\n return (prd.productId === action.product.productId) ? action.product : prd;\r\n })\r\n }\r\n }, {\r\n deep: true\r\n });\r\n case authentication.LOGGED_OUT:\r\n return defaultState();\r\n default:\r\n return state;\r\n }\r\n}","import * as authentication from \"../../common/actions/authentication\";\r\nimport * as productImage from \"../actions/productImage.js\";\r\n\r\nimport Immutable from \"seamless-immutable\";\r\n\r\nconst defaultState = () => {\r\n return Immutable({\r\n });\r\n};\r\n\r\n/**\r\n * productImage reducer\r\n * @param {Object} state\r\n * @param {{type: string}} action\r\n * @return {*}\r\n */\r\nexport default function(state = defaultState(), action) {\r\n switch(action.type) {\r\n case productImage.PRODUCT_IMAGE_IS_LOADING:\r\n return state.merge({\r\n [action.productId]: {\r\n loading: true,\r\n imageUrl: \"\",\r\n }\r\n });\r\n case productImage.PRODUCT_IMAGE_DONE_LOADING:\r\n return state.merge({\r\n [action.productId]: {\r\n loading: false,\r\n imageUrl: action.imageUrl,\r\n }\r\n });\r\n case productImage.PRODUCT_IMAGE_FAILED_LOADING:\r\n return state.merge({\r\n [action.productId]: {\r\n loading: false,\r\n imageUrl: \"\",\r\n }\r\n });\r\n case authentication.LOGGED_OUT:\r\n return defaultState();\r\n default:\r\n return state;\r\n }\r\n}","import * as authentication from \"../../common/actions/authentication\";\r\nimport * as productLists from \"../actions/productLists.js\";\r\n\r\nimport Immutable from \"seamless-immutable\";\r\nimport {postFix} from \"../../common/util/changeUtils.jsx\";\r\n\r\nconst defaultState = () => {\r\n return Immutable({\r\n campaignProductsLoading: false,\r\n newProductsLoading: false,\r\n boughtProductsLoading: false,\r\n customListsLoading: false,\r\n customListUploading: false,\r\n customListDownloadingPdf: false,\r\n customListsSorting: false,\r\n campaignProducts: [],\r\n newProducts: [],\r\n boughtProducts: [],\r\n customLists: [],\r\n campaigns:[],\r\n });\r\n};\r\n\r\n/**\r\n * View reducer\r\n * @param {Object} state\r\n * @param {{type: string}} action\r\n * @return {*}\r\n */\r\nexport default function(state = defaultState(), action) {\r\n switch(action.type) {\r\n case productLists.LOADING_CAMPAIGN:\r\n return state.merge({\r\n campaignProductsLoading: action.loading,\r\n }, {\r\n deep: true\r\n });\r\n case productLists.SET_CAMPAIGN_PRODUCTS:\r\n return state.merge({\r\n campaignProducts: action.products\r\n }, {\r\n deep: true\r\n });\r\n case productLists.SET_CAMPAIGNS:\r\n return state.merge({\r\n campaigns: [\r\n ...action.campaigns,\r\n ]\r\n }, {\r\n deep: true\r\n });\r\n case productLists.SET_CAMPAIGN_PRODUCT_IMAGE_URL:\r\n return state.merge({\r\n campaignProducts: Immutable(state.campaignProducts).map(function(obj, index) {\r\n return (index === action.index) ? {\r\n ...obj,\r\n product: {\r\n ...obj.product,\r\n imageUrl:action.imageUrl\r\n }\r\n } : obj;\r\n })\r\n }, {\r\n deep: true\r\n });\r\n case productLists.LOADING_NEW_PRODUCTS:\r\n return state.merge({\r\n newProductsLoading: action.loading,\r\n }, {\r\n deep: true\r\n });\r\n case productLists.SET_NEW_PRODUCTS:\r\n return state.merge({\r\n newProducts: action.products\r\n }, {\r\n deep: true\r\n });\r\n case productLists.SET_NEW_PRODUCT_IMAGE_URL:\r\n return state.merge({\r\n newProducts: Immutable(state.newProducts).map(function(obj, index) {\r\n return (index === action.index) ? {\r\n ...obj,\r\n product: {\r\n ...obj.product,\r\n imageUrl:action.imageUrl\r\n }\r\n } : obj;\r\n })\r\n }, {\r\n deep: true\r\n });\r\n case productLists.LOADING_BOUGHT_PRODUCTS:\r\n return state.merge({\r\n boughtProductsLoading: action.loading,\r\n }, {\r\n deep: true\r\n });\r\n case productLists.SET_BOUGHT_PRODUCTS:\r\n return state.merge({\r\n boughtProducts: action.products\r\n }, {\r\n deep: true\r\n });\r\n case productLists.LOADING_MY_LISTS:\r\n return state.merge({\r\n customListsLoading: action.loading,\r\n }, {\r\n deep: true\r\n });\r\n case productLists.UPLOADING_MY_LIST:\r\n return state.merge({\r\n customListUploading: action.uploading,\r\n }, {\r\n deep: true\r\n });\r\n case productLists.DOWNLOADING_MY_LIST_PDF:\r\n return state.merge({\r\n customListDownloadingPdf: action.downloading,\r\n }, {\r\n deep: true\r\n });\r\n case productLists.SET_MY_LISTS:\r\n return state.merge({\r\n customLists: [\r\n ...action.lists,\r\n {\r\n myListId: -1,\r\n name: \"\",\r\n lines: [],\r\n [`lines${postFix}`]: [],\r\n }\r\n ]\r\n }, {\r\n deep: true\r\n });\r\n case productLists.SET_MY_LIST_PRODUCT_IMAGE_URL:\r\n return state.merge({\r\n customLists: Immutable(state.customLists).map(function(obj, index) {\r\n return (index === action.listIndex) ? {\r\n ...obj,\r\n lines: Immutable(obj.lines).map(function(obj, index) {\r\n return (index === action.itemIndex) ? {\r\n ...obj,\r\n product: {\r\n ...obj.product,\r\n imageUrl: action.imageUrl,\r\n }\r\n } : obj;\r\n }),\r\n [`lines${postFix}`]: Immutable(obj[`lines${postFix}`]).map(function(obj, index) {\r\n return (index === action.itemIndex) ? {\r\n ...obj,\r\n product: {\r\n ...obj.product,\r\n imageUrl: action.imageUrl,\r\n }\r\n } : obj;\r\n }),\r\n } : obj;\r\n })\r\n }, {\r\n deep: true\r\n });\r\n case productLists.SWAP_REPLACEMENT_IN_MY_LIST:\r\n return state.merge({\r\n customLists: Immutable(state.customLists).map(function(obj) {\r\n return (obj.myListId === action.listId) ? {\r\n ...obj,\r\n [`lines${postFix}`]: Immutable(obj[`lines${postFix}`]).map(function(obj) {\r\n return (obj.productId === action.replacedProductId) ? {\r\n ...obj,\r\n productId: action.replacementProductId,\r\n replacedProduct: null,\r\n product: {\r\n ...obj.replacedProduct,\r\n }\r\n } : obj;\r\n }),\r\n } : obj;\r\n })\r\n }, {\r\n deep: true\r\n });\r\n case productLists.EDIT_MY_LIST:\r\n return state.merge({\r\n customLists: Immutable(state.customLists).map(function(obj) {\r\n return (obj.myListId === action.listId) ? {\r\n ...obj,\r\n ...action.change,\r\n } : obj;\r\n })\r\n }, {\r\n deep: true\r\n });\r\n case productLists.ADD_TO_MY_LISTS:\r\n return state.merge({\r\n customLists: Immutable(state.customLists).map(function(obj) {\r\n return (obj.myListId === action.listId) ? {\r\n ...obj,\r\n [`lines${postFix}`]: obj[`lines${postFix}`].some((ele) => ele.productId===action.item.productId) ? obj[`lines${postFix}`] :\r\n obj[`lines${postFix}`].concat({\r\n ...action.item,\r\n }),\r\n } : obj;\r\n })\r\n }, {\r\n deep: true\r\n });\r\n case productLists.ADD_NEW_MYLIST:\r\n return state.merge({\r\n customLists: state.customLists.concat(action.listItem)\r\n }, {\r\n deep: true\r\n });\r\n case productLists.REMOVE_FROM_MY_LISTS:\r\n return state.merge({\r\n customLists: Immutable(state.customLists).map(function(obj) {\r\n return (obj.myListId === action.listId) ? {\r\n ...obj,\r\n [`lines${postFix}`]: obj[`lines${postFix}`].filter((ele) => ele.productId!==action.productId)\r\n } : obj;\r\n }),\r\n }, {\r\n deep: true\r\n });\r\n case productLists.DELETE_MYLIST:\r\n return state.merge({\r\n customLists: Immutable(state.customLists).filter((ele) => ele.myListId!==action.myListId),\r\n }, {\r\n deep: true\r\n });\r\n case productLists.MOVE_FROM_TO_MY_LIST:\r\n {\r\n return state.merge({\r\n customLists: Immutable(state.customLists).map(function(obj) {\r\n if(obj.myListId === action.listId){\r\n const arr = Immutable.asMutable(obj[`lines${postFix}`]);\r\n const itemToMove = arr[action.index1];\r\n arr.splice(action.index1,1);\r\n arr.splice(action.index2,0,itemToMove);\r\n return {\r\n ...obj,\r\n [`lines${postFix}`]: arr,\r\n };\r\n } else {\r\n return obj;\r\n }\r\n })\r\n }, {\r\n deep: true\r\n });\r\n }\r\n case productLists.SET_SORTING_MY_LISTS:\r\n return state.merge({\r\n customListsSorting: action.sorting,\r\n }, {\r\n deep: true\r\n });\r\n case productLists.SORT_MY_LISTS:\r\n {\r\n const arr = Immutable.asMutable(state.customLists);\r\n const itemToMove = arr[action.index1];\r\n arr.splice(action.index1,1);\r\n arr.splice(action.index2,0,itemToMove);\r\n\r\n return Immutable.setIn(state, [\"customLists\"], arr);\r\n }\r\n case productLists.FIX_CHANGES_MYLIST:\r\n return state.merge({\r\n customLists: Immutable(state.customLists).map(function(obj) {\r\n if(obj.myListId === action.listId){\r\n return {\r\n ...obj,\r\n name: obj[`name${postFix}`] ? obj[`name${postFix}`] : obj.name,\r\n lines: obj[`lines${postFix}`] ? obj[`lines${postFix}`] : obj.lines,\r\n };\r\n } else {\r\n return obj;\r\n }\r\n })\r\n }, {\r\n deep: true\r\n });\r\n case productLists.CLEAR_CHANGES_MYLIST:\r\n return state.merge({\r\n customLists: Immutable(state.customLists).map(function(obj) {\r\n return {\r\n ...obj,\r\n [`name${postFix}`]: obj.name,\r\n [`lines${postFix}`]: obj.lines,\r\n };\r\n })\r\n }, {\r\n deep: true\r\n });\r\n case authentication.LOGGED_OUT:\r\n return defaultState();\r\n default:\r\n return state;\r\n }\r\n}","import * as authentication from \"../../common/actions/authentication\";\r\nimport * as productQuery from \"../actions/productQuery.js\";\r\n\r\nimport Immutable from \"seamless-immutable\";\r\n\r\nconst defaultState = () => {\r\n return Immutable({\r\n isLoading: false,\r\n allResaultsLoaded: false,\r\n resaultCountString: \"0\",\r\n filter: {\r\n searchString: \"\",\r\n ReturnTobacco: false,\r\n },\r\n resaults: [],\r\n });\r\n};\r\n\r\n/**\r\n * productQuery reducer\r\n * @param {Object} state\r\n * @param {{type: string}} action\r\n * @return {*}\r\n */\r\nexport default function(state = defaultState(), action) {\r\n switch(action.type) {\r\n case productQuery.SET_QUERY_RESAULTS:\r\n return state.merge({\r\n resaultCountString: `${action.resaults.length}${state.allResaultsLoaded?\"\":\"+\"}`,\r\n resaults: action.resaults\r\n });\r\n case productQuery.ADD_QUERY_RESAULTS:\r\n {\r\n const arr = Immutable.asMutable(state.resaults);\r\n arr.splice(action.startIndex, arr.length-action.startIndex, ...action.resaults);\r\n return state.merge({\r\n resaultCountString: `${action.startIndex+action.resaults.length}${state.allResaultsLoaded?\"\":\"+\"}`,\r\n resaults: arr,\r\n });\r\n }\r\n case productQuery.SET_QUERY_PRODUCT_IMAGE_URL:\r\n return state.merge({\r\n resaults: Immutable(state.resaults).map(function(obj, index) {\r\n return (index === action.index) ? {\r\n product:{\r\n ...obj.product,\r\n imageUrl:action.imageUrl,\r\n }\r\n } : obj;\r\n })\r\n }, {\r\n deep: true\r\n });\r\n case productQuery.QUERY_IS_LOADING:\r\n return state.merge({\r\n isLoading: true,\r\n });\r\n case productQuery.QUERY_DONE_LOADING:\r\n case productQuery.QUERY_FAILED_LOADING:\r\n return state.merge({\r\n isLoading: false,\r\n });\r\n case productQuery.QUERY_ALL_RESAULTS_LOADED:\r\n return state.merge({\r\n allResaultsLoaded: true,\r\n resaultCountString: state.resaults.length.toString(),\r\n });\r\n case productQuery.EDIT_QUERY_FILTER:\r\n return state.merge({\r\n allResaultsLoaded: false,\r\n resaultCountString: \"0\",\r\n filter:{\r\n ...action.change\r\n },\r\n resaults: []\r\n }, {\r\n deep: true\r\n });\r\n case productQuery.CLEAR_QUERY_RESAULTS:\r\n return state.merge({\r\n resaults: []\r\n }, {\r\n deep: true\r\n });\r\n case productQuery.SET_QUERY_OPTION:\r\n return state.merge({\r\n productGroups: action.productGroups,\r\n productSuppliers: action.productSuppliers,\r\n }, {\r\n deep: true\r\n });\r\n case authentication.LOGGED_OUT:\r\n return defaultState();\r\n default:\r\n return state;\r\n }\r\n}","import * as authentication from \"../../common/actions/authentication\";\r\nimport * as singleChainSortiment from \"../actions/singleChainSortiment.js\";\r\n\r\nimport Immutable from \"seamless-immutable\";\r\nimport {findStoreProduct} from \"../util/storeProductMerger.js\";\r\n\r\nconst defaultState = () => {\r\n return Immutable({\r\n isLoading: false,\r\n allResultsLoaded: false,\r\n resultCountString: \"0\",\r\n chainFilter: {\r\n onlyAvailableForChain: true,\r\n onlyNews: false,\r\n searchString: \"\"\r\n },\r\n chainProducts: [],\r\n newProducts: [],\r\n newProductsLoading: false,\r\n productDetail: {},\r\n invoiceGroups: [],\r\n selected: {},\r\n });\r\n};\r\n\r\n/**\r\n * Single chain sortiment reducer\r\n * @param {Object} state\r\n * @param {{type: string}} action\r\n * @return {*}\r\n */\r\nexport default function(state = defaultState(), action) {\r\n switch (action.type) {\r\n case singleChainSortiment.SET_SINGLE_CHAIN_SORTIMENT:\r\n return state.merge({\r\n resultCountString: `${action.chainProducts.length}${state.allResultsLoaded ? \"\" : \"+\"}`,\r\n chainProducts: action.chainProducts\r\n });\r\n case singleChainSortiment.ADD_SINGLE_CHAIN_SORTIMENT:\r\n return state.merge({\r\n resultCountString: `${state.chainProducts.length + action.chainProducts.length}${state.allResultsLoaded ? \"\" : \"+\"}`,\r\n chainProducts: state.chainProducts.concat(action.chainProducts)\r\n });\r\n case singleChainSortiment.UPDATE_SINGLE_CHAIN_PRODUCT_LIST:\r\n return state.merge({\r\n chainProducts: state.chainProducts.map(p => findStoreProduct(p, action.products))\r\n });\r\n case singleChainSortiment.SET_QUERY_PRODUCT_IMAGE_URL:\r\n return state.merge(\r\n {\r\n chainProducts: Immutable(state.chainProducts).map(function(obj, index) {\r\n return index === action.index\r\n ? {\r\n product: {\r\n ...obj.product,\r\n imageUrl: action.imageUrl\r\n }\r\n }\r\n : obj;\r\n })\r\n },\r\n {\r\n deep: true\r\n }\r\n );\r\n case singleChainSortiment.SINGLE_CHAIN_SORTIMENT_IS_LOADING:\r\n return state.merge({\r\n isLoading: true\r\n });\r\n case singleChainSortiment.SINGLE_CHAIN_QUERY_DONE_LOADING:\r\n case singleChainSortiment.SINGLE_CHAIN_QUERY_FAILED_LOADING:\r\n return state.merge({\r\n isLoading: false\r\n });\r\n case singleChainSortiment.SINGLE_CHAIN_QUERY_ALL_LOADED:\r\n return state.merge({\r\n allResultsLoaded: true,\r\n resultCountString: state.chainProducts.length.toString()\r\n });\r\n case singleChainSortiment.EDIT_SINGLE_CHAIN_FILTER:\r\n return state.merge(\r\n {\r\n allResultsLoaded: false,\r\n resultCountString: \"0\",\r\n chainFilter: {\r\n ...action.change\r\n },\r\n chainProducts: []\r\n },\r\n {\r\n deep: true\r\n }\r\n );\r\n case singleChainSortiment.CLEAR_SINGLE_CHAIN_SORTIMENT:\r\n return state.merge(\r\n {\r\n chainProducts: []\r\n },\r\n {\r\n deep: true\r\n }\r\n );\r\n case singleChainSortiment.SET_SINGLE_CHAIN_SORTIMENT_FILTER:\r\n return state.merge(\r\n {\r\n chainFilter: {\r\n onlyAvailableForChain: {\r\n ...action.change\r\n }\r\n }\r\n },\r\n {\r\n deep: true\r\n }\r\n );\r\n case singleChainSortiment.SET_SINGLE_CHAIN_PRODUCT_DETAIL:\r\n return state.merge(\r\n {\r\n productDetail: action.productDetail\r\n },\r\n {\r\n deep: true\r\n }\r\n );\r\n case singleChainSortiment.CLEAR_SINGLE_CHAIN_PRODUCT_DETAIL:\r\n return state.merge(\r\n {\r\n productDetail: {}\r\n },\r\n {\r\n deep: true\r\n }\r\n );\r\n case singleChainSortiment.SET_INVOICE_GROUPS:\r\n return state.merge(\r\n {\r\n invoiceGroups: action.invoiceGroups\r\n },\r\n {\r\n deep: true\r\n }\r\n );\r\n case singleChainSortiment.SET_QUERY_OPTION:\r\n return state.merge(\r\n {\r\n productGroups: action.productGroups,\r\n productSuppliers: action.productSuppliers\r\n },\r\n {\r\n deep: true\r\n }\r\n );\r\n case singleChainSortiment.SET_MULTI_SELECT:\r\n return state.merge(\r\n {\r\n selected: {\r\n ...action.change,\r\n }\r\n },\r\n {\r\n deep: true\r\n }\r\n );\r\n case singleChainSortiment.CLEAR_MULTI_SELECT:\r\n return state.setIn( [\"selected\"], {});\r\n case authentication.LOGGED_OUT:\r\n return defaultState();\r\n default:\r\n return state;\r\n }\r\n}\r\n","import * as authentication from \"../../common/actions/authentication\";\r\nimport * as singleEpixSortiment from \"../actions/singleEpixSortiment.js\";\r\n\r\nimport Immutable from \"seamless-immutable\";\r\nimport {findStoreProduct} from \"../util/storeProductMerger.js\";\r\n\r\nconst defaultState = () => {\r\n return Immutable({\r\n isLoading: false,\r\n allResultsLoaded: false,\r\n resultCountString: \"0\",\r\n chainFilter: {\r\n chainType: 5,\r\n onlyAvailableForChain: false,\r\n onlyNews: false,\r\n searchString: \"\"\r\n },\r\n allProducts: [],\r\n newProducts: [],\r\n newProductsLoading: false,\r\n productDetail: {},\r\n invoiceGroups: []\r\n });\r\n};\r\n\r\n/**\r\n * Single chain Epix sortiment reducer\r\n * @param {Object} state\r\n * @param {{type: string}} action\r\n * @return {*}\r\n */\r\nexport default function(state = defaultState(), action) {\r\n switch (action.type) {\r\n case singleEpixSortiment.SET_SINGLE_EPIX_SORTIMENT:\r\n return state.merge({\r\n resultCountString: `${action.allProducts.length}${state.allResultsLoaded ? \"\" : \"+\"}`,\r\n allProducts: action.allProducts\r\n });\r\n case singleEpixSortiment.ADD_SINGLE_EPIX_SORTIMENT:\r\n return state.merge({\r\n resultCountString: `${state.allProducts.length + action.allProducts.length}${state.allResultsLoaded ? \"\" : \"+\"}`,\r\n allProducts: state.allProducts.concat(action.allProducts)\r\n });\r\n case singleEpixSortiment.UPDATE_SINGLE_EPIX_PRODUCT_LIST:\r\n return state.merge({\r\n allProducts: state.allProducts.map(p => findStoreProduct(p, action.products))\r\n });\r\n case singleEpixSortiment.SET_QUERY_PRODUCT_IMAGE_URL:\r\n return state.merge(\r\n {\r\n allProducts: Immutable(state.allProducts).map(function(obj, index) {\r\n return index === action.index\r\n ? {\r\n product: {\r\n ...obj.product,\r\n imageUrl: action.imageUrl\r\n }\r\n }\r\n : obj;\r\n })\r\n },\r\n {\r\n deep: true\r\n }\r\n );\r\n case singleEpixSortiment.SINGLE_EPIX_SORTIMENT_IS_LOADING:\r\n return state.merge({\r\n isLoading: true\r\n });\r\n case singleEpixSortiment.SINGLE_EPIX_QUERY_DONE_LOADING:\r\n case singleEpixSortiment.SINGLE_EPIX_QUERY_FAILED_LOADING:\r\n return state.merge({\r\n isLoading: false\r\n });\r\n case singleEpixSortiment.SINGLE_EPIX_QUERY_ALL_LOADED:\r\n return state.merge({\r\n allResultsLoaded: true,\r\n resultCountString: state.allProducts.length.toString()\r\n });\r\n case singleEpixSortiment.EDIT_SINGLE_EPIX_FILTER:\r\n return state.merge(\r\n {\r\n allResultsLoaded: false,\r\n resultCountString: \"0\",\r\n chainFilter: {\r\n ...action.change\r\n },\r\n allProducts: []\r\n },\r\n {\r\n deep: true\r\n }\r\n );\r\n case singleEpixSortiment.CLEAR_SINGLE_EPIX_SORTIMENT:\r\n return state.merge(\r\n {\r\n allProducts: []\r\n },\r\n {\r\n deep: true\r\n }\r\n );\r\n case singleEpixSortiment.SET_SINGLE_EPIX_SORTIMENT_FILTER:\r\n return state.merge(\r\n {\r\n chainFilter: {\r\n onlyAvailableForChain: {\r\n ...action.change\r\n }\r\n }\r\n },\r\n {\r\n deep: true\r\n }\r\n );\r\n case singleEpixSortiment.SET_SINGLE_EPIX_PRODUCT_DETAIL:\r\n return state.merge(\r\n {\r\n productDetail: action.productDetail\r\n },\r\n {\r\n deep: true\r\n }\r\n );\r\n case singleEpixSortiment.CLEAR_SINGLE_EPIX_PRODUCT_DETAIL:\r\n return state.merge(\r\n {\r\n productDetail: {}\r\n },\r\n {\r\n deep: true\r\n }\r\n );\r\n case singleEpixSortiment.SET_INVOICE_GROUPS:\r\n return state.merge(\r\n {\r\n invoiceGroups: action.invoiceGroups\r\n },\r\n {\r\n deep: true\r\n }\r\n );\r\n case singleEpixSortiment.SET_QUERY_OPTION:\r\n return state.merge(\r\n {\r\n productGroups: action.productGroups,\r\n productSuppliers: action.productSuppliers\r\n },\r\n {\r\n deep: true\r\n }\r\n );\r\n case authentication.LOGGED_OUT:\r\n return defaultState();\r\n default:\r\n return state;\r\n }\r\n}\r\n","import * as authentication from \"../../common/actions/authentication\";\r\nimport * as support from \"../actions/support.js\";\r\n\r\nimport Immutable from \"seamless-immutable\";\r\n\r\nconst defaultState = () => {\r\n return Immutable({\r\n isLoading: false,\r\n faq: [],\r\n message: {},\r\n });\r\n};\r\n\r\n/**\r\n * support reducer\r\n * @param {Object} state\r\n * @param {{type: string}} action\r\n * @return {*}\r\n */\r\nexport default function(state = defaultState(), action) {\r\n switch(action.type) {\r\n case support.SET_FAQ_RESULTS:\r\n return state.merge({\r\n faq: action.results\r\n });\r\n case support.FAQ_IS_LOADING:\r\n return state.merge({\r\n isLoading: true,\r\n });\r\n case support.FAQ_DONE_LOADING:\r\n case support.FAQ_FAILED_LOADING:\r\n return state.merge({\r\n isLoading: false,\r\n });\r\n case support.CHANGE_SUPPORT_MESSAGE:\r\n return state.merge({\r\n message: {\r\n ...action.change\r\n }\r\n }, {\r\n deep: true\r\n });\r\n case support.CLEAR_SUPPORT_MESSAGE:\r\n return state.merge({\r\n message: {}\r\n });\r\n case authentication.LOGGED_OUT:\r\n return defaultState();\r\n default:\r\n return state;\r\n }\r\n}\r\n","import * as authentication from \"../actions/authentication\";\r\nimport * as systemMessage from \"../actions/systemMessage\";\r\n\r\nimport Immutable from \"seamless-immutable\";\r\n\r\nconst defaultState = () => Immutable({\r\n counter: 0,\r\n messages: [],\r\n});\r\n\r\n/**\r\n * \r\n * @param {Object} state \r\n * @param {{type: String}} action \r\n * @returns {Object}\r\n */\r\nexport default function(state = defaultState(), action) {\r\n switch (action.type) {\r\n case systemMessage.PUSH_MESSAGE:\r\n return state.merge({\r\n counter: state.counter+1,\r\n messages: state.messages.concat({\r\n type:action.messageType,\r\n message:action.message,\r\n key: state.counter\r\n }),\r\n }, {\r\n deep: true\r\n });\r\n case systemMessage.REMOVE_MESSAGE:\r\n return Immutable.setIn(state, [\"messages\"], Immutable(state.messages).filter( (item,index) => index!==action.index));\r\n case authentication.LOGGED_OUT:\r\n return defaultState();\r\n default:\r\n return state;\r\n }\r\n}","import * as view from \"../actions/view.js\";\r\n\r\nimport Immutable from \"seamless-immutable\";\r\n\r\nconst defaultState = () => {\r\n return Immutable({\r\n // Bootstrap devicetype: xs, sm, md, lg\r\n deviceType: \"\",\r\n innerHeight: 0,\r\n innerWidth: 0,\r\n });\r\n};\r\n\r\n/**\r\n * View reducer\r\n * @param {Object} state\r\n * @param {{type: string}} action\r\n * @return {*}\r\n */\r\nexport default function(state = defaultState(), action) {\r\n switch(action.type) {\r\n case view.SET_DEVICE_TYPE:\r\n return state.merge({\r\n deviceType: action.deviceType\r\n });\r\n case view.SET_INNER_HEIGHT:\r\n return state.merge({\r\n innerHeight: action.innerHeight\r\n });\r\n case view.SET_INNER_WIDTH:\r\n return state.merge({\r\n innerWidth: action.innerWidth\r\n });\r\n default:\r\n return state;\r\n }\r\n}","import {combineReducers} from \"redux\";\r\nimport commonReducer from \"../../common/reducers/commonReducer.js\";\r\nimport customerReducer from \"./customerReducer.js\";\r\nimport customerSubscriptionsReducer from \"./customerSubscriptionsReducer.js\";\r\nimport deliveryReducer from \"./deliveryReducer.js\";\r\nimport dominosReducer from \"../../dominosweb/reducers/dominosReducer.js\";\r\nimport historyReducer from \"./historyReducer.js\";\r\nimport hubOverviewReducer from \"../../hubweb/reducers/hubReducer.js\";\r\nimport multiChainSortimentReducer from \"../../kjedeweb/reducers/multiChainSortimentReducer.js\";\r\nimport multiEpixSortimentReducer from \"../../kjedeweb/reducers/multiEpixSortimentReducer.js\";\r\nimport notificationsReducer from \"../../common/reducers/notificationsReducer\";\r\nimport orderReducer from \"./orderReducer\";\r\nimport productImageReducer from \"./productImageReducer.js\";\r\nimport productListsReducer from \"./productListsReducer.js\";\r\nimport productQueryReducer from \"./productQueryReducer.js\";\r\nimport singleChainSortimentReducer from \"../../kjedeweb/reducers/singleChainSortimentReducer.js\";\r\nimport singleEpixSortimentReducer from \"../../kjedeweb/reducers/singleEpixSortimentReducer.js\";\r\nimport supportReducer from \"./supportReducer.js\";\r\nimport systemMessageReducer from \"../../common/reducers/systemMessageReducer.js\";\r\nimport viewReducer from \"./viewReducer.js\";\r\n\r\nconst rootReducer = combineReducers({\r\n ...commonReducer,\r\n customer: customerReducer,\r\n customerSubscriptions: customerSubscriptionsReducer,\r\n delivery: deliveryReducer,\r\n history: historyReducer,\r\n freshFoodHub: hubOverviewReducer,\r\n dominosweb: dominosReducer,\r\n multiChainSortiment: multiChainSortimentReducer,\r\n multiEpixSortiment: multiEpixSortimentReducer,\r\n notifications: notificationsReducer,\r\n order: orderReducer,\r\n productImage: productImageReducer, \r\n productLists: productListsReducer,\r\n productQuery: productQueryReducer,\r\n singleChainSortiment: singleChainSortimentReducer,\r\n singleEpixSortiment: singleEpixSortimentReducer,\r\n support: supportReducer,\r\n systemMessage: systemMessageReducer,\r\n view: viewReducer,\r\n});\r\n\r\nexport default rootReducer;","import \"../public/buildinfo.json\";\r\nimport \"../styles/main.scss\";\r\nimport \"../styles/card.scss\";\r\nimport \"../styles/util.scss\";\r\nimport \"../styles/button.scss\";\r\nimport \"../styles/dropdown.scss\";\r\nimport \"../styles/tag.scss\";\r\nimport \"../styles/accordion.scss\";\r\nimport \"../styles/tabs.scss\";\r\nimport \"../styles/titletabs.scss\";\r\nimport \"../assets/config/web.config\";\r\nimport \"core-js/stable\";\r\nimport \"regenerator-runtime/runtime\";\r\n\r\nimport {setDeviceType, setInnerHeight, setInnerWidth} from \"./kundeweb/actions/view.js\";\r\n\r\nimport {Provider} from \"react-redux\";\r\nimport React from \"react\";\r\nimport ReactDOM from \"react-dom\";\r\nimport RootRouter from \"./kundeweb/routes/RootRouter.jsx\";\r\nimport configureStore from \"./common/store/configureStore.js\";\r\nimport rootReducer from \"./kundeweb/reducers/rootReducer.js\";\r\n\r\nconst store = configureStore(rootReducer);\r\n\r\nconst updateBrowserDimensions = () => {\r\n const w = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);\r\n const h = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);\r\n const action = setDeviceType(w);\r\n\r\n if (store.getState().view.deviceType !== action.deviceType) {\r\n store.dispatch(action);\r\n }\r\n if (store.getState().view.innerHeight !== h) {\r\n store.dispatch(setInnerHeight(h));\r\n }\r\n if (store.getState().view.innerWidth !== w) {\r\n store.dispatch(setInnerWidth(w));\r\n }\r\n};\r\n\r\nupdateBrowserDimensions();\r\n\r\nconst renderApp = () => {\r\n ReactDOM.render(\r\n \r\n \r\n ,\r\n document.getElementById(\"react-main\")\r\n );\r\n};\r\n\r\nrenderApp();\r\n\r\nif (module.hot) {\r\n module.hot.decline();\r\n\r\n module.hot.accept(\"./kundeweb/routes/router.jsx\", () => {\r\n renderApp();\r\n });\r\n\r\n module.hot.accept(\"./kundeweb/reducers/rootReducer.js\", () => {\r\n store.replaceReducer(rootReducer);\r\n });\r\n}\r\n\r\naddEventListener(\"resize\", updateBrowserDimensions);\r\ndocument.addEventListener(\"DOMContentLoaded\", updateBrowserDimensions);","import Logger from \"./Logger.js\";\r\nimport {NetworkError} from \"../net/httpClient.js\";\r\n//import {logError as doLogError} from \"../actions/net.js\";\r\n//import {javascriptVersion} from \"./config.jsx\";\r\n\r\n/**\r\n * Loggar en händelse till api backend.\r\n * @param {Object} state \r\n * @param {string} message \r\n * @returns {undefined}\r\n */\r\n// export function logInfo(state, message){\r\n// try {\r\n// //doLogError(javascriptVersion, message, Error().stack, state.authentication.token);\r\n// console.log(message);\r\n// } catch (error){\r\n// //logError(state, error);\r\n// console.log(message);\r\n// }\r\n// }\r\n\r\n\r\n/**\r\n * Loggar ett fel till api backend.\r\n * @param {Object} state \r\n * @param {Object} error \r\n * @returns {undefined}\r\n */\r\nexport function logError(state, error){\r\n try {\r\n if (!state.authentication.token) {\r\n return;\r\n }\r\n \r\n if (error instanceof NetworkError){\r\n //const {url, errorType, message, stack} = error || {};\r\n //const text = `NetworkError: url: ${url}, errorType: ${errorType}, message: ${message}`;\r\n //doLogError(javascriptVersion, text, stack, state.authentication.token);\r\n if (process.env.NODE_ENV !== \"production\") {\r\n Logger.error(error);//alert(error);\r\n }\r\n } else {\r\n //const {message, stack} = error || {};\r\n //doLogError(javascriptVersion, message || \"Unknown error message\", stack || `Unknown callstack, caught: ${Error().stack}`, state.authentication.token);\r\n if (process.env.NODE_ENV !== \"production\") {\r\n Logger.error(error);//alert(error);\r\n }\r\n }\r\n\r\n } catch (error) {\r\n // Vad göra här?\r\n Logger.error(error);//alert(error);\r\n }\r\n}","function createThunkMiddleware(extraArgument) {\n return function (_ref) {\n var dispatch = _ref.dispatch,\n getState = _ref.getState;\n return function (next) {\n return function (action) {\n if (typeof action === 'function') {\n return action(dispatch, getState, extraArgument);\n }\n\n return next(action);\n };\n };\n };\n}\n\nvar thunk = createThunkMiddleware();\nthunk.withExtraArgument = createThunkMiddleware;\n\nexport default thunk;","import { applyMiddleware, compose, createStore } from \"redux\";\r\n\r\nimport {errorHandler} from \"../util/errorHandlerMiddleware.js\";\r\nimport thunkMiddleware from \"redux-thunk\";\r\n\r\nconst createStoreWithMiddleware = compose(\r\n applyMiddleware(\r\n errorHandler,\r\n thunkMiddleware // lets us dispatch() functions\r\n )\r\n)(createStore);\r\n\r\n/**\r\n * @returns {*}\r\n */\r\nexport default function(rootReducer) {\r\n const store = createStoreWithMiddleware(rootReducer);\r\n return store;\r\n}","import {logError} from \"./logging.js\";\r\n\r\n/**\r\n * Returnerar true om obj är en promise.\r\n * @param {any} obj \r\n * @returns {bool}\r\n */\r\nconst isPromise = obj => {\r\n return !!obj && (typeof obj === \"object\" || typeof obj === \"function\") && typeof obj.then === \"function\" && typeof obj.catch === \"function\";\r\n // return obj instanceOf Promise;\r\n};\r\n\r\n/*\r\n Middleware som fångar exceptions som slängs inuti en action som kan vara en thunk, vanlig funktion eller en promise.\r\n Dessa fel skickas till loggern.\r\n @param {Object} store - Redux store\r\n */\r\nexport const errorHandler = store => next => action => {\r\n try {\r\n const what = next(action);\r\n\r\n if (isPromise(what)){\r\n return what.catch(e => {\r\n logError(store.getState(), e);\r\n throw e;\r\n });\r\n }\r\n return what;\r\n } catch (e) {\r\n logError(store.getState(), e);\r\n throw e;\r\n }\r\n};\r\n\r\n"],"sourceRoot":""}