\n \n \n \n \n \n \n \n \n \n \n \n);\n\nexport default withSettings(Footer);\n","/**\n * Lori Footer\n */\n\nimport React from 'react';\nimport { styled } from '@smooth-ui/core-sc';\n\nconst StyledLoriFooter = styled.div`\n background-color: #141f2d;\n color: #fff;\n flex-shrink: 0;\n font-size: 14px;\n padding: 0.5em;\n text-align: center;\n width: 100%;\n\n a {\n color: #f4bd19;\n text-decoration: none;\n\n &:hover {\n text-decoration: underline;\n }\n }\n`;\n\nconst LoriFooter = () => (\n \n Powered by Lori from{' '}\n \n Incremental\n \n \n);\n\nexport default LoriFooter;\n","/**\n * Scroll to top on route change\n *\n * Based on: https://github.com/ReactTraining/react-router/blob/master/packages/react-router-dom/docs/guides/scroll-restoration.md\n *\n * Modified to exclude routes with hashes, as those should scroll to the anchor,\n * even though those are most likely to come from external links.\n */\n\nimport { Component } from 'react';\nimport PropTypes from 'prop-types';\nimport { withRouter } from 'react-router-dom';\n\nclass ScrollToTop extends Component {\n componentDidUpdate(prevProps) {\n if (\n this.props.location !== prevProps.location &&\n this.props.location.hash === ''\n ) {\n window.scrollTo(0, 0);\n }\n }\n\n render() {\n return this.props.children;\n }\n}\n\nScrollToTop.propTypes = {\n children: PropTypes.node,\n location: PropTypes.object.isRequired,\n};\n\nScrollToTop.defaultProps = {\n children: undefined,\n};\n\nexport default withRouter(ScrollToTop);\n","/**\n * WebApp\n *\n * This is the main container for the project.\n */\n\n// Core imports\nimport React, { Component } from 'react';\nimport PropTypes from 'prop-types';\nimport { compose } from 'redux';\nimport { connect } from 'react-redux';\nimport { createStructuredSelector } from 'reselect';\nimport LoadingBar from 'react-redux-loading-bar';\nimport { cssTransition, ToastContainer } from 'react-toastify';\nimport 'react-toastify/dist/ReactToastify.min.css';\nimport { CloudinaryContext } from 'cloudinary-react';\n\n// Style, SEO and settings\nimport Helmet from 'react-helmet';\nimport { styled, withTheme } from '@smooth-ui/core-sc';\nimport GlobalStylesApp from 'theme/globalStylesApp';\nimport PrivateComponent from '_platform/src/utils/PrivateComponent';\n\n// Data\nimport injectReducer from '_platform/src/utils/injectReducer';\nimport injectSaga from '_platform/src/utils/injectSaga';\nimport {\n cartRequest,\n menuRequest,\n settingsRequest,\n wishlistRequest,\n} from './actions';\nimport reducer from './reducer';\nimport saga from './saga';\nimport {\n selectCart,\n selectMenu,\n selectRoutes,\n selectSettings,\n selectSettingsNextClaimingPeriod,\n selectSettingsPointsUOM,\n selectSettingsProgram,\n selectSettingsSalesUOMs,\n selectWishlist,\n} from './selectors';\nimport { SettingsProvider } from './SettingsContext';\n\n// Additional Components/Containers\nimport LoadAsync from '_platform/src/utils/LoadAsync';\nimport Routes from './Routes';\nimport Footer from '../../components/CustomComponents/CustomFooter/Footer';\nimport LoriFooter from '_platform/src/components/LoriFooter/LoriFooter';\nimport ScrollToTop from '_platform/src/components/ScrollToTop/ScrollToTop';\n\nconst Header = LoadAsync(() =>\n import(\n /* webpackChunkName: \"header\" */ 'components/CustomComponents/CustomHeader/Header'\n )\n);\nconst HeaderNav = LoadAsync(() =>\n import(\n /* webpackChunkName: \"headerNav\" */ 'components/CustomComponents/CustomHeaderNav/HeaderNav'\n )\n);\n\nconst Welcome = LoadAsync(() =>\n import(/* webpackChunkName: \"welcome\" */ 'containers/Welcome/Welcome')\n);\n\nconst HeaderLogin = LoadAsync(() =>\n import(\n /* webpackChunkName: \"header\" */ 'components/CustomComponents/CustomHeader/HeaderLogin'\n )\n);\n\nconst HeaderLoginNav = LoadAsync(() =>\n import(\n /* webpackChunkName: \"headerNav\" */ 'components/CustomComponents/CustomHeaderNav/HeaderLoginNav'\n )\n);\n\nconst AppWrapper = styled.div`\n /* for child elements */\n display: flex;\n flex-direction: column;\n\n /* sticky footer */\n flex: 1 0 auto;\n`;\n\nconst PageWrapper = styled.div`\n /* for child elements */\n display: flex;\n flex-direction: column;\n flex: 1 0 auto;\n`;\n\nconst ToastifyTransition = cssTransition({\n enter: 'Toastify__slide-enter--top-right',\n exit: 'Toastify__slide-exit--top-right',\n duration: [300, 600],\n});\n\nclass WebApp extends Component {\n componentDidMount() {\n // If the menu is not present, and the user does not have a stored token,\n // refresh the menu.\n // If the user has a token, the menu will be updated in cDU below via token refresh.\n // Prevents unnecessary initial request\n if (!this.props.menu && !this.props.currentUser.token) {\n this.props.onMenuRequest();\n }\n }\n\n componentDidUpdate(prevProps) {\n // On change of permissions, request the menu (login, token refresh)\n // Won't run if the user has just logged out (as the permissions prop is missing),\n // so we handle that in the logout saga\n if (\n (this.props.currentUser.permissions &&\n this.props.currentUser.permissions !==\n prevProps.currentUser.permissions) ||\n this.props.currentUser.userId !== prevProps.currentUser.userId\n ) {\n this.props.onMenuRequest(true);\n\n // Request the application settings\n // Need to be authenticated to access the endpoints\n // Should this change, need to copy to cDM as well, and remove the\n // undefined condition from this one.\n if (this.props.settings.lastUpdated === undefined) {\n this.props.onSettingsRequest();\n }\n\n // Fetch the Cart\n // Do not skip fetch using `settingsApp.cartDisabled` as the cart details\n // are used for the welcome module\n if (\n this.props.cart === undefined ||\n this.props.cart.lastUpdated === undefined\n ) {\n this.props.onCartRequest();\n }\n\n // Fetch the Wishlist\n // Can skip fetching via settingsApp.wishlistDisabled\n // We're not checking the settings from API as the request would take too long to fetch, causing needless re-renders.\n // The wishlist button / functionality will be disabled/hidden with either of the settings though.\n if (\n !this.props.theme.settingsApp.wishlistDisabled &&\n (this.props.wishlist === undefined ||\n this.props.wishlist.lastUpdated === undefined)\n ) {\n this.props.onWishlistRequest();\n }\n }\n }\n\n render() {\n const { theme } = this.props;\n\n return (\n \n \n \n \n \n \n \n \n \n \n ) : (\n \n )\n }\n >\n \n \n \n \n \n \n \n \n\n {/*\n Prevent unnecessary re-renders of the Welcome container, and ensure the user is logged in\n Cart is fetched for every logged in user via componentDidUpdate above\n */}\n\n \n \n \n \n \n \n \n \n \n \n \n );\n }\n}\n\nWebApp.propTypes = {\n cart: PropTypes.object,\n currentUser: PropTypes.object.isRequired,\n location: PropTypes.object.isRequired,\n menu: PropTypes.array,\n onCartRequest: PropTypes.func.isRequired,\n onMenuRequest: PropTypes.func.isRequired,\n onLogout: PropTypes.func, // eslint-disable-line react/require-default-props\n // Using the disable line above as react sometimes doesn't pass through the prop pre-first render\n onSettingsRequest: PropTypes.func.isRequired,\n onWishlistRequest: PropTypes.func.isRequired,\n routes: PropTypes.array,\n settings: PropTypes.object,\n settingsNextClaimingPeriod: PropTypes.object,\n settingsPointsUOM: PropTypes.object,\n settingsProgram: PropTypes.object,\n settingsSalesUOMs: PropTypes.array,\n theme: PropTypes.object,\n wishlist: PropTypes.array,\n};\n\nWebApp.defaultProps = {\n cart: undefined,\n menu: undefined,\n routes: undefined,\n theme: { settingsApp: {} },\n settings: {},\n settingsNextClaimingPeriod: undefined,\n settingsPointsUOM: undefined,\n settingsProgram: undefined,\n settingsSalesUOMs: undefined,\n wishlist: undefined,\n};\n\nconst mapStateToProps = createStructuredSelector({\n cart: selectCart(),\n menu: selectMenu(),\n routes: selectRoutes(),\n settings: selectSettings(),\n settingsNextClaimingPeriod: selectSettingsNextClaimingPeriod(),\n settingsPointsUOM: selectSettingsPointsUOM(),\n settingsSalesUOMs: selectSettingsSalesUOMs(),\n settingsProgram: selectSettingsProgram(),\n wishlist: selectWishlist(),\n});\n\nfunction mapDispatchToProps(dispatch) {\n return {\n dispatch,\n onCartRequest: () => dispatch(cartRequest()),\n onMenuRequest: refresh => dispatch(menuRequest(refresh)),\n onSettingsRequest: refresh => dispatch(settingsRequest(refresh)),\n onWishlistRequest: () => dispatch(wishlistRequest()),\n };\n}\n\nconst withConnect = connect(mapStateToProps, mapDispatchToProps);\nconst withReducer = injectReducer({ key: 'webApp', reducer });\nconst withSaga = injectSaga({ key: 'webApp', saga });\n\nexport default compose(withTheme, withReducer, withSaga, withConnect)(WebApp);\n"],"sourceRoot":""}