{"version":3,"sources":["web/ajax.js","components/Product.jsx","components/PageLoading.jsx","components/Products.jsx","components/Search.jsx","components/Header.jsx","components/ProductImageCarousel.jsx","utils/inventory.js","components/ProductInventory.jsx","components/ProductColorSelector.jsx","components/PageError.jsx","components/ProductPage.jsx","components/Layout.jsx","App.js","serviceWorker.js","index.js"],"names":["get","url","a","fetch","method","mode","headers","readResult","response","result","success","ok","status","json","message","Message","Product","product","this","props","className","to","id","src","image","alt","title","React","Component","PageLoading","role","Spinner","animation","Products","products","isLoaded","productList","map","item","key","Search","handleChange","e","value","target","suggestions","length","filter","p","toUpperCase","includes","sort","b","slice","setState","text","handleBlur","handleProductClick","renderSuggestions","state","onClick","noValidate","type","placeholder","onChange","onFocus","autoComplete","Header","href","ProductImageCarousel","activeIndex","selectedVariantImageId","onSelect","desiredIndex","images","findIndex","img","carouselItemsList","idx","Carousel","Item","width","viewBox","height","flattenInventoryData","inventory","results","forEach","inv","record","Color","Quantity","Ship_Eta","Ship_Qty","Shipments","ship","push","Eta","calculateUpcomingShipments","onHandQty","shipments","Date","i","shift","prepareDataForInventoryTable","find","r","ProductInventory","isSelectedLocale","locale","selectedLocale","getLocales","locales","onLocaleChange","Code","htmlFor","name","checked","Region","getInventoryTableData","shipmentsList","shipmentsRows","index","toLocaleDateString","Fragment","data-toggle","scope","ProductColorSelector","selectedColor","dropdownItemsList","variants","variant","Dropdown","as","option1","DropdownButton","PageError","heading","content","ProductPage","componentDidMount","getProductData","componentDidUpdate","prevProps","productId","match","params","process","productFetchResult","Error","Locale","localeInventory","Variations","selectedVariant","isError","handleCarouselSelection","selectedIndex","handleColorSelection","variantId","matchingVariant","renderProductWeight","weight","weight_unit","handleLocaleChange","newLocaleCode","currentTarget","matchingInventory","getAvailableLocales","getErrorInfo","errorContent","aria-label","image_id","ReactHtmlParser","body_html","Layout","getProducts","jsonResult","selectedProduct","path","component","children","App","Boolean","window","location","hostname","ReactDOM","render","document","getElementById","navigator","serviceWorker","ready","then","registration","unregister","catch","error","console"],"mappings":"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","file":"static/js/main.fff1c194.chunk.js","sourcesContent":["/**\r\n * Makes an AJAX request with the specified configuration\r\n * @param {string} url Url to call\r\n */\r\nexport async function get(url) {\r\n return await fetch(url, {\r\n method: \"GET\",\r\n mode: \"cors\",\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n },\r\n });\r\n // return await response.json();\r\n}\r\n\r\n/**\r\n * Reads a GET request response and returns network info along with data (if success)\r\n * @param {Object} response Response from a GET request\r\n */\r\nexport async function readResult(response) {\r\n let result = {};\r\n\r\n if (response) {\r\n result.success = response.ok;\r\n result.status = response.status;\r\n\r\n const json = await response.json();\r\n\r\n if (!response.ok) {\r\n result.message = json.Message || \"unknown error\";\r\n } else {\r\n result = { ...result, ...json };\r\n }\r\n }\r\n\r\n return result;\r\n}\r\n","import React from \"react\";\r\nimport { Link } from \"react-router-dom\";\r\nimport \"../styles/Product.css\";\r\n\r\nexport class Product extends React.Component {\r\n render() {\r\n const { product } = this.props;\r\n return (\r\n
\r\n
\r\n \r\n \r\n
\r\n

{product.title}

\r\n
\r\n \r\n
\r\n
\r\n );\r\n }\r\n}\r\n\r\nexport default Product;\r\n","import React, { Component } from \"react\";\r\nimport { Spinner } from \"react-bootstrap\";\r\n\r\nclass PageLoading extends Component {\r\n render() {\r\n const { role } = this.props;\r\n\r\n return (\r\n \r\n Loading...\r\n \r\n );\r\n }\r\n}\r\n\r\nexport default PageLoading;\r\n","import React, { Component } from \"react\";\r\nimport Product from \"./Product\";\r\nimport PageLoading from \"./PageLoading\";\r\nimport \"../styles/Loading.css\";\r\n\r\nclass Products extends Component {\r\n render() {\r\n const { products, isLoaded } = this.props;\r\n const productList = products.map((item) => {\r\n return ;\r\n });\r\n\r\n let content;\r\n\r\n if (isLoaded) {\r\n content =
{productList}
;\r\n } else {\r\n content = (
\r\n \r\n
);\r\n }\r\n return content;\r\n }\r\n}\r\n\r\nexport default Products;\r\n","import React, { Component } from \"react\";\r\nimport { Link } from \"react-router-dom\";\r\nimport \"../styles/Search.css\";\r\n\r\n/**\r\n * Search bar for all the products.\r\n *\r\n * Allows the user to search by keyword that appears\r\n * in the title of the product.\r\n */\r\nclass Search extends Component {\r\n constructor(props) {\r\n super(props);\r\n this.state = {\r\n suggestions: [],\r\n text: \"\",\r\n };\r\n }\r\n\r\n handleChange = (e) => {\r\n const value = e.target.value;\r\n let suggestions = [];\r\n\r\n if (value.length > 0) {\r\n // Get the first 5 products that ressemble the inputted value\r\n suggestions = this.props.products\r\n .filter((p) => p.title.toUpperCase().includes(value.toUpperCase()))\r\n .sort((a, b) => a.title - b.title)\r\n .slice(0, 5);\r\n }\r\n\r\n this.setState({ suggestions, text: value });\r\n };\r\n\r\n handleBlur = () => {\r\n this.setState({ suggestions: [] });\r\n };\r\n\r\n handleProductClick = (product) => {\r\n this.setState({ suggestions: [], text: \"\" });\r\n };\r\n\r\n renderSuggestions = () => {\r\n const { suggestions } = this.state;\r\n if (suggestions.length === 0) return null;\r\n\r\n return (\r\n \r\n );\r\n };\r\n\r\n render() {\r\n return (\r\n
\r\n
\r\n \r\n {this.renderSuggestions()}\r\n \r\n
\r\n );\r\n }\r\n}\r\n\r\nexport default Search;\r\n","import React, { Component } from \"react\";\r\nimport Search from \"./Search\";\r\nimport \"../styles/Header.css\";\r\n\r\nclass Header extends Component {\r\n render() {\r\n const logoUri = process.env.PUBLIC_URL + \"/asobu-logo.png\";\r\n const { products } = this.props;\r\n\r\n return (\r\n \r\n );\r\n }\r\n}\r\n\r\nexport default Header;\r\n","import React from \"react\";\r\nimport { Carousel } from \"react-bootstrap\";\r\nimport \"../styles/ProductImageCarousel.css\";\r\n\r\nclass ProductImageCarousel extends React.Component {\r\n render() {\r\n const {\r\n product,\r\n activeIndex,\r\n selectedVariantImageId,\r\n onSelect,\r\n } = this.props;\r\n\r\n // Use the given id if specified directly by user (arrows)\r\n // Or if the color was selected in the dropdown find the\r\n // matching image id and use that index in the carousel\r\n const desiredIndex =\r\n activeIndex !== -1\r\n ? activeIndex\r\n : product.images.findIndex((img) => img.id === selectedVariantImageId);\r\n\r\n // Create the carousel item list\r\n const carouselItemsList = product.images.map((img, idx) => {\r\n return (\r\n \r\n \r\n \r\n \r\n \r\n );\r\n });\r\n\r\n return (\r\n \r\n {carouselItemsList}\r\n \r\n );\r\n }\r\n}\r\n\r\nexport default ProductImageCarousel;\r\n","/**\r\n * Creates a single dimension array for the inventory data.\r\n *\r\n * @param {Array} inventory Inventory array for a particular locale\r\n */\r\nexport const flattenInventoryData = (inventory) => {\r\n const results = [];\r\n inventory.forEach((inv) => {\r\n // Create a default record data with at least the color and onHandQty\r\n const record = {\r\n Color: inv.Color,\r\n Quantity: inv.Quantity,\r\n Ship_Eta: null,\r\n Ship_Qty: null,\r\n };\r\n\r\n if (inv.Shipments && inv.Shipments.length !== 0) {\r\n inv.Shipments.forEach((ship) => {\r\n // Add the shipment details\r\n results.push({\r\n ...record,\r\n Ship_Eta: ship.Eta,\r\n Ship_Qty: ship.Quantity,\r\n });\r\n });\r\n } else {\r\n results.push(record);\r\n }\r\n });\r\n\r\n return results;\r\n};\r\n\r\n/**\r\n * Calculates the on hand quantity of the inventory item taking\r\n * into consideration upcoming shipments and current stock.\r\n *\r\n * If there is reserved stock (ie. invItem.Quantity < 0),\r\n * the item will subtract the stock from the upcoming shipments and\r\n * remove those shipments from the list.\r\n *\r\n * @param {Object} invItem Inventory item for a single color\r\n */\r\nexport const calculateUpcomingShipments = (inventory) => {\r\n const results = [];\r\n\r\n inventory.forEach((inv) => {\r\n let onHandQty = inv.Quantity;\r\n\r\n // Ensure shipments are ordered earliest first\r\n let shipments = [...inv.Shipments]\r\n .map((ship) => {\r\n return { ...ship, Eta: new Date(ship.Eta) };\r\n })\r\n .sort((a, b) => a.Eta - b.Eta);\r\n\r\n let i = 0;\r\n while (onHandQty < 0 && i < shipments.length) {\r\n // Note: onHandQty is negative here\r\n if (shipments[i].Quantity + onHandQty > 0) {\r\n // Adjust on hand qty to 0 and subtract reserved stock from first shipment\r\n shipments[i].Quantity += onHandQty;\r\n onHandQty = 0;\r\n i++;\r\n } else {\r\n // Adjust on hand qty with shipment amount and remove shipment\r\n onHandQty += shipments[i].Quantity;\r\n shipments.shift();\r\n }\r\n }\r\n\r\n if (onHandQty < 0 && shipments.length === 0) {\r\n onHandQty = 0;\r\n }\r\n\r\n results.push({ ...inv, Quantity: onHandQty, Shipments: shipments });\r\n });\r\n\r\n return results;\r\n};\r\n\r\n/**\r\n * Remove the color and onHandQty of every subsequent inventory\r\n * item. Those fields should only appear once.\r\n *\r\n * @param {Array} inventory Inventory item data array\r\n */\r\nexport const prepareDataForInventoryTable = (inventory) => {\r\n const results = [];\r\n\r\n inventory.forEach((inv) => {\r\n if (results.find((r) => r.Color === inv.Color)) {\r\n // If there is already this color, only add the shipments details\r\n results.push({\r\n ...inv,\r\n Color: null,\r\n Quantity: null,\r\n });\r\n } else {\r\n results.push({ ...inv });\r\n }\r\n });\r\n\r\n return results;\r\n};\r\n","import React, { Component } from \"react\";\r\nimport {\r\n flattenInventoryData,\r\n calculateUpcomingShipments,\r\n prepareDataForInventoryTable,\r\n} from \"../utils/inventory\";\r\n\r\nclass ProductInventory extends Component {\r\n /**\r\n * Comparing the selected locale code (eg. NA or EU) to the\r\n * specified locale code.\r\n *\r\n * @param {String} locale The locale code eg. NA or EU\r\n */\r\n isSelectedLocale = (locale) => {\r\n return this.props.selectedLocale === locale;\r\n };\r\n\r\n getLocales = () => {\r\n const { locales, onLocaleChange, type } = this.props;\r\n\r\n return locales.map((locale) => {\r\n return (\r\n // Create a radio option for each inventory region\r\n \r\n null} // Swallowing the event because there is a bug with onChange\r\n value={locale.Code}\r\n />\r\n {locale.Region}\r\n \r\n );\r\n });\r\n };\r\n\r\n getInventoryTableData = () => {\r\n const inventory = [...this.props.inventory];\r\n\r\n // Adjust current stock with upcoming shipments\r\n let shipmentsList = calculateUpcomingShipments(inventory);\r\n\r\n // Make the data single dimension\r\n shipmentsList = flattenInventoryData(shipmentsList);\r\n\r\n // Remove duplicate colors and onHandQty\r\n shipmentsList = prepareDataForInventoryTable(shipmentsList);\r\n\r\n const shipmentsRows = shipmentsList.map((ship, index) => {\r\n return (\r\n \r\n {ship.Color}\r\n {ship.Quantity}\r\n {ship.Ship_Eta ? ship.Ship_Eta.toLocaleDateString() : \"-\"}\r\n {ship.Ship_Qty ? ship.Ship_Qty : \"-\"}\r\n \r\n );\r\n });\r\n\r\n return {shipmentsRows};\r\n };\r\n\r\n render() {\r\n return (\r\n \r\n

