{"version":3,"sources":["redux/reducers.ts","components/Header.tsx","utils/index.ts","config.ts","redux/actions.ts","components/PasteForm.tsx","components/Error.tsx","pages/Home.tsx","components/PasteDetails.tsx","pages/PasteViewer.tsx","pages/NotFound.tsx","themes/theme.ts","App.tsx","serviceWorker.js","index.tsx","redux/store.ts"],"names":["rootReducer","combineReducers","isFetching","state","action","type","payload","error","activePaste","initialState","useStyles","makeStyles","theme","root","width","padding","diplay","justifyContent","alignItems","minWidth","margin","paddingBottom","borderBottom","palette","primary","main","textDecoration","color","Header","classes","Toolbar","className","Typography","variant","to","convertToPaste","data","pasteUrl","title","content","ttl","timestamp","_ts","config","frontend_url","backend_url","get_paste_function_key","post_paste_function_key","setIsFetching","status","setError","errorDetails","setActivePaste","paste","flexFlow","whiteSpace","PasteForm","dispatch","useDispatch","history","useHistory","useState","setState","redirectToCreatedPaste","push","TextField","label","fullWidth","length","helperText","onBlur","event","target","value","multiline","rows","InputLabel","id","Select","labelId","required","defaultValue","onChange","seconds","map","index","MenuItem","key","Button","onClick","newPaste","trim","callback","getState","a","fetch","method","headers","body","JSON","stringify","res","json","detail","instance","postPaste","text","backgroundColor","background","default","Error","message","lineHeight","marginBottom","Home","useSelector","gutterBottom","Link","href","overflow","PasteDetails","moment","unix","format","component","PasteViewer","useParams","pasteIsLoaded","setPasteIsLoaded","useEffect","getPaste","CircularProgress","NotFound","createMuiTheme","contrastText","secondary","disabled","hint","divider","paper","active","hover","hoverOpacity","selected","selectedOpacity","disabledBackground","disabledOpacity","focus","focusOpacity","activatedOpacity","typography","fontFamily","body2","App","ThemeProvider","path","Boolean","window","location","hostname","match","store","preloadedState","createStore","applyMiddleware","thunkMiddleware","configureStore","ReactDOM","render","document","getElementById","navigator","serviceWorker","ready","then","registration","unregister","catch","console"],"mappings":"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","file":"static/js/main.665cb0f6.chunk.js","sourcesContent":["import { combineReducers } from 'redux';\r\nimport { ErrorDetails } from '../models/ErrorDetails';\r\nimport { Paste } from '../models/Paste';\r\nimport { ReduxAction } from '../models/ReduxAction';\r\nimport { ReduxState } from '../models/ReduxState';\r\n\r\nexport const isFetching = (state: boolean = false, action: ReduxAction) => {\r\n return action.type === \"SET_IS_FETCHING\" ? action.payload : state;\r\n};\r\n\r\nexport const error = (state: ErrorDetails | null = null, action: ReduxAction) => {\r\n return action.type === \"SET_ERROR\" ? action.payload : state;\r\n};\r\n\r\nexport const activePaste = (state: Paste | null = null, action: ReduxAction) => {\r\n return action.type === \"SET_ACTIVE_PASTE\" ? action.payload : state;\r\n};\r\n\r\nexport const rootReducer = combineReducers({\r\n isFetching,\r\n error,\r\n activePaste\r\n});\r\n\r\nexport const initialState: ReduxState = {\r\n isFetching: false,\r\n error: null,\r\n activePaste: null,\r\n};","import React from 'react';\r\nimport { makeStyles } from '@material-ui/core/styles';\r\nimport { Toolbar, Typography } from '@material-ui/core';\r\nimport { Link } from 'react-router-dom';\r\n\r\nconst useStyles = makeStyles(theme => ({\r\n root: {\r\n width: '100%',\r\n padding: '1.5em 0',\r\n diplay: 'flex',\r\n justifyContent: 'center',\r\n alignItems: 'center',\r\n \"& .MuiTypography-root\": {\r\n width: '60%',\r\n minWidth: '280px',\r\n margin: '0 auto 10px auto',\r\n paddingBottom: '0.5em',\r\n borderBottom: `2px solid ${theme.palette.primary.main}`,\r\n },\r\n \"& .link\": {\r\n textDecoration: 'none',\r\n color: theme.palette.primary.main,\r\n },\r\n }\r\n}));\r\n\r\nfunction Header() {\r\n const classes = useStyles();\r\n\r\n return (\r\n \r\n \r\n \r\n pastebin\r\n \r\n \r\n \r\n )\r\n}\r\n\r\nexport { Header };","import { Paste } from '../models/Paste';\r\n\r\n// Check if paste has non-empty title and content\r\nexport const validatePaste = (paste: Paste): boolean => {\r\n return paste.title.trim().length > 0 && paste.content.trim().length > 0;\r\n}\r\n\r\n// Convert JSON data from api responses into Paste objects\r\nexport const convertToPaste = (data: any): Paste => {\r\n const newPaste: Paste = {\r\n pasteUrl: data.pasteUrl,\r\n title: data.title,\r\n content: data.content,\r\n ttl: data.ttl,\r\n timestamp: data._ts\r\n };\r\n return newPaste;\r\n}","interface AppConfig {\r\n frontend_url: string,\r\n backend_url: string;\r\n get_paste_function_key: string;\r\n post_paste_function_key: string;\r\n}\r\n\r\nconst config: AppConfig = {\r\n frontend_url: 'https://pastebin-zandrexrc.azureedge.net/',\r\n backend_url: 'https://pastebin-zandrexrc.azurewebsites.net/api/pastes',\r\n get_paste_function_key: '9wRzYGypAq1z2l6gwn4aaSnx9sp46uva4zHSGfoGB6/6sJuO9xc7ww==',\r\n post_paste_function_key: 'UWoe1NA4a1y0EEjY5OdLr/urJkZ1r2nqRBLPc5s16zRIdB6WbzzZDA=='\r\n}\r\n\r\nexport default config;\r\n","import fetch from 'cross-fetch';\r\nimport { ErrorDetails } from '../models/ErrorDetails';\r\nimport { Paste } from '../models/Paste';\r\nimport { ReduxThunk } from '../models/ReduxThunk';\r\nimport { convertToPaste } from '../utils';\r\nimport config from '../config';\r\n\r\nexport const setIsFetching = (status: boolean) => ({\r\n type: \"SET_IS_FETCHING\",\r\n payload: status,\r\n});\r\n\r\nexport const setError = (errorDetails: ErrorDetails | null) => ({\r\n type: \"SET_ERROR\",\r\n payload: errorDetails,\r\n});\r\n\r\nexport const setActivePaste = (paste: Paste) => ({\r\n type: \"SET_ACTIVE_PASTE\",\r\n payload: paste,\r\n});\r\n\r\nexport const getPaste = (pasteUrl: string): ReduxThunk => \r\n async (dispatch, getState) => {\r\n if (!getState().isFetching) {\r\n dispatch(setIsFetching(true));\r\n try {\r\n const res = await fetch(\r\n `${config.backend_url}/${pasteUrl}`,\r\n {\r\n method: 'GET',\r\n headers: {\r\n 'x-functions-key': config.get_paste_function_key\r\n }\r\n }\r\n );\r\n const payload = await res.json();\r\n\r\n if (payload.error) {\r\n dispatch(setError(payload.error));\r\n } else {\r\n const newPaste = convertToPaste(payload)\r\n dispatch(setActivePaste(newPaste));\r\n dispatch(setError(null));\r\n }\r\n }\r\n catch (error) {\r\n const errorDetails = {\r\n status: 503,\r\n title: \"Connection error\",\r\n detail: \"Failed to connect to the server\",\r\n type: \"/errors/network-error\",\r\n instance: `${config.frontend_url}/${pasteUrl}`\r\n };\r\n dispatch(setError(errorDetails));\r\n } finally {\r\n dispatch(setIsFetching(false));\r\n }\r\n }\r\n }\r\n\r\nexport const postPaste = (paste: Paste, callback: (pasteUrl: string) => void): ReduxThunk => \r\n async (dispatch, getState) => {\r\n if (!getState().isFetching) {\r\n dispatch(setIsFetching(true));\r\n try {\r\n const res = await fetch(\r\n `${config.backend_url}`,\r\n {\r\n method: 'POST',\r\n headers: { \r\n 'Content-Type': 'application/json',\r\n 'x-functions-key': config.post_paste_function_key\r\n },\r\n body: JSON.stringify(paste)\r\n }\r\n );\r\n const payload = await res.json();\r\n\r\n if (payload.error) {\r\n dispatch(setError(payload.error));\r\n } else {\r\n const newPaste = convertToPaste(payload)\r\n dispatch(setActivePaste(newPaste));\r\n dispatch(setError(null));\r\n callback(payload.pasteUrl);\r\n }\r\n }\r\n catch (error) {\r\n const errorDetails = {\r\n status: 503,\r\n title: \"Connection error\",\r\n detail: \"Failed to connect to the server\",\r\n type: \"/errors/network-error\",\r\n instance: `${config.frontend_url}`\r\n };\r\n dispatch(setError(errorDetails));\r\n } finally {\r\n dispatch(setIsFetching(false));\r\n }\r\n }\r\n }","import React, { useState } from 'react';\r\nimport { useHistory } from \"react-router-dom\";\r\nimport { useDispatch } from 'react-redux';\r\nimport { postPaste } from '../redux/actions';\r\nimport { makeStyles } from '@material-ui/core/styles';\r\nimport { Button, InputLabel, MenuItem, Select, TextField } from '@material-ui/core';\r\nimport { Paste } from '../models/Paste';\r\nimport { validatePaste } from '../utils';\r\n\r\nconst useStyles = makeStyles(({\r\n root: {\r\n width: '100%',\r\n minWidth: '280px',\r\n diplay: 'flex',\r\n flexFlow: 'column nowrap',\r\n justifyContent: 'center',\r\n alignItems: 'center',\r\n \"& .field\": {\r\n width: '60%',\r\n minWidth: '280px',\r\n margin: '0 auto 30px auto',\r\n \"& .MuiButton-root\": {\r\n width: '100%',\r\n },\r\n },\r\n \"& .displayLinebreaksAndTabs\": {\r\n whiteSpace: 'pre-wrap',\r\n },\r\n }\r\n}));\r\n\r\nfunction PasteForm() {\r\n const classes = useStyles();\r\n const dispatch = useDispatch();\r\n const history = useHistory();\r\n\r\n const [state, setState] = useState({\r\n pasteUrl: \"\",\r\n title: \" \",\r\n content: \" \",\r\n ttl: -1,\r\n });\r\n\r\n const expirationValues = [\r\n { label: 'None', seconds: -1 },\r\n { label: 'A day', seconds: 86400 },\r\n { label: 'A week', seconds: 604800 },\r\n { label: 'A month', seconds: 2592000 },\r\n { label: 'A year', seconds: 31556926 }\r\n ];\r\n \r\n const submit = () => {\r\n // POST form data only if it is valid\r\n const newPaste: Paste = state as Paste;\r\n if (validatePaste(newPaste)) {\r\n dispatch(postPaste(newPaste, redirectToCreatedPaste));\r\n }\r\n }\r\n\r\n const redirectToCreatedPaste = (pasteUrl: string) => {\r\n // Redirect current url path to paste url\r\n history.push(`/p/${pasteUrl}`);\r\n }\r\n\r\n return (\r\n
\r\n
\r\n setState(\r\n { ...state, title: event.target.value }\r\n )}\r\n />\r\n
\r\n
\r\n setState(\r\n { ...state, content: event.target.value }\r\n )}\r\n />\r\n
\r\n
\r\n Expiration\r\n setState(\r\n { ...state, ttl: event.target.value as number})\r\n }\r\n >\r\n {\r\n expirationValues.map((value, index) => (\r\n \r\n { value.label }\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 { PasteForm };","import React from 'react';\r\nimport { makeStyles } from '@material-ui/core/styles';\r\nimport { Typography } from '@material-ui/core';\r\n\r\nconst useStyles = makeStyles(theme => ({\r\n root: {\r\n color: theme.palette.text.primary,\r\n backgroundColor: theme.palette.background.default,\r\n \"& .MuiTypography-root\": {\r\n width: '60%',\r\n minWidth: '280px',\r\n margin: '0 auto 10px auto',\r\n }\r\n }\r\n}));\r\n\r\ntype ErrorProps = {\r\n status: number,\r\n message: string,\r\n};\r\n\r\nfunction Error({ status, message }: ErrorProps) {\r\n const classes = useStyles();\r\n\r\n return (\r\n
\r\n \r\n { status }\r\n \r\n\r\n \r\n { message }\r\n \r\n
\r\n )\r\n}\r\n\r\nexport { Error };","import React from 'react';\r\nimport { useSelector } from 'react-redux';\r\nimport { makeStyles } from '@material-ui/core/styles';\r\nimport { Link, Typography } from '@material-ui/core';\r\nimport { Header } from '../components/Header';\r\nimport { PasteForm } from '../components/PasteForm';\r\nimport { Error } from '../components/Error';\r\nimport { ReduxState } from '../models/ReduxState';\r\n\r\nconst useStyles = makeStyles(theme => ({\r\n root: {\r\n color: theme.palette.text.primary,\r\n backgroundColor: theme.palette.background.default,\r\n \"& .MuiTypography-root\": {\r\n width: '60%',\r\n minWidth: '280px',\r\n margin: '0 auto 10px auto',\r\n },\r\n \"& .MuiTypography-body2\": {\r\n lineHeight: 1.5,\r\n marginBottom: '2em',\r\n }\r\n }\r\n}));\r\n\r\nfunction Home() {\r\n const classes = useStyles();\r\n const error = useSelector((state: ReduxState) => state.error);\r\n\r\n return (\r\n
\r\n
\r\n {\r\n !error && \r\n
\r\n \r\n # Disclaimer\r\n \r\n \r\n This site is intended for use as a short-term exchange \r\n of pasted information between parties. All submitted \r\n data is considered public information. As such, please \r\n refrain from submitting personal or sensitive data. \r\n Submitted data is not guaranteed to be permanent, \r\n and may be removed at any time. \r\n

\r\n Please do not set up programs to send data to this site \r\n in an automated fashion; it is intended to be used \r\n directly by humans.\r\n

\r\n Should you reasonably believe that any third-party \r\n content you access through this site is in breach of \r\n any law, regulation or third party’s rights, you should \r\n notify the site owner at  \r\n \r\n zandrexrc@gmail.com\r\n .\r\n
\r\n \r\n # Create new paste\r\n \r\n \r\n
\r\n }\r\n {\r\n error && \r\n \r\n }\r\n
\r\n )\r\n}\r\n\r\nexport { Home };","import React from 'react';\r\nimport { makeStyles } from '@material-ui/core/styles';\r\nimport { Typography } from '@material-ui/core';\r\nimport { Paste } from '../models/Paste';\r\nimport moment from 'moment';\r\n\r\nconst useStyles = makeStyles(theme => ({\r\n root: {\r\n color: theme.palette.text.primary,\r\n backgroundColor: theme.palette.background.default,\r\n \"& .MuiTypography-root\": {\r\n width: '60%',\r\n minWidth: '280px',\r\n margin: '0 auto 10px auto',\r\n overflow: 'auto',\r\n },\r\n }\r\n}));\r\n\r\ntype PasteDetailsProps = {\r\n paste: Paste,\r\n};\r\n\r\nfunction PasteDetails({ paste }: PasteDetailsProps) {\r\n const classes = useStyles();\r\n \r\n return (\r\n
\r\n \r\n { paste.title }\r\n \r\n\r\n {\r\n paste.ttl && paste.timestamp &&\r\n
\r\n \r\n Posted on { moment.unix(paste.timestamp).format('LL') }
\r\n { \r\n paste.ttl > -1\r\n ? `Expires ${moment.unix(paste.timestamp + paste.ttl).format('LL')}`\r\n : 'No expiration date'\r\n }\r\n
\r\n
\r\n }\r\n\r\n \r\n { paste.content }\r\n \r\n
\r\n )\r\n}\r\n\r\nexport { PasteDetails };","import React, { useEffect, useState } from 'react';\r\nimport { makeStyles } from '@material-ui/core/styles';\r\nimport { CircularProgress } from '@material-ui/core/';\r\nimport { useParams } from 'react-router-dom';\r\nimport { useDispatch, useSelector } from 'react-redux';\r\nimport { getPaste } from '../redux/actions';\r\nimport { ReduxState } from '../models/ReduxState';\r\nimport { Header } from '../components/Header';\r\nimport { PasteDetails } from '../components/PasteDetails';\r\nimport { Error } from '../components/Error';\r\n\r\nconst useStyles = makeStyles(theme => ({\r\n root: {\r\n color: theme.palette.text.primary,\r\n backgroundColor: theme.palette.background.default,\r\n \"& .loading\": {\r\n width: '50%',\r\n minWidth: '280px',\r\n margin: '2em auto 0 auto',\r\n },\r\n },\r\n}));\r\n\r\ntype PasteViewerRouteParams = {\r\n pasteUrl: string,\r\n};\r\n\r\nfunction PasteViewer() {\r\n const classes = useStyles();\r\n\r\n // Get paste url\r\n const routeParams: PasteViewerRouteParams = useParams();\r\n const pasteUrl = routeParams.pasteUrl;\r\n\r\n // Get state from redux store\r\n const error = useSelector((state: ReduxState) => state.error);\r\n const paste = useSelector((state: ReduxState) => state.activePaste);\r\n\r\n // Track fetch progress\r\n const [pasteIsLoaded, setPasteIsLoaded] = useState(false);\r\n const isFetching = useSelector((state: ReduxState) => state.isFetching);\r\n\r\n // Fetch paste contents\r\n const dispatch = useDispatch();\r\n useEffect(() => {\r\n // Only send request if selected paste is not in redux state\r\n if (!paste || paste.pasteUrl !== pasteUrl) {\r\n dispatch(getPaste(pasteUrl));\r\n }\r\n setPasteIsLoaded(true);\r\n }, [pasteIsLoaded, dispatch, paste, pasteUrl]);\r\n\r\n return (\r\n
\r\n
\r\n {\r\n pasteIsLoaded && !isFetching && paste && \r\n \r\n }\r\n {\r\n pasteIsLoaded && !isFetching && error && \r\n \r\n }\r\n {\r\n (!pasteIsLoaded || isFetching) &&\r\n
\r\n \r\n
\r\n }\r\n
\r\n )\r\n}\r\n\r\nexport { PasteViewer };","import React from 'react';\r\nimport { Error } from '../components/Error';\r\nimport { Header } from '../components/Header';\r\n\r\nfunction NotFound() {\r\n return (\r\n
\r\n
\r\n \r\n
\r\n )\r\n}\r\n\r\nexport { NotFound };","import { createMuiTheme } from '@material-ui/core/styles';\r\n\r\nconst theme = createMuiTheme({\r\n palette: {\r\n type: 'dark',\r\n primary: {\r\n main: '#00cc00',\r\n contrastText: '#111'\r\n },\r\n secondary: {\r\n main: '#333',\r\n },\r\n text: {\r\n primary: '#fff',\r\n secondary: 'rgba(255, 255, 255, 0.7)',\r\n disabled: 'rgba(255, 255, 255, 0.5)',\r\n hint: 'rgba(255, 255, 255, 0.5)',\r\n },\r\n divider: 'rgba(255, 255, 255, 0.12)',\r\n background: {\r\n paper: '#333',\r\n default: '#111'\r\n },\r\n action: {\r\n active: '#fff',\r\n hover: 'rgba(255, 255, 255, 0.08)',\r\n hoverOpacity: 0.08,\r\n selected: 'rgba(255, 255, 255, 0.16)',\r\n selectedOpacity: 0.16,\r\n disabled: 'rgba(255, 255, 255, 0.3)',\r\n disabledBackground: 'rgba(255, 255, 255, 0.12)',\r\n disabledOpacity: 0.38,\r\n focus: 'rgba(255, 255, 255, 0.12)',\r\n focusOpacity: 0.12,\r\n activatedOpacity: 0.24\r\n }\r\n },\r\n typography: {\r\n fontFamily: \"'Roboto Mono', monospace\",\r\n body2: {\r\n fontFamily: \"'Roboto', sans-serif\",\r\n }\r\n }\r\n});\r\n\r\nexport { theme };","import React from 'react';\r\nimport { ThemeProvider } from '@material-ui/core/styles';\r\nimport { BrowserRouter, Route, Switch } from 'react-router-dom';\r\nimport { Home } from './pages/Home';\r\nimport { PasteViewer } from './pages/PasteViewer';\r\nimport { NotFound } from './pages/NotFound';\r\nimport { theme } from './themes/theme';\r\nimport './App.css';\r\n\r\nfunction App() {\r\n return (\r\n
\r\n \r\n \r\n \r\n\r\n \r\n \r\n \r\n\r\n \r\n \r\n \r\n\r\n \r\n \r\n \r\n\r\n \r\n \r\n \r\n
\r\n );\r\n}\r\n\r\nexport { App };","// 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\n export 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\n function 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\n function 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\n export 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 React from 'react';\r\nimport ReactDOM from 'react-dom';\r\nimport { Provider } from 'react-redux';\r\nimport { configureStore } from './redux/store';\r\nimport './index.css';\r\nimport { App } from './App';\r\nimport * as serviceWorker from './serviceWorker';\r\n\r\n// Set up redux store\r\nconst store = configureStore({});\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","import { createStore, applyMiddleware } from 'redux';\r\nimport thunkMiddleware from 'redux-thunk';\r\nimport { rootReducer, initialState } from './reducers';\r\nimport { ReduxState } from '../models/ReduxState';\r\n// Uncomment to enable redux logging\r\n// import { createLogger } from 'redux-logger';\r\n\r\n// Uncomment to enable redux logging\r\n// const loggerMiddleware = createLogger();\r\n\r\nfunction configureStore(preloadedState: ReduxState | any = initialState) {\r\n return createStore(\r\n rootReducer,\r\n preloadedState,\r\n applyMiddleware(\r\n thunkMiddleware, \r\n // Uncomment to enable redux logging\r\n // loggerMiddleware\r\n )\r\n );\r\n}\r\n\r\nexport { configureStore };"],"sourceRoot":""}