\n );\n }\n if (props.pastDelay) {\n return ;\n }\n return null;\n};\n\nLoading.propTypes = {\n error: PropTypes.oneOfType([PropTypes.bool, PropTypes.object]),\n timedOut: PropTypes.bool,\n pastDelay: PropTypes.bool,\n retry: PropTypes.func,\n};\n\nLoading.defaultProps = {\n error: false,\n timedOut: false,\n pastDelay: false,\n retry: null,\n};\n\nexport default Loading;\n","/**\n * Helper for Loadable to dynamically load components and split into webpack chunks\n */\n\nimport Loadable from 'react-loadable';\nimport Loading from '../components/Loading/Loading'; // _platform\n\nconst LoadAsync = (loadFn, opts) =>\n Loadable({\n loader: loadFn,\n loading: Loading,\n delay: opts && opts.delay ? opts.delay : 200, // Delay displaying the loader in milliseconds\n timeout: opts && opts.timeout ? opts.timeout : null, // Show timeout message in milliseconds\n });\n\nexport default LoadAsync;\n","/**\n * Custom History object to be used as a singleton throughout\n * the project to navigate between pages\n */\nimport { createBrowserHistory } from 'history';\n\nconst history = createBrowserHistory();\nexport default history;\n","/**\n * App selectors\n */\nimport { createSelector } from 'reselect';\nimport { initialState } from './reducer';\n\n/**\n * Container state\n */\nconst selectGlobalState = state => state.global || initialState;\n\n/**\n * Fetch state\n */\nconst selectStatus = () =>\n createSelector(\n selectGlobalState,\n state => ({\n status: state.status,\n statusDetails: state.statusDetails,\n })\n );\n\n/**\n * Countries\n */\nconst selectCountries = () =>\n createSelector(\n selectGlobalState,\n state => state.countries\n );\n\n/**\n * Current user\n */\nconst selectCurrentUser = () =>\n createSelector(\n selectGlobalState,\n state => state.currentUser\n );\n\nconst selectCurrentUserTemp = () =>\n createSelector(\n selectGlobalState,\n state => state.currentUserTemp\n );\n\nconst selectIsFetchingToken = () =>\n createSelector(\n selectGlobalState,\n state => state.isFetchingToken\n );\n\nconst selectUserOptions = () =>\n createSelector(\n selectGlobalState,\n state => state.userOptions\n );\n\n/**\n * Profile details\n */\nconst selectUserProfile = () =>\n createSelector(\n selectGlobalState,\n state => state.profileDetails\n );\n\nexport {\n selectGlobalState,\n selectCountries,\n selectCurrentUser,\n selectCurrentUserTemp,\n selectIsFetchingToken,\n selectStatus,\n selectUserOptions,\n selectUserProfile,\n};\n","/**\n * Check if the URL is absolute or relative\n *\n * @param {string} url URL path\n */\nexport function isUrlAbsolute(url) {\n const r = new RegExp('^(?:[a-z]+:)?//', 'i');\n return r.test(url);\n}\n\n/**\n * removeProperty - Immutably removes a property from an object\n * Use as an immutable replacement to the `delete` keyword\n *\n * @param {object} obj Object from which the property should be removed\n * @param {string} property Name of the property\n */\nexport const removeProperty = (obj, property) =>\n Object.keys(obj).reduce((acc, key) => {\n return key !== property ? { ...acc, [key]: obj[key] } : acc;\n }, {});\n\n/**\n * flattenDeepArrayOfObjects - Flatten a deep array of objects\n *\n * Example:\n * const routesOriginal = [\n * {\n * route: '/users',\n * component: 'UsersPage/UsersPage',\n * subRoutes: [\n * { route: '/users/:id/profile', component: 'UsersProfile/UsersProfile' },\n * ],\n * }\n * ]\n * const routes = flattenDeepArrayOfObjects(routesOriginal, 'subRoutes');\n *\n * Result:\n * [\n * {\n * route: '/users',\n * component: 'UsersPage/UsersPage',\n * },\n * {\n * route: '/users/:id/profile',\n * component: 'UsersProfile/UsersProfile',\n * },\n * ]\n *\n * @param {array} arr The array of objects\n * @param {string} childrenProp The property that contains the children\n */\nexport const flattenDeepArrayOfObjects = function(\n arr,\n childrenProp = 'children'\n) {\n const array = Array.isArray(arr) ? arr : [arr];\n return array.reduce(function(acc, item) {\n acc.push(item);\n if (item[childrenProp]) {\n acc = acc.concat(flattenDeepArrayOfObjects(item[childrenProp]));\n // delete item[childrenProp];\n }\n return acc;\n }, []);\n};\n\n/**\n * untrailingSlashIt - Remove trailing slash from a path if there is one\n *\n * @param {string} str The URL or path\n */\nexport const untrailingSlashIt = str => str.replace(/\\/$/, '');\n\n/**\n * trailingSlashIt - Add a trailing slash to a path if it doesn't have one\n *\n * @param {string} str The URL or path\n */\nexport const trailingSlashIt = str => `${untrailingSlashIt(str)}/`;\n\n/**\n * lowercaseFirstLetter - Convert the first character in a string to lower case\n * Used in normalising endpoint response data objects\n *\n * @param {string} string The string\n */\nexport const lowercaseFirstLetter = string =>\n string.charAt(0).toLowerCase() + string.slice(1);\n","var map = {\n\t\"./AboutPage/AboutAwardsNight\": [\n\t\t349,\n\t\t9,\n\t\t64\n\t],\n\t\"./AboutPage/AboutAwardsNight.js\": [\n\t\t349,\n\t\t9,\n\t\t64\n\t],\n\t\"./AboutPage/AboutPage\": [\n\t\t350,\n\t\t9,\n\t\t36\n\t],\n\t\"./AboutPage/AboutPage.js\": [\n\t\t350,\n\t\t9,\n\t\t36\n\t],\n\t\"./AboutPage/images/about@2x.png\": [\n\t\t657,\n\t\t7,\n\t\t172\n\t],\n\t\"./AboutPage/images/banner-about-@1x.jpg\": [\n\t\t678,\n\t\t7,\n\t\t173\n\t],\n\t\"./AboutPage/images/banner-about-@2x.jpg\": [\n\t\t679,\n\t\t7,\n\t\t174\n\t],\n\t\"./AboutPage/images/banner-about-man_using_keyboard-@2x.jpg\": [\n\t\t680,\n\t\t7,\n\t\t175\n\t],\n\t\"./AboutPage/images/banner-about-mobile-@1x.jpg\": [\n\t\t681,\n\t\t7,\n\t\t176\n\t],\n\t\"./AboutPage/images/banner-about-mobile-@2x.jpg\": [\n\t\t682,\n\t\t7,\n\t\t177\n\t],\n\t\"./AboutPage/images/banner-about-tablet-@1x.jpg\": [\n\t\t683,\n\t\t7,\n\t\t178\n\t],\n\t\"./AboutPage/images/banner-about-tablet-@2x.jpg\": [\n\t\t684,\n\t\t7,\n\t\t179\n\t],\n\t\"./AboutPage/images/bg-about-awards_night_banner-@2x.jpg\": [\n\t\t656,\n\t\t7,\n\t\t180\n\t],\n\t\"./AboutPage/images/icon-handgraph.svg\": [\n\t\t685,\n\t\t7,\n\t\t160\n\t],\n\t\"./AboutPage/images/icon-lightbulb.svg\": [\n\t\t686,\n\t\t7,\n\t\t161\n\t],\n\t\"./AboutPage/images/icon-shield.svg\": [\n\t\t687,\n\t\t7,\n\t\t162\n\t],\n\t\"./AboutPage/images/icon-stopwatch.svg\": [\n\t\t688,\n\t\t7,\n\t\t163\n\t],\n\t\"./AboutPage/images/image-about-1-@2x.jpg\": [\n\t\t689,\n\t\t7,\n\t\t181\n\t],\n\t\"./AboutPage/images/image-about-2-@2x.jpg\": [\n\t\t690,\n\t\t7,\n\t\t182\n\t],\n\t\"./AboutPage/images/image-about-digital_giftcards-@2x.jpg\": [\n\t\t691,\n\t\t7,\n\t\t183\n\t],\n\t\"./AboutPage/images/image-about-rewards_collage-@2x.jpg\": [\n\t\t692,\n\t\t7,\n\t\t184\n\t],\n\t\"./AboutPage/images/image-about-travel_collage-@2x.jpg\": [\n\t\t693,\n\t\t7,\n\t\t185\n\t],\n\t\"./BehaviourProvider/BehaviourProvider\": [\n\t\t333,\n\t\t9,\n\t\t6\n\t],\n\t\"./BehaviourProvider/BehaviourProvider.js\": [\n\t\t333,\n\t\t9,\n\t\t6\n\t],\n\t\"./BehaviourProvider/actions\": [\n\t\t286,\n\t\t9,\n\t\t65\n\t],\n\t\"./BehaviourProvider/actions.js\": [\n\t\t286,\n\t\t9,\n\t\t65\n\t],\n\t\"./BehaviourProvider/constants\": [\n\t\t275,\n\t\t9,\n\t\t84\n\t],\n\t\"./BehaviourProvider/constants.js\": [\n\t\t275,\n\t\t9,\n\t\t84\n\t],\n\t\"./BehaviourProvider/reducer\": [\n\t\t287,\n\t\t9,\n\t\t66\n\t],\n\t\"./BehaviourProvider/reducer.js\": [\n\t\t287,\n\t\t9,\n\t\t66\n\t],\n\t\"./BehaviourProvider/saga\": [\n\t\t304,\n\t\t9,\n\t\t46\n\t],\n\t\"./BehaviourProvider/saga.js\": [\n\t\t304,\n\t\t9,\n\t\t46\n\t],\n\t\"./BehaviourProvider/selectors\": [\n\t\t305,\n\t\t9,\n\t\t47\n\t],\n\t\"./BehaviourProvider/selectors.js\": [\n\t\t305,\n\t\t9,\n\t\t47\n\t],\n\t\"./CartPage/CartPage\": [\n\t\t351,\n\t\t9,\n\t\t85\n\t],\n\t\"./CartPage/CartPage.js\": [\n\t\t351,\n\t\t9,\n\t\t85\n\t],\n\t\"./CartProvider/CartProvider\": [\n\t\t306,\n\t\t9,\n\t\t7\n\t],\n\t\"./CartProvider/CartProvider.js\": [\n\t\t306,\n\t\t9,\n\t\t7\n\t],\n\t\"./CartProvider/actions\": [\n\t\t288,\n\t\t9,\n\t\t67\n\t],\n\t\"./CartProvider/actions.js\": [\n\t\t288,\n\t\t9,\n\t\t67\n\t],\n\t\"./CartProvider/constants\": [\n\t\t276,\n\t\t9,\n\t\t86\n\t],\n\t\"./CartProvider/constants.js\": [\n\t\t276,\n\t\t9,\n\t\t86\n\t],\n\t\"./CartProvider/reducer\": [\n\t\t289,\n\t\t9,\n\t\t68\n\t],\n\t\"./CartProvider/reducer.js\": [\n\t\t289,\n\t\t9,\n\t\t68\n\t],\n\t\"./CartProvider/saga\": [\n\t\t307,\n\t\t9,\n\t\t48\n\t],\n\t\"./CartProvider/saga.js\": [\n\t\t307,\n\t\t9,\n\t\t48\n\t],\n\t\"./CartProvider/selectors\": [\n\t\t308,\n\t\t9,\n\t\t49\n\t],\n\t\"./CartProvider/selectors.js\": [\n\t\t308,\n\t\t9,\n\t\t49\n\t],\n\t\"./ClaimHistoryPage/ClaimHistoryPage\": [\n\t\t369,\n\t\t9,\n\t\t32\n\t],\n\t\"./ClaimHistoryPage/ClaimHistoryPage.js\": [\n\t\t369,\n\t\t9,\n\t\t32\n\t],\n\t\"./ClaimHistoryProvider/ClaimHistoryProvider\": [\n\t\t352,\n\t\t9,\n\t\t8\n\t],\n\t\"./ClaimHistoryProvider/ClaimHistoryProvider.js\": [\n\t\t352,\n\t\t9,\n\t\t8\n\t],\n\t\"./ClaimHistoryProvider/actions\": [\n\t\t290,\n\t\t9,\n\t\t69\n\t],\n\t\"./ClaimHistoryProvider/actions.js\": [\n\t\t290,\n\t\t9,\n\t\t69\n\t],\n\t\"./ClaimHistoryProvider/constants\": [\n\t\t277,\n\t\t9,\n\t\t87\n\t],\n\t\"./ClaimHistoryProvider/constants.js\": [\n\t\t277,\n\t\t9,\n\t\t87\n\t],\n\t\"./ClaimHistoryProvider/reducer\": [\n\t\t291,\n\t\t9,\n\t\t70\n\t],\n\t\"./ClaimHistoryProvider/reducer.js\": [\n\t\t291,\n\t\t9,\n\t\t70\n\t],\n\t\"./ClaimHistoryProvider/saga\": [\n\t\t310,\n\t\t9,\n\t\t50\n\t],\n\t\"./ClaimHistoryProvider/saga.js\": [\n\t\t310,\n\t\t9,\n\t\t50\n\t],\n\t\"./ClaimHistoryProvider/selectors\": [\n\t\t311,\n\t\t9,\n\t\t51\n\t],\n\t\"./ClaimHistoryProvider/selectors.js\": [\n\t\t311,\n\t\t9,\n\t\t51\n\t],\n\t\"./CodesProvider/CodesList\": [\n\t\t312,\n\t\t9,\n\t\t38\n\t],\n\t\"./CodesProvider/CodesList.js\": [\n\t\t312,\n\t\t9,\n\t\t38\n\t],\n\t\"./CodesProvider/CodesProvider\": [\n\t\t334,\n\t\t9,\n\t\t9\n\t],\n\t\"./CodesProvider/CodesProvider.js\": [\n\t\t334,\n\t\t9,\n\t\t9\n\t],\n\t\"./CodesProvider/CodesRedeemForm\": [\n\t\t315,\n\t\t9,\n\t\t0,\n\t\t1,\n\t\t31\n\t],\n\t\"./CodesProvider/CodesRedeemForm.js\": [\n\t\t315,\n\t\t9,\n\t\t0,\n\t\t1,\n\t\t31\n\t],\n\t\"./CodesProvider/actions\": [\n\t\t292,\n\t\t9,\n\t\t71\n\t],\n\t\"./CodesProvider/actions.js\": [\n\t\t292,\n\t\t9,\n\t\t71\n\t],\n\t\"./CodesProvider/constants\": [\n\t\t278,\n\t\t9,\n\t\t88\n\t],\n\t\"./CodesProvider/constants.js\": [\n\t\t278,\n\t\t9,\n\t\t88\n\t],\n\t\"./CodesProvider/reducer\": [\n\t\t293,\n\t\t9,\n\t\t72\n\t],\n\t\"./CodesProvider/reducer.js\": [\n\t\t293,\n\t\t9,\n\t\t72\n\t],\n\t\"./CodesProvider/saga\": [\n\t\t313,\n\t\t9,\n\t\t52\n\t],\n\t\"./CodesProvider/saga.js\": [\n\t\t313,\n\t\t9,\n\t\t52\n\t],\n\t\"./CodesProvider/selectors\": [\n\t\t314,\n\t\t9,\n\t\t53\n\t],\n\t\"./CodesProvider/selectors.js\": [\n\t\t314,\n\t\t9,\n\t\t53\n\t],\n\t\"./ContactPage/ContactPage\": [\n\t\t353,\n\t\t9,\n\t\t41\n\t],\n\t\"./ContactPage/ContactPage.js\": [\n\t\t353,\n\t\t9,\n\t\t41\n\t],\n\t\"./ContactPage/images/banner-contact-@1x.jpg\": [\n\t\t694,\n\t\t7,\n\t\t186\n\t],\n\t\"./ContactPage/images/banner-contact-@2x.jpg\": [\n\t\t695,\n\t\t7,\n\t\t187\n\t],\n\t\"./ContactPage/images/banner-contact-mobile-@1x.jpg\": [\n\t\t696,\n\t\t7,\n\t\t188\n\t],\n\t\"./ContactPage/images/banner-contact-mobile-@2x.jpg\": [\n\t\t697,\n\t\t7,\n\t\t189\n\t],\n\t\"./ContactPage/images/banner-contact-tablet-@1x.jpg\": [\n\t\t698,\n\t\t7,\n\t\t190\n\t],\n\t\"./ContactPage/images/banner-contact-tablet-@2x.jpg\": [\n\t\t699,\n\t\t7,\n\t\t191\n\t],\n\t\"./FaqsPage/FaqsPage\": [\n\t\t370,\n\t\t9,\n\t\t0,\n\t\t30\n\t],\n\t\"./FaqsPage/FaqsPage.js\": [\n\t\t370,\n\t\t9,\n\t\t0,\n\t\t30\n\t],\n\t\"./FaqsPage/actions\": [\n\t\t295,\n\t\t9,\n\t\t73\n\t],\n\t\"./FaqsPage/actions.js\": [\n\t\t295,\n\t\t9,\n\t\t73\n\t],\n\t\"./FaqsPage/constants\": [\n\t\t279,\n\t\t9,\n\t\t89\n\t],\n\t\"./FaqsPage/constants.js\": [\n\t\t279,\n\t\t9,\n\t\t89\n\t],\n\t\"./FaqsPage/images/FAQs-Banner.jpg\": [\n\t\t700,\n\t\t7,\n\t\t192\n\t],\n\t\"./FaqsPage/images/FAQs-Banner@2x.jpg\": [\n\t\t701,\n\t\t7,\n\t\t193\n\t],\n\t\"./FaqsPage/images/Minus.svg\": [\n\t\t665,\n\t\t7,\n\t\t164\n\t],\n\t\"./FaqsPage/images/Plus.svg\": [\n\t\t664,\n\t\t7,\n\t\t165\n\t],\n\t\"./FaqsPage/reducer\": [\n\t\t294,\n\t\t9,\n\t\t74\n\t],\n\t\"./FaqsPage/reducer.js\": [\n\t\t294,\n\t\t9,\n\t\t74\n\t],\n\t\"./FaqsPage/saga\": [\n\t\t316,\n\t\t9,\n\t\t54\n\t],\n\t\"./FaqsPage/saga.js\": [\n\t\t316,\n\t\t9,\n\t\t54\n\t],\n\t\"./FaqsPage/selectors\": [\n\t\t317,\n\t\t9,\n\t\t55\n\t],\n\t\"./FaqsPage/selectors.js\": [\n\t\t317,\n\t\t9,\n\t\t55\n\t],\n\t\"./HomePage/HomePage\": [\n\t\t345,\n\t\t9,\n\t\t10\n\t],\n\t\"./HomePage/HomePage.js\": [\n\t\t345,\n\t\t9,\n\t\t10\n\t],\n\t\"./HomePage/images/Icon1.svg\": [\n\t\t644,\n\t\t7,\n\t\t166\n\t],\n\t\"./HomePage/images/Icon2.svg\": [\n\t\t645,\n\t\t7,\n\t\t167\n\t],\n\t\"./HomePage/images/Icon3.svg\": [\n\t\t646,\n\t\t7,\n\t\t168\n\t],\n\t\"./HomePage/images/Ribbon.svg\": [\n\t\t702,\n\t\t7,\n\t\t169\n\t],\n\t\"./HomePage/images/Ribbon@2x.png\": [\n\t\t643,\n\t\t7,\n\t\t194\n\t],\n\t\"./HomePage/images/calendar.svg\": [\n\t\t647,\n\t\t7,\n\t\t170\n\t],\n\t\"./HomePage/images/home-hero.jpg\": [\n\t\t703,\n\t\t7,\n\t\t195\n\t],\n\t\"./HomePage/images/image-about-laptop-2-@2x.jpg\": [\n\t\t704,\n\t\t7,\n\t\t196\n\t],\n\t\"./HomePage/images/image-about-people-@2x.jpg\": [\n\t\t705,\n\t\t7,\n\t\t197\n\t],\n\t\"./HomePage/images/image-about-products-@2x.jpg\": [\n\t\t706,\n\t\t7,\n\t\t198\n\t],\n\t\"./HomePage/images/image-home-reward-chromecast-@2x.jpg\": [\n\t\t707,\n\t\t7,\n\t\t199\n\t],\n\t\"./HomePage/images/image-home-reward-dewalt-@2x.jpg\": [\n\t\t708,\n\t\t7,\n\t\t200\n\t],\n\t\"./HomePage/images/image-home-reward-nintendo-@2x.jpg\": [\n\t\t709,\n\t\t7,\n\t\t201\n\t],\n\t\"./HomePage/images/image-home-reward-phillips-@2x.jpg\": [\n\t\t710,\n\t\t7,\n\t\t202\n\t],\n\t\"./InvoicePage/InvoiceForm\": [\n\t\t328,\n\t\t9,\n\t\t0,\n\t\t1,\n\t\t2,\n\t\t24,\n\t\t11\n\t],\n\t\"./InvoicePage/InvoiceForm.js\": [\n\t\t328,\n\t\t9,\n\t\t0,\n\t\t1,\n\t\t2,\n\t\t24,\n\t\t11\n\t],\n\t\"./InvoicePage/InvoiceList\": [\n\t\t335,\n\t\t9,\n\t\t3,\n\t\t4,\n\t\t12\n\t],\n\t\"./InvoicePage/InvoiceList.js\": [\n\t\t335,\n\t\t9,\n\t\t3,\n\t\t4,\n\t\t12\n\t],\n\t\"./InvoicePage/InvoicePage\": [\n\t\t354,\n\t\t9,\n\t\t90\n\t],\n\t\"./InvoicePage/InvoicePage.js\": [\n\t\t354,\n\t\t9,\n\t\t90\n\t],\n\t\"./InvoiceProvider/InvoiceProvider\": [\n\t\t318,\n\t\t9,\n\t\t3,\n\t\t13\n\t],\n\t\"./InvoiceProvider/InvoiceProvider.js\": [\n\t\t318,\n\t\t9,\n\t\t3,\n\t\t13\n\t],\n\t\"./InvoiceProvider/actions\": [\n\t\t296,\n\t\t9,\n\t\t75\n\t],\n\t\"./InvoiceProvider/actions.js\": [\n\t\t296,\n\t\t9,\n\t\t75\n\t],\n\t\"./InvoiceProvider/constants\": [\n\t\t280,\n\t\t9,\n\t\t91\n\t],\n\t\"./InvoiceProvider/constants.js\": [\n\t\t280,\n\t\t9,\n\t\t91\n\t],\n\t\"./InvoiceProvider/reducer\": [\n\t\t297,\n\t\t9,\n\t\t76\n\t],\n\t\"./InvoiceProvider/reducer.js\": [\n\t\t297,\n\t\t9,\n\t\t76\n\t],\n\t\"./InvoiceProvider/saga\": [\n\t\t319,\n\t\t9,\n\t\t3,\n\t\t40\n\t],\n\t\"./InvoiceProvider/saga.js\": [\n\t\t319,\n\t\t9,\n\t\t3,\n\t\t40\n\t],\n\t\"./InvoiceProvider/selectors\": [\n\t\t320,\n\t\t9,\n\t\t56\n\t],\n\t\"./InvoiceProvider/selectors.js\": [\n\t\t320,\n\t\t9,\n\t\t56\n\t],\n\t\"./LeaderboardPage/LeaderboardPage\": [\n\t\t355,\n\t\t9,\n\t\t33\n\t],\n\t\"./LeaderboardPage/LeaderboardPage.js\": [\n\t\t355,\n\t\t9,\n\t\t33\n\t],\n\t\"./LeaderboardProvider/LeaderboardProvider\": [\n\t\t321,\n\t\t9,\n\t\t35\n\t],\n\t\"./LeaderboardProvider/LeaderboardProvider.js\": [\n\t\t321,\n\t\t9,\n\t\t35\n\t],\n\t\"./LeaderboardProvider/actions\": [\n\t\t283,\n\t\t9,\n\t\t77\n\t],\n\t\"./LeaderboardProvider/actions.js\": [\n\t\t283,\n\t\t9,\n\t\t77\n\t],\n\t\"./LeaderboardProvider/constants\": [\n\t\t274,\n\t\t9,\n\t\t92\n\t],\n\t\"./LeaderboardProvider/constants.js\": [\n\t\t274,\n\t\t9,\n\t\t92\n\t],\n\t\"./LeaderboardProvider/reducer\": [\n\t\t284,\n\t\t9,\n\t\t78\n\t],\n\t\"./LeaderboardProvider/reducer.js\": [\n\t\t284,\n\t\t9,\n\t\t78\n\t],\n\t\"./LeaderboardProvider/saga\": [\n\t\t302,\n\t\t9,\n\t\t57\n\t],\n\t\"./LeaderboardProvider/saga.js\": [\n\t\t302,\n\t\t9,\n\t\t57\n\t],\n\t\"./LeaderboardProvider/selectors\": [\n\t\t303,\n\t\t9,\n\t\t58\n\t],\n\t\"./LeaderboardProvider/selectors.js\": [\n\t\t303,\n\t\t9,\n\t\t58\n\t],\n\t\"./LoginPage/LoginPage\": [\n\t\t368,\n\t\t9,\n\t\t14\n\t],\n\t\"./LoginPage/LoginPage.js\": [\n\t\t368,\n\t\t9,\n\t\t14\n\t],\n\t\"./LoginPage/images/Background-v2.jpg\": [\n\t\t648,\n\t\t7,\n\t\t203\n\t],\n\t\"./LoginPage/images/Background-v2@2x.jpg\": [\n\t\t649,\n\t\t7,\n\t\t204\n\t],\n\t\"./LoginPage/images/Patties-Extravaganza@2x.png\": [\n\t\t650,\n\t\t7,\n\t\t205\n\t],\n\t\"./LoginPage/images/Patties@2x.png\": [\n\t\t653,\n\t\t7,\n\t\t206\n\t],\n\t\"./LoginPage/images/Text.png\": [\n\t\t711,\n\t\t7,\n\t\t207\n\t],\n\t\"./LoginPage/images/Text@2x.png\": [\n\t\t651,\n\t\t7,\n\t\t208\n\t],\n\t\"./LoginPage/images/image-login_page-background-@1x.jpg\": [\n\t\t712,\n\t\t7,\n\t\t209\n\t],\n\t\"./LoginPage/images/image-login_page-background-@2x.jpg\": [\n\t\t713,\n\t\t7,\n\t\t210\n\t],\n\t\"./LoginPage/images/leader_ribbon_col@2x.png\": [\n\t\t654,\n\t\t7,\n\t\t211\n\t],\n\t\"./LoginPage/images/welcome-bottom@1x.png\": [\n\t\t652,\n\t\t7,\n\t\t212\n\t],\n\t\"./LoginPage/images/welcome-bottom@2x.png\": [\n\t\t714,\n\t\t7,\n\t\t213\n\t],\n\t\"./LogoutPage/LogoutPage\": [\n\t\t347,\n\t\t9,\n\t\t15\n\t],\n\t\"./LogoutPage/LogoutPage.js\": [\n\t\t347,\n\t\t9,\n\t\t15\n\t],\n\t\"./MobileAppSSOPage/MobileAppSSOPage\": [\n\t\t348,\n\t\t9,\n\t\t16\n\t],\n\t\"./MobileAppSSOPage/MobileAppSSOPage.js\": [\n\t\t348,\n\t\t9,\n\t\t16\n\t],\n\t\"./NotFoundPage/NotFoundPage\": [\n\t\t332,\n\t\t9,\n\t\t17\n\t],\n\t\"./NotFoundPage/NotFoundPage.js\": [\n\t\t332,\n\t\t9,\n\t\t17\n\t],\n\t\"./NotFoundPage/images/404-error-icons.svg\": [\n\t\t655,\n\t\t7,\n\t\t171\n\t],\n\t\"./PasswordResetPage/PasswordResetPage\": [\n\t\t346,\n\t\t9,\n\t\t18\n\t],\n\t\"./PasswordResetPage/PasswordResetPage.js\": [\n\t\t346,\n\t\t9,\n\t\t18\n\t],\n\t\"./PrivacyPage/PrivacyPage\": [\n\t\t356,\n\t\t9,\n\t\t42\n\t],\n\t\"./PrivacyPage/PrivacyPage.js\": [\n\t\t356,\n\t\t9,\n\t\t42\n\t],\n\t\"./ProductsPage/ProductsPage\": [\n\t\t357,\n\t\t9,\n\t\t43\n\t],\n\t\"./ProductsPage/ProductsPage.js\": [\n\t\t357,\n\t\t9,\n\t\t43\n\t],\n\t\"./ProfilePage/ProfilePage\": [\n\t\t358,\n\t\t9,\n\t\t39\n\t],\n\t\"./ProfilePage/ProfilePage.js\": [\n\t\t358,\n\t\t9,\n\t\t39\n\t],\n\t\"./ProfilePage/images/banner-profile-@1x.jpg\": [\n\t\t715,\n\t\t7,\n\t\t214\n\t],\n\t\"./ProfilePage/images/banner-profile-@2x.jpg\": [\n\t\t716,\n\t\t7,\n\t\t215\n\t],\n\t\"./ProfilePage/images/banner-profile-mobile-@1x.jpg\": [\n\t\t717,\n\t\t7,\n\t\t216\n\t],\n\t\"./ProfilePage/images/banner-profile-mobile-@2x.jpg\": [\n\t\t718,\n\t\t7,\n\t\t217\n\t],\n\t\"./ProfilePage/images/banner-profile-tablet-@1x.jpg\": [\n\t\t719,\n\t\t7,\n\t\t218\n\t],\n\t\"./ProfilePage/images/banner-profile-tablet-@2x.jpg\": [\n\t\t720,\n\t\t7,\n\t\t219\n\t],\n\t\"./RedeemCode/RedeemCode\": [\n\t\t359,\n\t\t9,\n\t\t93\n\t],\n\t\"./RedeemCode/RedeemCode.js\": [\n\t\t359,\n\t\t9,\n\t\t93\n\t],\n\t\"./RedirectToFirstAvailableSubMenu/RedirectToFirstAvailableSubMenu\": [\n\t\t360,\n\t\t9,\n\t\t94\n\t],\n\t\"./RedirectToFirstAvailableSubMenu/RedirectToFirstAvailableSubMenu.js\": [\n\t\t360,\n\t\t9,\n\t\t94\n\t],\n\t\"./RegisterPage/RegisterPage\": [\n\t\t361,\n\t\t9,\n\t\t0,\n\t\t1,\n\t\t28\n\t],\n\t\"./RegisterPage/RegisterPage.js\": [\n\t\t361,\n\t\t9,\n\t\t0,\n\t\t1,\n\t\t28\n\t],\n\t\"./RewardsPage/RewardsConciergeBlock\": [\n\t\t329,\n\t\t9,\n\t\t79\n\t],\n\t\"./RewardsPage/RewardsConciergeBlock.js\": [\n\t\t329,\n\t\t9,\n\t\t79\n\t],\n\t\"./RewardsPage/RewardsPage\": [\n\t\t362,\n\t\t9,\n\t\t0,\n\t\t1,\n\t\t2,\n\t\t26\n\t],\n\t\"./RewardsPage/RewardsPage.js\": [\n\t\t362,\n\t\t9,\n\t\t0,\n\t\t1,\n\t\t2,\n\t\t26\n\t],\n\t\"./RewardsPage/images/banner-rewards-@1x.jpg\": [\n\t\t670,\n\t\t7,\n\t\t220\n\t],\n\t\"./RewardsPage/images/banner-rewards-@2x.jpg\": [\n\t\t671,\n\t\t7,\n\t\t221\n\t],\n\t\"./RewardsPage/images/banner-rewards-mobile-@1x.jpg\": [\n\t\t666,\n\t\t7,\n\t\t222\n\t],\n\t\"./RewardsPage/images/banner-rewards-mobile-@2x.jpg\": [\n\t\t667,\n\t\t7,\n\t\t223\n\t],\n\t\"./RewardsPage/images/banner-rewards-tablet-@1x.jpg\": [\n\t\t668,\n\t\t7,\n\t\t224\n\t],\n\t\"./RewardsPage/images/banner-rewards-tablet-@2x.jpg\": [\n\t\t669,\n\t\t7,\n\t\t225\n\t],\n\t\"./RewardsPage/images/bg-rewards-concierge-@2x.jpg\": [\n\t\t642,\n\t\t7,\n\t\t226\n\t],\n\t\"./RewardsProvider/RewardsProvider\": [\n\t\t336,\n\t\t9,\n\t\t19,\n\t\t45\n\t],\n\t\"./RewardsProvider/RewardsProvider.js\": [\n\t\t336,\n\t\t9,\n\t\t19,\n\t\t45\n\t],\n\t\"./RewardsProvider/actions\": [\n\t\t298,\n\t\t9,\n\t\t80\n\t],\n\t\"./RewardsProvider/actions.js\": [\n\t\t298,\n\t\t9,\n\t\t80\n\t],\n\t\"./RewardsProvider/constants\": [\n\t\t281,\n\t\t9,\n\t\t95\n\t],\n\t\"./RewardsProvider/constants.js\": [\n\t\t281,\n\t\t9,\n\t\t95\n\t],\n\t\"./RewardsProvider/reducer\": [\n\t\t299,\n\t\t9,\n\t\t81\n\t],\n\t\"./RewardsProvider/reducer.js\": [\n\t\t299,\n\t\t9,\n\t\t81\n\t],\n\t\"./RewardsProvider/rewardsUtils\": [\n\t\t285,\n\t\t9,\n\t\t96\n\t],\n\t\"./RewardsProvider/rewardsUtils.js\": [\n\t\t285,\n\t\t9,\n\t\t96\n\t],\n\t\"./RewardsProvider/saga\": [\n\t\t322,\n\t\t9,\n\t\t59\n\t],\n\t\"./RewardsProvider/saga.js\": [\n\t\t322,\n\t\t9,\n\t\t59\n\t],\n\t\"./RewardsProvider/selectors\": [\n\t\t323,\n\t\t9,\n\t\t60\n\t],\n\t\"./RewardsProvider/selectors.js\": [\n\t\t323,\n\t\t9,\n\t\t60\n\t],\n\t\"./SitemapPage/SitemapPage\": [\n\t\t371,\n\t\t9,\n\t\t37\n\t],\n\t\"./SitemapPage/SitemapPage.js\": [\n\t\t371,\n\t\t9,\n\t\t37\n\t],\n\t\"./StatementIncentivePage/StatementIncentivePage\": [\n\t\t363,\n\t\t9,\n\t\t34\n\t],\n\t\"./StatementIncentivePage/StatementIncentivePage.js\": [\n\t\t363,\n\t\t9,\n\t\t34\n\t],\n\t\"./StatementIncentivePage/images/banner-statement-@1x.jpg\": [\n\t\t676,\n\t\t7,\n\t\t227\n\t],\n\t\"./StatementIncentivePage/images/banner-statement-@2x.jpg\": [\n\t\t677,\n\t\t7,\n\t\t228\n\t],\n\t\"./StatementIncentivePage/images/banner-statement-mobile-@1x.jpg\": [\n\t\t672,\n\t\t7,\n\t\t229\n\t],\n\t\"./StatementIncentivePage/images/banner-statement-mobile-@2x.jpg\": [\n\t\t673,\n\t\t7,\n\t\t230\n\t],\n\t\"./StatementIncentivePage/images/banner-statement-tablet-@1x.jpg\": [\n\t\t674,\n\t\t7,\n\t\t231\n\t],\n\t\"./StatementIncentivePage/images/banner-statement-tablet-@2x.jpg\": [\n\t\t675,\n\t\t7,\n\t\t232\n\t],\n\t\"./StatementPage/StatementPage\": [\n\t\t364,\n\t\t9,\n\t\t44\n\t],\n\t\"./StatementPage/StatementPage.js\": [\n\t\t364,\n\t\t9,\n\t\t44\n\t],\n\t\"./StatementPage/StatementTabs\": [\n\t\t309,\n\t\t9,\n\t\t63\n\t],\n\t\"./StatementPage/StatementTabs.js\": [\n\t\t309,\n\t\t9,\n\t\t63\n\t],\n\t\"./StatementPage/images/banner-statement-@1x.jpg\": [\n\t\t662,\n\t\t7,\n\t\t233\n\t],\n\t\"./StatementPage/images/banner-statement-@2x.jpg\": [\n\t\t663,\n\t\t7,\n\t\t234\n\t],\n\t\"./StatementPage/images/banner-statement-mobile-@1x.jpg\": [\n\t\t658,\n\t\t7,\n\t\t235\n\t],\n\t\"./StatementPage/images/banner-statement-mobile-@2x.jpg\": [\n\t\t659,\n\t\t7,\n\t\t236\n\t],\n\t\"./StatementPage/images/banner-statement-tablet-@1x.jpg\": [\n\t\t660,\n\t\t7,\n\t\t237\n\t],\n\t\"./StatementPage/images/banner-statement-tablet-@2x.jpg\": [\n\t\t661,\n\t\t7,\n\t\t238\n\t],\n\t\"./StatementProvider/StatementProvider\": [\n\t\t324,\n\t\t9,\n\t\t20\n\t],\n\t\"./StatementProvider/StatementProvider.js\": [\n\t\t324,\n\t\t9,\n\t\t20\n\t],\n\t\"./StatementProvider/actions\": [\n\t\t300,\n\t\t9,\n\t\t82\n\t],\n\t\"./StatementProvider/actions.js\": [\n\t\t300,\n\t\t9,\n\t\t82\n\t],\n\t\"./StatementProvider/constants\": [\n\t\t282,\n\t\t9,\n\t\t97\n\t],\n\t\"./StatementProvider/constants.js\": [\n\t\t282,\n\t\t9,\n\t\t97\n\t],\n\t\"./StatementProvider/reducer\": [\n\t\t301,\n\t\t9,\n\t\t83\n\t],\n\t\"./StatementProvider/reducer.js\": [\n\t\t301,\n\t\t9,\n\t\t83\n\t],\n\t\"./StatementProvider/saga\": [\n\t\t325,\n\t\t9,\n\t\t61\n\t],\n\t\"./StatementProvider/saga.js\": [\n\t\t325,\n\t\t9,\n\t\t61\n\t],\n\t\"./StatementProvider/selectors\": [\n\t\t326,\n\t\t9,\n\t\t62\n\t],\n\t\"./StatementProvider/selectors.js\": [\n\t\t326,\n\t\t9,\n\t\t62\n\t],\n\t\"./TermsPage/TermsPage\": [\n\t\t365,\n\t\t9,\n\t\t98\n\t],\n\t\"./TermsPage/TermsPage.js\": [\n\t\t365,\n\t\t9,\n\t\t98\n\t],\n\t\"./TrainingPage/TrainingPage\": [\n\t\t366,\n\t\t9,\n\t\t99\n\t],\n\t\"./TrainingPage/TrainingPage.js\": [\n\t\t366,\n\t\t9,\n\t\t99\n\t],\n\t\"./WebApp/Routes\": [\n\t\t132,\n\t\t9\n\t],\n\t\"./WebApp/Routes.js\": [\n\t\t132,\n\t\t9\n\t],\n\t\"./WebApp/SettingsContext\": [\n\t\t77,\n\t\t9\n\t],\n\t\"./WebApp/SettingsContext.js\": [\n\t\t77,\n\t\t9\n\t],\n\t\"./WebApp/WebApp\": [\n\t\t97,\n\t\t9\n\t],\n\t\"./WebApp/WebApp.js\": [\n\t\t97,\n\t\t9\n\t],\n\t\"./WebApp/actions\": [\n\t\t19,\n\t\t9\n\t],\n\t\"./WebApp/actions.js\": [\n\t\t19,\n\t\t9\n\t],\n\t\"./WebApp/constants\": [\n\t\t8,\n\t\t9\n\t],\n\t\"./WebApp/constants.js\": [\n\t\t8,\n\t\t9\n\t],\n\t\"./WebApp/reducer\": [\n\t\t84,\n\t\t9\n\t],\n\t\"./WebApp/reducer.js\": [\n\t\t84,\n\t\t9\n\t],\n\t\"./WebApp/saga\": [\n\t\t131,\n\t\t9\n\t],\n\t\"./WebApp/saga.js\": [\n\t\t131,\n\t\t9\n\t],\n\t\"./WebApp/selectors\": [\n\t\t45,\n\t\t9\n\t],\n\t\"./WebApp/selectors.js\": [\n\t\t45,\n\t\t9\n\t],\n\t\"./Welcome/Welcome\": [\n\t\t344,\n\t\t9,\n\t\t21\n\t],\n\t\"./Welcome/Welcome.js\": [\n\t\t344,\n\t\t9,\n\t\t21\n\t],\n\t\"./WishlistPage/WishlistPage\": [\n\t\t367,\n\t\t9,\n\t\t100\n\t],\n\t\"./WishlistPage/WishlistPage.js\": [\n\t\t367,\n\t\t9,\n\t\t100\n\t],\n\t\"./WishlistProvider/WishlistProvider\": [\n\t\t327,\n\t\t9,\n\t\t22\n\t],\n\t\"./WishlistProvider/WishlistProvider.js\": [\n\t\t327,\n\t\t9,\n\t\t22\n\t]\n};\nfunction webpackAsyncContext(req) {\n\tif(!__webpack_require__.o(map, req)) {\n\t\treturn Promise.resolve().then(function() {\n\t\t\tvar e = new Error(\"Cannot find module '\" + req + \"'\");\n\t\t\te.code = 'MODULE_NOT_FOUND';\n\t\t\tthrow e;\n\t\t});\n\t}\n\n\tvar ids = map[req], id = ids[0];\n\treturn Promise.all(ids.slice(2).map(__webpack_require__.e)).then(function() {\n\t\treturn __webpack_require__.t(id, ids[1])\n\t});\n}\nwebpackAsyncContext.keys = function webpackAsyncContextKeys() {\n\treturn Object.keys(map);\n};\nwebpackAsyncContext.id = 640;\nmodule.exports = webpackAsyncContext;","/**\n *\n * Settings defaults - do not edit this file in individual projects, as it provides fallbacks.\n *\n * You can override specific values in the project src/theme/settingsApp.js file.\n *\n */\n\nconst settingsDefault = {\n // How long before the token expiry should the token be refreshed (in minutes)\n authTokenRefreshBeforeExpiry: 10,\n\n // Input date format\n dateFormat: 'dd/MM/yyyy',\n dateLongFormat: 'LLL dd, yyyy',\n dateTimeFormat: 'dd/MM/yyyy HH:mm',\n dateTimeLongFormat: 'E, LLL dd, yyyy HH:mm',\n\n // Form prefer optional indicator over required\n formPreferOptionalIndicator: false,\n formIndicatorOptionalText: '(optional)',\n formIndicatorRequiredText: ' *',\n\n // Path to the login page.\n loginPagePath: '/login/',\n\n // Toggle Remember Me option for login\n loginRememberMeEnabled: true,\n\n // Setting this option to true stores the token information in SessionStorage,\n // meaning it's only available to the current tab, and only until the tab is closed.\n // Setting this to true will disable Remember Me.\n loginUseSessionStorage: false,\n\n // Redirect users with incomplete profiles after signing in.\n // If the path is not specified (or false), the user will stay on the same\n // page where the login form is.\n // The user will be added to currentUserTemp, and any profile update module\n // will need to be supplied that object in order for display content and update\n // the back-end.\n // Important!: If the user is being redirected, ensure that the PrivateRoute\n // component has the `tempAuthAllowed` prop set, otherwise the user will not\n // be able to see/update their profile\n // Relative path with the leading slash. Eg: '/profile/'. Default: false\n redirectOnIncompleteProfile: false,\n\n // Password reset / Forgot password\n loginPasswordResetLabel: 'Reset Password',\n loginPasswordResetShow: true,\n passwordResetEnabled: true,\n passwordResetPagePath: '/password-reset/',\n\n // Path to the logout page - without trailing slash as it's not an exact path\n logoutPagePath: '/logout',\n\n // Path to the profile page\n profilePagePath: '/profile/',\n\n // Mobile App SSO\n mobileAppSSOEnabled: false,\n mobileAppSSOPagePath: '/sso/',\n\n // Rewards page - disable category listing and display rewards on the main page\n rewardsCategorySkip: false,\n\n // Minimum password character length\n minimumPasswordLength: 7,\n passwordRequirementMessage:\n 'Passwords must be at least 7 characters long and must contain at least 1 digit and 1 lowercase letter.',\n\n // Default page size for lists\n defaultPageSize: 100,\n\n // Maximum state data cache time (seconds) - used by shouldFetchData utility\n // Default 5 minutes for regular data, or 10 minutes for infrequent data (eg, contact form definitions)\n dataCacheTime: 300,\n dataCacheTimeLong: 600,\n\n // Order status labels\n orderStatusLabels: {\n Received: 'Claim Received',\n Ordered: 'Reward Ordered',\n Packing: 'Reward being Packed',\n Dispatched: 'Reward Dispatched',\n BackOrder: 'Reward has been placed on Back Order',\n },\n};\n\nexport default settingsDefault;\n","/**\n *\n * Project settings - override any values from platform settingsDefaults here\n *\n */\n\nimport settingsDefault from '_platform/src/theme/settingsDefault';\n\nconst settings = {\n // -- Base Settings --\n siteName: 'Patties EXTRAVAGANZA ',\n\n // -- Cloudinary Settings --\n // Cloudinary cloud name\n cloudinaryCloudName: 'incremental',\n\n // -- Rewards --\n // Hide reward category images (main rewards page)\n // rewardsCategoryHideImage: true,\n\n // Pages - must have trailing slash\n cartPage: '/cart/',\n privacyPage: '/privacy/',\n rewardsPage: '/rewards/',\n\n // Delivery method \"Client\" label (usually Branch or Rep)\n deliveryMethodClientLabel: 'Rep',\n\n // Master override settings\n cartDisabled: true,\n quickviewDisabled: true,\n wishlistDisabled: true,\n\n // -- Default Overrides --\n\n // Important!: If the user is being redirected, ensure that the PrivateRoute\n // component has the `tempAuthAllowed` prop set, otherwise the user will not\n // be able to see/update their profile.\n // For futher documentation, see _platform/src/theme/settingsDefault.js\n // redirectOnIncompleteProfile: '/profile/',\n\n // Rewards page - disable category listing and display rewards on the main page\n // rewardsCategorySkip: true,\n};\n\n// Note: If you are altering the breakpoints, make sure you loop over the\n// values and create the media prop. See settingsDefault.js for implementation.\n\n// Deep merge with default values\nconst settingsApp = { ...settingsDefault, ...settings };\n\nexport default settingsApp;\n","/**\n * Application theme\n *\n * Override and extend smooth-ui theme values\n * https://github.com/smooth-code/smooth-ui/blob/master/packages/shared/core/theme.js\n * https://smooth-ui.smooth-code.com/\n */\n\nimport { transparentize } from 'polished';\nimport { thd, theme } from '@smooth-ui/core-sc';\nimport settingsApp from 'theme/settingsApp';\n\n/*\nIf overwriting the default Smooth-UI theme properties, and you're planning on\nre-using them throughout the default export below, make sure to define them in\nthe outer scope, otherwise components attempting to use the value with throw errors\n*/\nconst primary = '#1C355E';\nconst secondary = '#F4BD19';\nconst grey = '#54707C';\nconst bluegrey = '#87B1C3';\nconst green = '#A3CF62';\nconst text = '#131D28';\n\nexport default {\n // Mandatory\n ...theme,\n settingsApp, // Bring in the merged app settings\n\n // Resets\n borderRadius: 0,\n error: thd('danger', '#dc3545'),\n gridMaxWidths: { sm: '100%', md: '100%', lg: '100%', xl: '1200px' },\n primary: primary,\n secondary: secondary,\n text: text,\n grey: grey,\n bluegrey: bluegrey,\n green: green,\n\n // Layout\n borderColor: thd('gray300', '#ddd'),\n containerWidth: '1200px',\n\n // Colours\n defaultFontColor: theme.gray800,\n // pointsValueColor: '#f90',\n\n // Input + Buttons\n inputBtnMinWidth: '200px',\n customInputHintColor: theme.gray600,\n customInputHintFontSize: '.875em',\n customInlineInputInvalidColor: theme.red,\n customCheckboxDisabledBackground: '#ced4da',\n\n // Header + Menu\n customHeaderBackground: '#151d29',\n customHeaderColor: '#f8fbfe',\n customMenuBackground: '#151d29',\n customMenuColor: '#fff',\n customMenuHighlight: '#151d29',\n customMenuHighlightColor: '#80C3C8',\n customMenuFocus: '#fff',\n customSubMenuBackground: '#151d29',\n customMobileMenuOverlayBackground: 'rgba(0, 0, 0, 0.5)',\n\n // Loading animations\n loadingBarColor: primary || '#f4bd19',\n loadingSpinnerPrimary: '#555',\n loadingSpinnerSecondary: '#eee',\n\n // Welcome component\n welcomeBackground: '#2A4572',\n welcomeColor: '#fff',\n welcomeHighlight: '#fff',\n\n // Breadcrumbs\n // breadcrumbsBackground: thd('gray200', '#fff'),\n breadcrumbsColor: thd('gray600', '#555'),\n breadcrumbsContainerWidth: thd('containerWidth', '100%'),\n breadcrumbsLinkColor: thd('gray600', '#555'),\n breadcrumbsLinkHoverColor: thd('gray800', '#333'),\n breadcrumbsCurrentLinkColor: thd('gray800', '#333'),\n breadcrumbsFontSize: '0.75rem',\n\n // Cart\n // miniCartBackground: '#fff',\n cartBadgeBackground: '#f4be00',\n cartBadgeColor: '#fff',\n cartPointsBalanceBackground: transparentize(0.75, '#369'),\n cartRemainingNegativeColor: thd('danger', '#dc3545'),\n\n // Rewards\n rewardCategoriesListContainerWidth: thd('containerWidth', '100%'),\n rewardCategoriesFilterContainerWidth: thd('containerWidth', '100%'),\n rewardListContainerWidth: thd('containerWidth', '100%'),\n rewardDetailContainerWidth: thd('containerWidth', '100%'),\n rewardDescription1ContainerWidth: thd('containerWidth', '100%'),\n rewardDescription2ContainerWidth: thd('containerWidth', '100%'),\n\n // Rewards - Quickview\n // quickviewBackground: '#333',\n // quickviewColor: '#fff',\n\n // Rewards - Wishlist\n // miniWishlistBackground: '#fff',\n wishlistBadgeBackground: '#f4be00',\n wishlistBadgeColor: '#fff',\n wishlistContainerWidth: '500px',\n // wishlistIconActive: '#f4bd19',\n // wishlistIconInactive: theme.gray500,\n\n // Rewards - Highlight (featured/related rewards)\n rewardsHighlightBackground: '#fff',\n rewardsHighlightContainerWidth: thd('containerWidth', '100%'),\n\n // Statement\n statementHighlightColor: '#f4bd19',\n statementStatus: {\n achieved: '#1e967a',\n onTrack: '#1e967a',\n close: '#ea7c22',\n behind: '#dc402a',\n inProgress: '#ea7c22',\n timeElapsed: '#32343b',\n },\n statementDoughnutBorder: '#eaeaeb',\n statementDoughnutRemainingTrack: '#fff',\n\n // Tooltips\n tooltipBackground: '#fff',\n tooltipBorderColor: '#fff',\n tooltipColor: thd('defaultFontColor', theme.gray800),\n\n // Pagination\n pagerActiveBackground: 'rgba(0,0,0,0.125)',\n pagerActiveColor: '#fff',\n // pagerColor: thd('gray800', 'inherit'),\n pagerBackgroundHover: 'rgba(0,0,0,0.125)',\n};\n","/**\n * Gets the app and user configuration\n */\n\nimport { call, put, takeLatest } from 'redux-saga/effects';\nimport { showLoading, hideLoading } from 'react-redux-loading-bar';\nimport qs from 'qs';\nimport history from '../../utils/history'; // _platform\nimport {\n api,\n apiErrorHandler,\n apiSetAuthorizationToken,\n} from '../../utils/request'; // _platform\nimport { formatToken, storeToken, removeToken } from '../../utils/tokenUtils'; // _platform\nimport { removeProperty } from '../../utils/utilities'; // _platform\nimport getLoginPath from '../../utils/getLoginPath'; // _platform\n\nimport {\n COUNTRIES_REQUEST,\n USER_LOGOUT_REQUEST,\n USER_PROFILE_REQUEST,\n USER_TOKEN_REQUEST,\n} from './constants';\nimport {\n countriesSuccess,\n countriesError,\n setUser,\n userLogoutRequest,\n userProfileSuccess,\n userProfileError,\n userTokenSuccess,\n userTokenError,\n} from './actions';\n\n/**\n * Request App Settings\n */\nexport function* requestCountries() {\n try {\n yield put(showLoading());\n const response = yield call(() =>\n api.get('/Country/v1/true', {\n description: 'Countries', // Description is used as title for any errors (optional)\n })\n );\n yield put(countriesSuccess(response.data, Math.floor(Date.now() / 1000)));\n } catch (err) {\n yield put(countriesError(apiErrorHandler(err)));\n } finally {\n yield put(hideLoading());\n }\n}\n\n/**\n * Request User Logout\n *\n * 1. Remove currentUser from state (done in reducer)\n * 2. Send logout API request, unless options.options.skipRemote is true\n * 3. Remove token from localStorage and sessionStorage\n * 4. Redirect user to login page (with querystring)\n */\nexport function* requestUserLogout(options) {\n try {\n if (!options.options || options.options.skipRemote !== true) {\n yield call(() =>\n api.post('/Authentication/v1/Logout', {\n description: 'User logout',\n })\n );\n }\n\n removeToken();\n apiSetAuthorizationToken(null);\n } catch (err) {\n // errors\n } finally {\n // redirect with Querystring if necessary\n const loginPath = getLoginPath(\n (options.options && options.options.settingsApp) || {} // Blank object if coming from request.js\n );\n\n if (loginPath) {\n yield call(history.push, loginPath);\n }\n }\n}\n\n/**\n * Request User Token (refresh)\n */\nexport function* requestUserToken(options) {\n try {\n yield put(showLoading());\n\n // On logout page, don't try to refresh the token - return error in order to log the user out\n if (history.location.pathname === options.settingsApp.logoutPagePath) {\n yield put(userTokenError());\n } else {\n const response = yield call(() =>\n api.post('/Authentication/v1/RefreshToken', {\n settingsApp: {\n loginPagePath:\n options &&\n options.settingsApp &&\n options.settingsApp.loginPagePath,\n },\n })\n );\n\n // Format user's token data\n const userData = formatToken(response.data);\n\n // Get the query string\n // Use lowercaseKeys to make the object keys predictable\n const pageQueryString = qs.parse(\n history.location.search.replace(/returnUrl/gi, 'returnUrl'),\n {\n ignoreQueryPrefix: true,\n }\n );\n\n // Original queryString but sanitised\n const cleanQueryString = qs.stringify(pageQueryString);\n\n // Remove returnUrl from querystring and keep the remainder\n const trimmedQueryString = qs.stringify(\n removeProperty(pageQueryString, 'returnUrl')\n );\n\n // Set API Authorization token to be used on subsequent calls\n apiSetAuthorizationToken(userData.token);\n\n // Check if the user has a valid profile\n if (\n response.data.isProfileValid === true &&\n response.data.forcePasswordChange === false\n ) {\n // Store the authentication info\n storeToken(userData, options.settingsApp.loginUseSessionStorage);\n\n // Put authentication info into App state\n yield put(setUser(userData));\n yield put(userTokenSuccess()); // After setUser() in order to avoid infinite loops\n } else {\n // Put authentication info into App state as currentUserTemp until the profile is complete\n // yield put(setUser(userData, 'incompleteProfile'));\n yield put(\n setUser(userData, {\n forcePasswordChange: response.data.forcePasswordChange,\n isProfileValid: response.data.isProfileValid,\n })\n );\n yield put(userTokenSuccess()); // After setUser() in order to avoid infinite loops\n\n const { redirectOnIncompleteProfile } = options.settingsApp;\n\n // Check if we should redirect to another page if the profile is incomplete\n // Include any query strings that may be present\n if (\n redirectOnIncompleteProfile &&\n response.data.forcePasswordChange === false\n ) {\n // Remove returnUrl if it matches redirectOnIncompleteProfile path\n const redirectQS =\n pageQueryString.returnUrl === redirectOnIncompleteProfile\n ? trimmedQueryString\n : cleanQueryString;\n\n yield call(history.push, {\n pathname: redirectOnIncompleteProfile,\n search: redirectQS && `?${redirectQS}`,\n });\n }\n }\n }\n } catch (err) {\n yield put(userTokenError(apiErrorHandler(err)));\n\n yield put(\n userLogoutRequest({\n skipRemote: true,\n })\n );\n } finally {\n yield put(hideLoading());\n }\n}\n\n/**\n * Request profile\n */\nexport function* requestUserProfile() {\n try {\n yield put(showLoading());\n const response = yield call(() =>\n api.get('/User/v1/Profile', {\n description: 'Profile details',\n })\n );\n\n yield put(userProfileSuccess(response.data, Math.floor(Date.now() / 1000)));\n } catch (err) {\n yield put(userProfileError(apiErrorHandler(err)));\n } finally {\n yield put(hideLoading());\n }\n}\n\n/**\n * Default saga managers the watcher lifecycle\n */\nexport default function* appSaga() {\n // Specify the constant to watch and the saga generator function to call when one is triggered\n // It returns a task descriptor (just like a fork) so we can continue execution, and will be\n // automatically cancelled on unmount (unless the mode is set to DAEMON)\n // Specify as many yields (watchers) here as necessary\n yield takeLatest(COUNTRIES_REQUEST, requestCountries);\n yield takeLatest(USER_LOGOUT_REQUEST, requestUserLogout);\n yield takeLatest(USER_PROFILE_REQUEST, requestUserProfile);\n yield takeLatest(USER_TOKEN_REQUEST, requestUserToken);\n}\n","/**\n * App\n *\n * This is the main container that gets loaded and is a wrapper around all other components.\n * It should contain containers/components and state available to all other pages.\n *\n * See below for order of import statements\n */\n\n// Core imports\nimport React, { Component } from 'react';\nimport PropTypes from 'prop-types';\nimport { withRouter } from 'react-router-dom';\nimport { compose } from 'redux';\nimport { connect } from 'react-redux';\nimport { createStructuredSelector } from 'reselect';\n\n// Style, SEO and settings\nimport { withTheme } from '@smooth-ui/core-sc';\n\n// Component features\nimport { apiSetAuthorizationToken } from '../../utils/request'; // _platform\nimport injectSaga from '../../utils/injectSaga'; // _platform\nimport { userLogoutRequest, userTokenRequest } from './actions';\nimport {\n selectCurrentUser,\n selectIsFetchingToken,\n selectStatus,\n} from './selectors';\nimport saga from './saga';\n\nclass App extends Component {\n componentDidMount() {\n // Set API Authorization token if one is stored\n apiSetAuthorizationToken(this.props.currentUser.token);\n\n // Refresh user's token if necessary\n this.tokenRefresh(true); // Action this even if the user has a token, even if it's not close to expiry. To ensure that the token is still valid after a refresh\n\n // Set up a page change listener\n this.props.history.listen(location => {\n // If the current page is not /login/, refresh the token if necessary\n if (location.pathname !== this.props.theme.settingsApp.loginPagePath)\n this.tokenRefresh();\n });\n }\n\n /**\n * refreshToken\n *\n * Determine if the user's authentication token needs to be refreshed\n * in order to keep them logged in safely for as long as possible\n *\n * @param {force} bool If token is present refresh it, bypassing token expiry check\n */\n tokenRefresh(force) {\n const { currentUser, isFetchingToken } = this.props;\n\n if (currentUser.token && currentUser.tokenData && !isFetchingToken) {\n const { authTokenRefreshBeforeExpiry } = this.props.theme.settingsApp;\n\n // Determine the lifespan of a token\n const tokenLifeTime =\n (currentUser.tokenData.tokenExpiry -\n currentUser.tokenData.generatedLocal) /\n 60;\n\n // Check if the authTokenRefreshBeforeExpiry is longer than the max life of token\n // If so, refresh token after 5 mins of token generation\n const refreshPeriod =\n authTokenRefreshBeforeExpiry < tokenLifeTime\n ? authTokenRefreshBeforeExpiry // If the setting is less than token max life\n : tokenLifeTime - 5; // After 5 minutes\n\n const triggerFetchTime = new Date(\n currentUser.tokenData.tokenExpiry * 1000\n );\n triggerFetchTime.setMinutes(\n triggerFetchTime.getMinutes() - refreshPeriod\n );\n\n if (force || new Date() > triggerFetchTime) {\n // Check token expiry time? If so, and the token has expired, it may leave\n // the user feeling as though they are logged in when they are not.\n // If we don't check, then the fetch will run, return a 401 and push to logout.\n this.props.dispatch(userTokenRequest(this.props.theme.settingsApp));\n }\n }\n }\n\n render() {\n if (this.props.children) {\n return React.Children.map(this.props.children, childElement =>\n React.cloneElement(childElement, this.props)\n );\n }\n\n return null;\n }\n}\n\nApp.propTypes = {\n children: PropTypes.node.isRequired,\n currentUser: PropTypes.object.isRequired,\n history: PropTypes.object.isRequired,\n isFetchingToken: PropTypes.bool.isRequired,\n onLogout: PropTypes.func.isRequired,\n status: PropTypes.object.isRequired,\n theme: PropTypes.object.isRequired,\n dispatch: PropTypes.func.isRequired,\n};\n\nfunction mapDispatchToProps(dispatch, props) {\n const settingsApp = (props.theme && props.theme.settingsApp) || {};\n\n return {\n onLogout: () => dispatch(userLogoutRequest({ settingsApp })),\n dispatch,\n };\n}\n\nconst mapStateToProps = createStructuredSelector({\n currentUser: selectCurrentUser(),\n isFetchingToken: selectIsFetchingToken(),\n status: selectStatus(),\n});\n\nconst withConnect = connect(\n mapStateToProps,\n mapDispatchToProps\n);\n\nconst withSaga = injectSaga({ key: 'app', saga });\n\nexport default compose(\n withTheme,\n withSaga,\n withRouter,\n withConnect\n)(App);\n","// In production, we register a service worker to serve assets from local cache.\n\n// This lets the app load faster on subsequent visits in production, and gives\n// it offline capabilities. However, it also means that developers (and users)\n// will only see deployed updates on the \"N+1\" visit to a page, since previously\n// cached resources are updated in the background.\n\n// To learn more about the benefits of this model, read https://goo.gl/KwvDNy.\n// This link also includes instructions on opting out of this behavior.\n\nconst isLocalhost = Boolean(\n window.location.hostname === 'localhost' ||\n // [::1] is the IPv6 localhost address.\n window.location.hostname === '[::1]' ||\n // 127.0.0.1/8 is considered localhost for IPv4.\n window.location.hostname.match(\n /^127(?:\\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/\n )\n);\n\nexport function register(config) {\n if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {\n // The URL constructor is available in all browsers that support SW.\n const publicUrl = new URL(process.env.PUBLIC_URL, window.location);\n if (publicUrl.origin !== window.location.origin) {\n // Our service worker won't work if PUBLIC_URL is on a different origin\n // from what our page is served on. This might happen if a CDN is used to\n // serve assets; see https://github.com/facebook/create-react-app/issues/2374\n return;\n }\n\n window.addEventListener('load', () => {\n const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;\n\n if (isLocalhost) {\n // This is running on localhost. Let's check if a service worker still exists or not.\n checkValidServiceWorker(swUrl, config);\n\n // Add some additional logging to localhost, pointing developers to the\n // service worker/PWA documentation.\n navigator.serviceWorker.ready.then(() => {\n console.log(\n 'This web app is being served cache-first by a service ' +\n 'worker. To learn more, visit https://goo.gl/SC7cgQ'\n );\n });\n } else {\n // Is not local host. Just register service worker\n registerValidSW(swUrl, config);\n }\n });\n }\n}\n\nfunction registerValidSW(swUrl, config) {\n navigator.serviceWorker\n .register(swUrl)\n .then(registration => {\n registration.onupdatefound = () => {\n const installingWorker = registration.installing;\n installingWorker.onstatechange = () => {\n if (installingWorker.state === 'installed') {\n if (navigator.serviceWorker.controller) {\n // At this point, the old content will have been purged and\n // the fresh content will have been added to the cache.\n // It's the perfect time to display a \"New content is\n // available; please refresh.\" message in your web app.\n console.log('New content is available; please refresh.');\n\n // Execute callback\n if (config.onUpdate) {\n config.onUpdate(registration);\n }\n } else {\n // At this point, everything has been precached.\n // It's the perfect time to display a\n // \"Content is cached for offline use.\" message.\n console.log('Content is cached for offline use.');\n\n // Execute callback\n if (config.onSuccess) {\n config.onSuccess(registration);\n }\n }\n }\n };\n };\n })\n .catch(error => {\n console.error('Error during service worker registration:', error);\n });\n}\n\nfunction checkValidServiceWorker(swUrl, config) {\n // Check if the service worker can be found. If it can't reload the page.\n fetch(swUrl)\n .then(response => {\n // Ensure service worker exists, and that we really are getting a JS file.\n if (\n response.status === 404 ||\n response.headers.get('content-type').indexOf('javascript') === -1\n ) {\n // No service worker found. Probably a different app. Reload the page.\n navigator.serviceWorker.ready.then(registration => {\n registration.unregister().then(() => {\n window.location.reload();\n });\n });\n } else {\n // Service worker found. Proceed as normal.\n registerValidSW(swUrl, config);\n }\n })\n .catch(() => {\n console.log(\n 'No internet connection found. App is running in offline mode.'\n );\n });\n}\n\nexport function unregister() {\n if ('serviceWorker' in navigator) {\n navigator.serviceWorker.ready.then(registration => {\n registration.unregister();\n });\n }\n}\n","// Polyfills required for IE\nimport 'react-app-polyfill/ie11'; // CRA package for IE 11 support\n// https://github.com/facebook/create-react-app/tree/master/packages/react-app-polyfill\nimport 'core-js/features/array/includes';\nimport 'core-js/features/reflect/apply';\nimport 'core-js/features/reflect/construct';\nimport 'core-js/features/reflect/has';\n// Required by us\nimport 'core-js/features/array/find';\nimport 'core-js/features/array/virtual/find-index'; // styled-components\nimport 'core-js/features/number';\nimport 'core-js/features/object/values'; // Statements/chartjs\n// End Polyfills\n\nimport React from 'react';\nimport { hydrate, render } from 'react-dom';\nimport { Router } from 'react-router-dom';\nimport { Provider } from 'react-redux';\nimport history from '_platform/src/utils/history';\nimport store from '_platform/src/utils/store';\nimport 'theme/globalStylesApp';\nimport { ThemeProvider } from '@smooth-ui/core-sc';\nimport themeApp from 'theme/themeApp'; // Settings and Theme\nimport App from '_platform/src/containers/App/App';\nimport WebApp from 'containers/WebApp/WebApp';\nimport * as serviceWorker from './serviceWorker';\n\nconst rootElement =\n document.getElementById('root') || document.createElement('div');\n\nif (rootElement.hasChildNodes()) {\n hydrate(\n \n \n \n \n \n \n \n \n ,\n rootElement\n );\n} else {\n render(\n \n \n \n \n \n \n \n \n ,\n rootElement\n );\n}\n\n// If you want your app to work offline and load faster, you can change\n// unregister() to register() below. Note this comes with some pitfalls.\n// Learn more about service workers: http://bit.ly/CRA-PWA\nserviceWorker.unregister();\n","/**\n * Check the shape of the redux store\n */\n\nimport conformsTo from 'lodash/conformsTo';\nimport isFunction from 'lodash/isFunction';\nimport isObject from 'lodash/isObject';\nimport invariant from 'invariant';\n\nexport default function checkStore(store) {\n const shape = {\n dispatch: isFunction,\n subscribe: isFunction,\n getState: isFunction,\n replaceReducer: isFunction,\n runSaga: isFunction,\n injectedReducers: isObject,\n injectedSagas: isObject,\n };\n\n invariant(\n conformsTo(store, shape),\n '(src/utils...) injectors: Expected a valid redux store'\n );\n}\n","import React from 'react';\nimport PropTypes from 'prop-types';\n\nconst SettingsContext = React.createContext();\n\nexport const SettingsProvider = ({ settings, ...props }) => (\n \n {props.children}\n \n);\n\nSettingsProvider.propTypes = {\n children: PropTypes.node.isRequired,\n settings: PropTypes.object.isRequired,\n};\n\nexport function withSettings(Component) {\n return function contextComponent(props) {\n return (\n \n {context => }\n \n );\n };\n}\n\nexport default withSettings;\n","/**\n * WebApp constants\n */\n\nexport const CART_REQUEST = 'local/WebApp/CART_REQUEST';\nexport const CART_SUCCESS = 'local/WebApp/CART_SUCCESS';\nexport const CART_ERROR = 'local/WebApp/CART_ERROR';\nexport const CUSTOMER_REPS_REQUEST = 'local/WebApp/CUSTOMER_REPS_REQUEST';\nexport const CUSTOMER_REPS_SUCCESS = 'local/WebApp/CUSTOMER_REPS_SUCCESS';\nexport const CUSTOMER_REPS_ERROR = 'local/WebApp/CUSTOMER_REPS_ERROR';\nexport const MENU_REQUEST = 'local/WebApp/MENU_REQUEST';\nexport const MENU_SUCCESS = 'local/WebApp/MENU_SUCCESS';\nexport const MENU_ERROR = 'local/WebApp/MENU_ERROR';\nexport const MENU_UPDATE_ROUTES = 'local/WebApp/MENU_UPDATE_ROUTES';\nexport const SETTINGS_REQUEST = 'local/WebApp/SETTINGS_REQUEST';\nexport const SETTINGS_SUCCESS = 'local/WebApp/SETTINGS_SUCCESS';\nexport const SETTINGS_ERROR = 'local/WebApp/SETTINGS_ERROR';\nexport const USER_LOGOUT_REQUEST_CLEANUP =\n 'local/WebApp/USER_LOGOUT_REQUEST_CLEANUP';\nexport const WISHLIST_REQUEST = 'local/WebApp/WISHLIST_REQUEST';\nexport const WISHLIST_SUCCESS = 'local/WebApp/WISHLIST_SUCCESS';\nexport const WISHLIST_ERROR = 'local/WebApp/WISHLIST_ERROR';\nexport const WISHLIST_ADDREMOVE_REQUEST =\n 'local/WebApp/WISHLIST_ADDREMOVE_REQUEST';\nexport const PATTIES_STATEMENT_REQUEST =\n 'local/WebApp/PATTIES_STATEMENT_REQUEST';\nexport const PATTIES_STATEMENT_SUCCESS =\n 'local/WebApp/PATTIES_STATEMENT_SUCCESS';\nexport const PATTIES_STATEMENT_ERROR = 'local/WebApp/PATTIES_STATEMENT_ERROR';\n","/**\n * Format the token for storage in state\n *\n * @param {object} data Response data from the login and refresh token endpoints\n * @returns currentUser object\n */\nexport function formatToken(data) {\n const timestamp = Math.floor(new Date().getTime() / 1000);\n const timeDiff = timestamp - data.generated;\n const decodedToken = decodeToken(data.token);\n const permissions = decodedToken\n ? decodedToken['INCREMENTAL.LORI/PERMISSION']\n : null;\n\n return {\n token: data.token,\n tokenData: {\n generatedServer: data.generated,\n expiryServer: data.expiry,\n generatedLocal: timestamp,\n timeDifference: timeDiff,\n tokenExpiry: data.expiry + timeDiff,\n },\n permissions,\n roles: data.roles,\n userId: decodedToken.nameid,\n disableClaiming: !(\n !decodedToken.DisableClaiming || decodedToken.DisableClaiming === 'False'\n ),\n };\n}\n\n/**\n * Store authentication token\n *\n * @param {object} userData User data object as outputted by utils/formatToken\n * @param {boolean} [useSessionStorage=false] Use session or local storage\n */\nexport function storeToken(userData, useSessionStorage = false) {\n if (!!useSessionStorage) {\n sessionStorage.setItem(\n 'auth',\n JSON.stringify({ token: userData.token, tokenData: userData.tokenData })\n );\n localStorage.removeItem('auth');\n } else {\n localStorage.setItem(\n 'auth',\n JSON.stringify({ token: userData.token, tokenData: userData.tokenData })\n );\n sessionStorage.removeItem('auth');\n }\n}\n\n/**\n * Retrieve authentication token\n *\n * @returns {object OR null} Parsed value from session or local storage, or null\n */\nexport function retrieveToken() {\n return (\n (sessionStorage.auth && JSON.parse(sessionStorage.auth)) ||\n (localStorage.auth && JSON.parse(localStorage.auth)) ||\n null\n );\n}\n\n/**\n * Remove authentication token\n */\nexport function removeToken() {\n localStorage.removeItem('auth');\n sessionStorage.removeItem('auth');\n}\n\n/**\n * Decode token\n */\nexport function decodeToken(token) {\n if (!token) return false;\n\n const base64Url = token.split('.')[1];\n const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');\n return JSON.parse(window.atob(base64));\n}\n","/**\n * WebApp reducer\n */\n\nimport {\n CART_REQUEST,\n CART_SUCCESS,\n CART_ERROR,\n CUSTOMER_REPS_REQUEST,\n CUSTOMER_REPS_SUCCESS,\n CUSTOMER_REPS_ERROR,\n MENU_REQUEST,\n MENU_SUCCESS,\n MENU_ERROR,\n MENU_UPDATE_ROUTES,\n SETTINGS_REQUEST,\n SETTINGS_SUCCESS,\n SETTINGS_ERROR,\n USER_LOGOUT_REQUEST_CLEANUP,\n WISHLIST_REQUEST,\n WISHLIST_SUCCESS,\n WISHLIST_ERROR,\n PATTIES_STATEMENT_REQUEST,\n PATTIES_STATEMENT_SUCCESS,\n PATTIES_STATEMENT_ERROR,\n} from './constants';\n\nexport const initialState = {\n cart: undefined,\n customerReps: undefined,\n menu: null,\n routes: (localStorage.routes && JSON.parse(localStorage.routes)) || undefined,\n settings: {},\n wishlist: undefined,\n};\n\nfunction webAppReducer(state = initialState, action) {\n switch (action.type) {\n case CART_REQUEST:\n if (action.refresh) {\n return state;\n }\n\n return {\n ...state,\n cart: { ...state.cart, isLoading: true } || { isLoading: true },\n };\n case CART_SUCCESS:\n return {\n ...state,\n cart: action.response,\n };\n case CART_ERROR:\n return {\n ...state,\n cart: initialState.cart,\n };\n case CUSTOMER_REPS_REQUEST:\n return {\n ...state,\n customerReps: state.customerReps || {},\n };\n case CUSTOMER_REPS_SUCCESS:\n return {\n ...state,\n customerReps: {\n data: action.response,\n lastUpdated: action.lastUpdated,\n },\n };\n case CUSTOMER_REPS_ERROR:\n return {\n ...state,\n customerReps: initialState.customerReps,\n };\n case MENU_ERROR:\n return {\n ...state,\n menu: initialState.menu,\n };\n case MENU_REQUEST:\n if (action.refresh) {\n return state;\n }\n\n return {\n ...state,\n menu: [],\n };\n case MENU_SUCCESS:\n return {\n ...state,\n menu: action.response,\n };\n case MENU_UPDATE_ROUTES:\n return {\n ...state,\n routes: action.response,\n };\n case SETTINGS_ERROR:\n return {\n ...state,\n settings: initialState.settings,\n };\n case SETTINGS_REQUEST:\n if (action.refresh) {\n return state;\n }\n\n return {\n ...state,\n settings: {\n lastUpdated: null,\n },\n };\n case SETTINGS_SUCCESS:\n return {\n ...state,\n settings: {\n ...state.settings,\n ...action.response,\n lastUpdated: action.lastUpdated,\n },\n };\n case USER_LOGOUT_REQUEST_CLEANUP:\n return {\n ...state,\n cart: initialState.cart,\n customerReps: initialState.customerReps,\n wishlist: initialState.wishlist,\n };\n case WISHLIST_REQUEST:\n if (state.wishlist) {\n return state; // Perf\n }\n\n return {\n ...state,\n wishlist: [],\n };\n case WISHLIST_SUCCESS:\n return {\n ...state,\n wishlist: action.response,\n };\n case WISHLIST_ERROR:\n return {\n ...state,\n wishlist: initialState.wishlist,\n };\n case PATTIES_STATEMENT_REQUEST:\n if (state.patties) {\n return state; // Perf\n }\n\n return {\n ...state,\n patties: [],\n };\n case PATTIES_STATEMENT_SUCCESS:\n return {\n ...state,\n patties: action.response,\n };\n case PATTIES_STATEMENT_ERROR:\n return {\n ...state,\n patties: initialState.patties,\n };\n default:\n return state;\n }\n}\n\nexport default webAppReducer;\n","import React from 'react';\nimport PropTypes from 'prop-types';\n\n// Style and SEO\nimport { css, up, styled, thd } from '@smooth-ui/core-sc';\nimport { Link } from 'react-router-dom';\nimport PrivateComponent from '_platform/src/utils/PrivateComponent';\nimport { withSettings } from 'containers/WebApp/SettingsContext';\nimport { trailingSlashIt } from '_platform/src/utils/utilities';\nimport Logo from './images/Footer-Logo@2x.png';\n\nconst FooterWrapper = styled.footer`\n background-color: #1c355e;\n`;\n\nconst FooterContainer = styled.div`\n display: flex;\n flex-direction: column;\n max-width: 1200px;\n margin-left: auto;\n margin-right: auto;\n width: 100%;\n padding: 0.94rem 0;\n justify-content: center;\n align-items: center;\n p {\n color: ${thd('primary', '#003E7E')};\n font-size: 16px;\n }\n .footer__logo {\n vertical-align: middle;\n height: 90px;\n }\n ul {\n padding-left: 0;\n list-style: none;\n display: flex;\n flex-direction: column;\n justify-content: center;\n margin: 0.8rem 0 0;\n ${up(\n 'md',\n css`\n flex-direction: row;\n `\n )};\n }\n li {\n font-size: 16px;\n color: #fff;\n text-align: center;\n padding: 5px 0;\n ${up(\n 'md',\n css`\n border-right: 1px solid #fff;\n padding: inherit;\n text-align: left;\n &:nth-last-child(1) {\n border-right: none;\n }\n `\n )};\n a {\n color: #fff;\n font-weight: bold;\n text-decoration: none;\n padding: 0.1rem 1rem;\n font-size: 14px;\n &:hover,\n &:focus {\n text-decoration: underline;\n }\n }\n }\n`;\n\nconst LogoContainers = styled.div`\n height: 100px;\n`;\n\nconst Footer = ({ siteName, location }) => (\n \n \n \n \n \n {trailingSlashIt(location.pathname) !== '/login/' && (\n
\n
\n
\n Terms & Conditions\n
\n
\n Privacy Policy\n
\n \n
\n FAQs\n
\n \n
\n Sitemap\n
\n
\n
\n )}\n \n \n);\n\nFooter.propTypes = {\n siteName: PropTypes.string,\n location: PropTypes.object.isRequired,\n};\n\nFooter.defaultProps = {\n siteName: 'Lori Program Default',\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';\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 pattiesStatementRequest,\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 selectPatties,\n} from './selectors';\nimport { SettingsProvider } from './SettingsContext';\n\n// Additional Components/Containers\nimport { trailingSlashIt } from '_platform/src/utils/utilities';\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);\nconst Welcome = LoadAsync(() =>\n import(/* webpackChunkName: \"welcome\" */ 'containers/Welcome/Welcome')\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 if (\n this.props.patties === undefined ||\n this.props.patties.lastUpdated === undefined\n ) {\n this.props.onPattiesStatementRequest();\n }\n }\n }\n\n render() {\n const { theme } = this.props;\n\n return (\n \n \n \n \n \n \n \n \n {trailingSlashIt(this.props.location.pathname) !==\n '/login/' && (\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 {this.props.cart && !this.props.cart.isLoading && (\n \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 patties: PropTypes.object,\n onPattiesStatementRequest: PropTypes.func.isRequired,\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 patties: 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 patties: selectPatties(),\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 onPattiesStatementRequest: refresh =>\n dispatch(pattiesStatementRequest(refresh)),\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","import configureStore from './core/configureStore'; // _platform\nimport history from './history'; // _platform\n\nconst initialState = {};\nconst store = configureStore(initialState, history);\n// Note: Store is exported in order to be used in utils/request\n\nexport default store;\n","import { createStore, compose, applyMiddleware } from 'redux';\nimport createSagaMiddleware from 'redux-saga';\n\nimport createReducer from './reducers';\n\nexport default function configureStore(initialState = {}, history) {\n let composeEnhancers = compose;\n let reduxSagaMonitorOptions = {};\n\n // If Redux DevTools and Saga Dev Tools Extensions are installed, enable them. Otherwise use Redux compose\n /* eslint-disable no-underscore-dangle */\n if (process.env.NODE_ENV !== 'production' && typeof window === 'object') {\n // Redux DevTools\n if (window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) {\n composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({\n // shouldHotReload: false,\n });\n }\n\n // Saga Dev Tools - enable once it supports redux-saga 1.x.x\n if (window.window.__SAGA_MONITOR_EXTENSION__) {\n reduxSagaMonitorOptions = {\n sagaMonitor: window.__SAGA_MONITOR_EXTENSION__,\n };\n }\n }\n /* eslint-enable */\n\n // Create the middlewares\n // 1. sagaMiddleware - redux-saga\n // 2. logger - redux-logger\n const sagaMiddleware = createSagaMiddleware(reduxSagaMonitorOptions);\n const middlewares = [sagaMiddleware];\n\n if (process.env.NODE_ENV === 'development') {\n // Add redux-logger in dev environment as it was added as a devDependency\n const { createLogger } = require('redux-logger');\n\n const logger = createLogger({\n collapsed: true,\n duration: true,\n });\n\n middlewares.push(logger);\n }\n\n const enhancers = [applyMiddleware(...middlewares)];\n\n // Create the store\n const store = createStore(\n createReducer(),\n initialState,\n composeEnhancers(...enhancers)\n );\n\n // Extensions\n store.runSaga = sagaMiddleware.run;\n store.injectedReducers = {}; // Register reducers\n store.injectedSagas = {}; // Register saga\n\n // Make reducers hot reloadable\n // https://github.com/wesbos/Learn-Redux/blob/master/client/store.js\n if (module.hot) {\n module.hot.accept('./reducers', () => {\n store.replaceReducer(createReducer(store.injectedReducers));\n });\n }\n\n return store;\n}\n"],"sourceRoot":""}