Product Inventory

\r\n
\r\n {this.getLocales()}\r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n {this.getInventoryTableData()}\r\n
ColorOn-Hand QuantityUpcoming ShipmentsShipment Quantities
\r\n
\r\n );\r\n }\r\n}\r\n\r\nexport default ProductInventory;\r\n","import React, { Component } from \"react\";\r\nimport { Dropdown, DropdownButton } from \"react-bootstrap\";\r\n\r\nimport \"../scss/ProductColorSelector.scss\";\r\n\r\nclass ProductColorSelector extends Component {\r\n render() {\r\n const { product, selectedColor, onSelect } = this.props;\r\n\r\n const dropdownItemsList = product.variants.map((variant, idx) => {\r\n // Create the dropdown item for each color\r\n return (\r\n onSelect(variant.id)}\r\n >\r\n {variant.option1}\r\n \r\n );\r\n });\r\n\r\n return (\r\n \r\n {dropdownItemsList}\r\n \r\n );\r\n }\r\n}\r\n\r\nexport default ProductColorSelector;\r\n","import React, { Component } from \"react\";\r\n\r\nclass PageError extends Component {\r\n render() {\r\n const heading = this.props.title || \"Error\";\r\n const content =\r\n this.props.content ||\r\n \"Something went wrong :( \\n Please report this issue\";\r\n return (\r\n
\r\n

{heading}

\r\n

{content}

\r\n
\r\n );\r\n }\r\n}\r\n\r\nexport default PageError;\r\n","import React, { Component } from \"react\";\r\nimport { Link } from \"react-router-dom\";\r\nimport ReactHtmlParser from \"react-html-parser\";\r\nimport { get, readResult } from \"../web/ajax\";\r\nimport ProductImageCarousel from \"./ProductImageCarousel\";\r\nimport ProductInventory from \"./ProductInventory\";\r\nimport ProductColorSelector from \"./ProductColorSelector\";\r\nimport PageError from \"./PageError\";\r\nimport PageLoading from \"./PageLoading\";\r\nimport \"../styles/Loading.css\";\r\n\r\nclass ProductPage extends Component {\r\n constructor(props) {\r\n super(props);\r\n this.state = {\r\n product: null,\r\n isLoaded: false,\r\n isError: false,\r\n activeIndex: 0,\r\n selectedLocale: null,\r\n localeInventory: [],\r\n selectedVariant: null,\r\n productFetchResult: null,\r\n };\r\n }\r\n\r\n componentDidMount = () => {\r\n this.getProductData();\r\n };\r\n\r\n componentDidUpdate = (prevProps) => {\r\n const productId = this.props.match.params.id;\r\n const prevProductId = prevProps.match.params.id;\r\n if (prevProductId !== productId) {\r\n this.setState({ isLoaded: false });\r\n this.getProductData();\r\n }\r\n };\r\n\r\n getProductData = async () => {\r\n const baseUrl = process.env.REACT_APP_ADNART_API_ENDPOINT;\r\n const id = this.props.match.params.id;\r\n const url = `${baseUrl}/products/${id}`;\r\n\r\n let productFetchResult;\r\n\r\n try {\r\n // Get the product details\r\n const result = await get(url);\r\n productFetchResult = await readResult(result);\r\n if (!productFetchResult.success) {\r\n throw new Error(\"GET request failed\");\r\n }\r\n\r\n const product = productFetchResult.products[0];\r\n\r\n // Get the first inventory in the list as the default selected locale\r\n const selectedLocale = product.inventory[0].Locale.Code;\r\n const localeInventory = [...product.inventory[0].Variations];\r\n\r\n const selectedVariant = { ...product.variants[0] };\r\n\r\n this.setState({\r\n isLoaded: true,\r\n product,\r\n selectedLocale,\r\n localeInventory,\r\n selectedVariant,\r\n productFetchResult,\r\n });\r\n } catch (err) {\r\n this.setState({ isError: true, productFetchResult });\r\n }\r\n };\r\n\r\n handleCarouselSelection = (selectedIndex, e) => {\r\n this.setState({ activeIndex: selectedIndex });\r\n };\r\n\r\n handleColorSelection = (variantId) => {\r\n // Find the matching variant and cache its data\r\n const matchingVariant = this.state.product.variants.find(\r\n (variant) => variant.id === variantId\r\n );\r\n // Setting the image index to -1 indicates manual user color selection\r\n this.setState({\r\n selectedVariant: matchingVariant,\r\n activeIndex: -1,\r\n });\r\n };\r\n\r\n renderProductWeight = () => {\r\n // Only show weight if it is provided\r\n const { weight, weight_unit } = this.state.selectedVariant;\r\n if (!weight) return null;\r\n\r\n return (\r\n

\r\n Weight - {weight} \r\n {weight_unit}\r\n

\r\n );\r\n };\r\n\r\n handleLocaleChange = (e) => {\r\n const { product, selectedLocale } = this.state;\r\n const newLocaleCode = e.currentTarget.value;\r\n\r\n if (newLocaleCode !== selectedLocale) {\r\n // Find the matching inventory data that corresponds with the new locale\r\n const matchingInventory = [\r\n ...product.inventory.find((inv) => inv.Locale.Code === newLocaleCode)\r\n .Variations,\r\n ];\r\n this.setState({\r\n selectedLocale: newLocaleCode,\r\n localeInventory: matchingInventory,\r\n });\r\n }\r\n };\r\n\r\n getAvailableLocales = () => {\r\n const { product } = this.state;\r\n let locales = [];\r\n\r\n if (!!product) {\r\n // Get each available locale for the current product\r\n product.inventory.forEach((inv) => {\r\n locales.push({ ...inv.Locale });\r\n });\r\n }\r\n\r\n return locales;\r\n };\r\n\r\n getErrorInfo = () => {\r\n const { product, productFetchResult } = this.state;\r\n const { match } = this.props;\r\n const productId = !!product ? product.title : match.params.id;\r\n let status, message;\r\n\r\n if (\r\n !!productFetchResult &&\r\n !!productFetchResult.status &&\r\n !!productFetchResult.message\r\n ) {\r\n status = productFetchResult.status;\r\n message = productFetchResult.message;\r\n }\r\n\r\n const errorContent = (\r\n

\r\n Error - {`${status} - ${message}`}\r\n
\r\n Please report this issue! Product ID: {productId}\r\n

\r\n );\r\n\r\n return ;\r\n };\r\n\r\n render() {\r\n const {\r\n product,\r\n isError,\r\n isLoaded,\r\n activeIndex,\r\n selectedLocale,\r\n localeInventory,\r\n selectedVariant,\r\n } = this.state;\r\n\r\n let content;\r\n if (isError) {\r\n content = this.getErrorInfo();\r\n } else if (!isLoaded) {\r\n content = (\r\n
\r\n \r\n
\r\n );\r\n } else {\r\n // Product data is finished loaded\r\n content = (\r\n
\r\n
\r\n \r\n \r\n All products\r\n \r\n \r\n
\r\n
\r\n
\r\n \r\n
\r\n
\r\n

{product.title}

\r\n \r\n
\r\n {ReactHtmlParser(product.body_html)}\r\n {this.renderProductWeight()}\r\n
\r\n
\r\n \r\n
\r\n
\r\n
\r\n );\r\n }\r\n\r\n return content;\r\n }\r\n}\r\n\r\nexport default ProductPage;\r\n","import React, { Component } from \"react\";\r\nimport { Route, Switch } from \"react-router-dom\";\r\n\r\nimport { get } from \"../web/ajax\";\r\n\r\nimport Products from \"./Products\";\r\nimport Header from \"./Header\";\r\nimport ProductPage from \"./ProductPage\";\r\n\r\nclass Layout extends Component {\r\n constructor(props) {\r\n super(props);\r\n this.state = {\r\n products: [],\r\n selectedProduct: null,\r\n isLoaded: false,\r\n };\r\n }\r\n\r\n componentDidMount = () => {\r\n this.getProducts();\r\n };\r\n\r\n getProducts = async () => {\r\n this.setState({isLoaded: false});\r\n const url = process.env.REACT_APP_ADNART_API_ENDPOINT + \"/products/\";\r\n const result = await get(url);\r\n const jsonResult = await result.json();\r\n if (jsonResult) {\r\n this.setState({ products: jsonResult.products, isLoaded: true });\r\n }\r\n };\r\n\r\n render() {\r\n const { products, isLoaded } = this.state;\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\nexport default Layout;\r\n","import React from \"react\";\r\nimport \"./App.css\";\r\nimport Layout from \"./components/Layout\";\r\n\r\nclass App extends React.Component {\r\n render() {\r\n return (\r\n
\r\n \r\n
\r\n );\r\n }\r\n}\r\n\r\nexport default App;\r\n","// This optional code is used to register a service worker.\r\n// register() is not called by default.\r\n\r\n// This lets the app load faster on subsequent visits in production, and gives\r\n// it offline capabilities. However, it also means that developers (and users)\r\n// will only see deployed updates on subsequent visits to a page, after all the\r\n// existing tabs open on the page have been closed, since previously cached\r\n// resources are updated in the background.\r\n\r\n// To learn more about the benefits of this model and instructions on how to\r\n// opt-in, read https://bit.ly/CRA-PWA\r\n\r\nconst isLocalhost = Boolean(\r\n window.location.hostname === 'localhost' ||\r\n // [::1] is the IPv6 localhost address.\r\n window.location.hostname === '[::1]' ||\r\n // 127.0.0.0/8 are considered localhost for IPv4.\r\n window.location.hostname.match(\r\n /^127(?:\\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/\r\n )\r\n);\r\n\r\nexport function register(config) {\r\n if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {\r\n // The URL constructor is available in all browsers that support SW.\r\n const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);\r\n if (publicUrl.origin !== window.location.origin) {\r\n // Our service worker won't work if PUBLIC_URL is on a different origin\r\n // from what our page is served on. This might happen if a CDN is used to\r\n // serve assets; see https://github.com/facebook/create-react-app/issues/2374\r\n return;\r\n }\r\n\r\n window.addEventListener('load', () => {\r\n const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;\r\n\r\n if (isLocalhost) {\r\n // This is running on localhost. Let's check if a service worker still exists or not.\r\n checkValidServiceWorker(swUrl, config);\r\n\r\n // Add some additional logging to localhost, pointing developers to the\r\n // service worker/PWA documentation.\r\n navigator.serviceWorker.ready.then(() => {\r\n console.log(\r\n 'This web app is being served cache-first by a service ' +\r\n 'worker. To learn more, visit https://bit.ly/CRA-PWA'\r\n );\r\n });\r\n } else {\r\n // Is not localhost. Just register service worker\r\n registerValidSW(swUrl, config);\r\n }\r\n });\r\n }\r\n}\r\n\r\nfunction registerValidSW(swUrl, config) {\r\n navigator.serviceWorker\r\n .register(swUrl)\r\n .then(registration => {\r\n registration.onupdatefound = () => {\r\n const installingWorker = registration.installing;\r\n if (installingWorker == null) {\r\n return;\r\n }\r\n installingWorker.onstatechange = () => {\r\n if (installingWorker.state === 'installed') {\r\n if (navigator.serviceWorker.controller) {\r\n // At this point, the updated precached content has been fetched,\r\n // but the previous service worker will still serve the older\r\n // content until all client tabs are closed.\r\n console.log(\r\n 'New content is available and will be used when all ' +\r\n 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'\r\n );\r\n\r\n // Execute callback\r\n if (config && config.onUpdate) {\r\n config.onUpdate(registration);\r\n }\r\n } else {\r\n // At this point, everything has been precached.\r\n // It's the perfect time to display a\r\n // \"Content is cached for offline use.\" message.\r\n console.log('Content is cached for offline use.');\r\n\r\n // Execute callback\r\n if (config && config.onSuccess) {\r\n config.onSuccess(registration);\r\n }\r\n }\r\n }\r\n };\r\n };\r\n })\r\n .catch(error => {\r\n console.error('Error during service worker registration:', error);\r\n });\r\n}\r\n\r\nfunction checkValidServiceWorker(swUrl, config) {\r\n // Check if the service worker can be found. If it can't reload the page.\r\n fetch(swUrl, {\r\n headers: { 'Service-Worker': 'script' },\r\n })\r\n .then(response => {\r\n // Ensure service worker exists, and that we really are getting a JS file.\r\n const contentType = response.headers.get('content-type');\r\n if (\r\n response.status === 404 ||\r\n (contentType != null && contentType.indexOf('javascript') === -1)\r\n ) {\r\n // No service worker found. Probably a different app. Reload the page.\r\n navigator.serviceWorker.ready.then(registration => {\r\n registration.unregister().then(() => {\r\n window.location.reload();\r\n });\r\n });\r\n } else {\r\n // Service worker found. Proceed as normal.\r\n registerValidSW(swUrl, config);\r\n }\r\n })\r\n .catch(() => {\r\n console.log(\r\n 'No internet connection found. App is running in offline mode.'\r\n );\r\n });\r\n}\r\n\r\nexport function unregister() {\r\n if ('serviceWorker' in navigator) {\r\n navigator.serviceWorker.ready\r\n .then(registration => {\r\n registration.unregister();\r\n })\r\n .catch(error => {\r\n console.error(error.message);\r\n });\r\n }\r\n}\r\n","import \"bootstrap/dist/css/bootstrap.min.css\";\r\nimport \"./css/custom-theme.css\";\r\nimport React from \"react\";\r\nimport ReactDOM from \"react-dom\";\r\nimport \"./index.css\";\r\nimport App from \"./App\";\r\nimport * as serviceWorker from \"./serviceWorker\";\r\nimport { BrowserRouter } from \"react-router-dom\";\r\n\r\nReactDOM.render(\r\n \r\n \r\n ,\r\n document.getElementById(\"root\")\r\n);\r\n\r\n// If you want your app to work offline and load faster, you can change\r\n// unregister() to register() below. Note this comes with some pitfalls.\r\n// Learn more about service workers: https://bit.ly/CRA-PWA\r\nserviceWorker.unregister();\r\n"],"sourceRoot":""}