├── .babelrc ├── .eslintrc ├── .gitignore ├── .npmignore ├── .travis.yml ├── LICENSE ├── README.md ├── gulpfile.js ├── img └── example.png ├── package-lock.json ├── package.json ├── public ├── favicon.ico ├── index.html └── manifest.json └── src ├── App.css ├── App.js ├── App.test.js ├── Confirm.js ├── Confirm.test.js ├── index.css ├── index.js ├── logo.svg └── registerServiceWorker.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["react", "es2015", "stage-0"], 3 | "plugins": [ 4 | ["transform-es2015-modules-umd", { 5 | "globals": { 6 | "react": "React", 7 | "prop-types": "PropTypes", 8 | "react-bootstrap": "ReactBootstrap", 9 | "react-bootstrap/lib/Button": "Button", 10 | "react-bootstrap/lib/Modal": "Modal", 11 | } 12 | }] 13 | ], 14 | } 15 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "arrow-spacing": 2, 4 | "constructor-super": 2, 5 | "keyword-spacing": 2, 6 | "space-before-blocks": 2, 7 | "no-case-declarations": 0, 8 | "no-empty-pattern": 2, 9 | "no-spaced-func": 2, 10 | "no-trailing-spaces": 2, 11 | "indent": [2, 4, {"SwitchCase": 1}], 12 | "quotes": [ 13 | 2, 14 | "single", 15 | "avoid-escape" 16 | ], 17 | "linebreak-style": [ 18 | 2, 19 | "unix" 20 | ], 21 | "semi": [ 22 | 2, 23 | "always" 24 | ], 25 | "curly": 2, 26 | "comma-dangle": 0, 27 | "jsx-quotes": 1, 28 | "prefer-spread": 2, 29 | "no-console": 0, 30 | "no-dupe-class-members": 2, 31 | "no-this-before-super": 2, 32 | "no-unused-vars": [2, {"vars": "all", "args": "none"}], 33 | "prefer-arrow-callback": 2, 34 | "react/jsx-boolean-value": [1, "always"], 35 | "react/jsx-closing-bracket-location": [1, {selfClosing: 'tag-aligned', nonEmpty: 'after-props'}], 36 | "react/jsx-curly-spacing": 1, 37 | "react/jsx-indent": 1, 38 | "react/jsx-no-duplicate-props": 1, 39 | "react/jsx-no-undef": 1, 40 | "react/jsx-uses-react": 1, 41 | "react/jsx-uses-vars": 1, 42 | "react/no-did-update-set-state": 1, 43 | "react/no-direct-mutation-state": 1, 44 | "react/no-unknown-property": 1, 45 | "react/react-in-jsx-scope": 1, 46 | "react/require-extension": 1, 47 | "react/self-closing-comp": 1, 48 | "react/wrap-multilines": 1 49 | }, 50 | "env": { 51 | "es6": true, 52 | "commonjs": true, 53 | "browser": true, 54 | "node": true, 55 | "jest": true, 56 | }, 57 | "extends": "eslint:recommended", 58 | "parserOptions": { 59 | "sourceType": "module", 60 | "ecmaFeatures": { 61 | "jsx": true, 62 | "experimentalObjectRestSpread": true, 63 | } 64 | }, 65 | "plugins": [ 66 | "react" 67 | ] 68 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | node_modules 6 | 7 | # testing 8 | /coverage 9 | 10 | # production 11 | /build 12 | lib 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: "8" 3 | 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Greg Schechter 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-confirm-bootstrap 2 | Confirm Dialog for react with Bootstrap Modal. 3 | 4 | 5 | ## Example 6 | 7 | ![Example](https://github.com/gregthebusker/react-confirm-bootstrap/blob/master/img/example.png) 8 | 9 | ```js 10 | var Confirm = require('react-confirm-bootstrap'); 11 | 12 | var ConfirmAction = React.createClass({ 13 | onConfirm() { 14 | // Preform your action. 15 | }, 16 | 17 | render() { 18 | return ( 19 | 24 | 25 | 26 | ) 27 | }, 28 | }); 29 | ``` 30 | 31 | ### Props 32 | #### body: React.PropTypes.any.isRequired 33 | Body text for the modal. 34 | 35 | #### buttonText: React.PropTypes.node 36 | Options text for the initial button. Is only used if children are not passed. 37 | 38 | #### cancelText: React.PropTypes.node 39 | Text for the cancel button in the modal. 40 | 41 | #### confirmBSStyle: React.PropTypes.string 42 | Bootstrap style. 43 |
44 | Options: 'primary', 'success', 'info', 'warning', 'danger', 'link'. 45 |
46 | Default: 'danger' 47 | 48 | #### confirmText: React.PropTypes.node 49 | Text for the confirm button in the modal. 50 | 51 | #### onClose: React.PropTypes.func 52 | Function to be called once closed. 53 | 54 | #### onConfirm: React.PropTypes.func.isRequired 55 | Function to be called once confirmed. 56 | 57 | #### title: React.PropTypes.node.isRequired 58 | Title text for the modal 59 | 60 | #### visible: React.PropTypes.bool 61 | Optional initial state if the modal should start open. 62 | 63 | #### children: React.PropTypes.any 64 | Node to listen to clicks for. `react-confirm-bootstrap` render a `react-bootstrap` button by default. 65 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var babel = require('gulp-babel'); 3 | 4 | gulp.task('build', () => { 5 | return gulp.src('./src/Confirm.js') 6 | .pipe(babel()) 7 | .pipe(gulp.dest('./lib')); 8 | }); -------------------------------------------------------------------------------- /img/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gregthebusker/react-confirm-bootstrap/6ea3ae00e5a3a6d9baa5d2cf276314b5a7936902/img/example.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-confirm-bootstrap", 3 | "version": "5.3.1", 4 | "description": "Confirm Dialog for react with Bootstrap Modal", 5 | "main": "lib/Confirm.js", 6 | "scripts": { 7 | "package": "gulp build", 8 | "clean": "rimraf lib", 9 | "lint": "eslint src", 10 | "prepare": "npm run clean && npm run package", 11 | "start": "react-scripts start", 12 | "build": "react-scripts build", 13 | "test": "react-scripts test --env=jsdom", 14 | "eject": "react-scripts eject" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/gregthebusker/react-confirm-bootstrap.git" 19 | }, 20 | "keywords": [ 21 | "react", 22 | "bootstrap", 23 | "confirm", 24 | "modal", 25 | "dialog" 26 | ], 27 | "author": "Greg Schechter", 28 | "license": "MIT", 29 | "bugs": { 30 | "url": "https://github.com/gregthebusker/react-confirm-bootstrap/issues" 31 | }, 32 | "homepage": "https://github.com/gregthebusker/react-confirm-bootstrap#readme", 33 | "devDependencies": { 34 | "babel": "^6.23.0", 35 | "babel-core": "^6.26.3", 36 | "babel-plugin-transform-es2015-modules-umd": "^6.24.1", 37 | "babel-preset-es2015": "^6.24.1", 38 | "babel-preset-react": "^6.24.1", 39 | "babel-preset-stage-0": "^6.24.1", 40 | "eslint": "^3.0.1", 41 | "eslint-plugin-react": "^5.1.1", 42 | "gulp": "^3.9.1", 43 | "gulp-babel": "^6.1.3", 44 | "react": "^16.3.2", 45 | "react-dom": "^16.3.2", 46 | "react-scripts": "^1.1.4", 47 | "rimraf": "^2.6.2" 48 | }, 49 | "peerDependencies": { 50 | "react": ">=15.0.0" 51 | }, 52 | "dependencies": { 53 | "prop-types": "^15.6.1", 54 | "react-bootstrap": "^0.33.1" 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gregthebusker/react-confirm-bootstrap/6ea3ae00e5a3a6d9baa5d2cf276314b5a7936902/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | 23 | React App 24 | 25 | 26 | 29 |
30 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | animation: App-logo-spin infinite 20s linear; 7 | height: 80px; 8 | } 9 | 10 | .App-header { 11 | background-color: #222; 12 | height: 150px; 13 | padding: 20px; 14 | color: white; 15 | } 16 | 17 | .App-title { 18 | font-size: 1.5em; 19 | } 20 | 21 | .App-intro { 22 | font-size: large; 23 | } 24 | 25 | @keyframes App-logo-spin { 26 | from { 27 | transform: rotate(0deg); 28 | } 29 | to { 30 | transform: rotate(360deg); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import logo from './logo.svg'; 3 | import './App.css'; 4 | import Confirm from './Confirm'; 5 | 6 | class App extends Component { 7 | render() { 8 | return ( 9 |
10 |
11 | logo 12 |

React Confirm Bootstrap

13 |
14 |

Example

15 |

16 | { 18 | alert('Confirmed'); 19 | }} 20 | body="Are you sure you want to delete this?" 21 | confirmText="Confirm Delete" 22 | title="Deleting Stuff"> 23 | 24 | 25 |

26 |
27 | ); 28 | } 29 | } 30 | 31 | export default App; 32 | -------------------------------------------------------------------------------- /src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | }); 9 | -------------------------------------------------------------------------------- /src/Confirm.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import Button from 'react-bootstrap/lib/Button'; 4 | import Modal from 'react-bootstrap/lib/Modal'; 5 | 6 | class Confirm extends React.Component { 7 | constructor(props) { 8 | super(props); 9 | this.state = { 10 | isOpened: props.visible 11 | }; 12 | this.onButtonClick = this.onButtonClick.bind(this); 13 | this.onClose = this.onClose.bind(this); 14 | this.onConfirm = this.onConfirm.bind(this); 15 | } 16 | 17 | onButtonClick() { 18 | // Since the modal is inside the button click events will propagate up. 19 | if (!this.state.isOpened) { 20 | this.setState({ 21 | isOpened: true 22 | }); 23 | } 24 | } 25 | 26 | onClose(event) { 27 | if (event) { 28 | event.stopPropagation(); 29 | } 30 | this.setState({ 31 | isOpened: false 32 | }); 33 | 34 | if (typeof this.props.onClose === 'function') { 35 | this.props.onClose(); 36 | } 37 | } 38 | 39 | onConfirm(event) { 40 | event.stopPropagation(); 41 | this.setState({ 42 | isOpened: false 43 | }); 44 | this.props.onConfirm(); 45 | } 46 | 47 | render() { 48 | var cancelButton = this.props.showCancelButton ? ( 49 | 52 | ) : null; 53 | var modal = ( 54 | 59 | 60 | {this.props.title} 61 | 62 | {this.props.body} 63 | 64 | {cancelButton} 65 | 68 | 69 | 70 | ); 71 | var content; 72 | if (this.props.children) { 73 | var btn = React.Children.only(this.props.children); 74 | content = React.cloneElement( 75 | btn, 76 | { 77 | onClick: this.onButtonClick, 78 | style: this.props.style 79 | }, 80 | btn.props.children, 81 | modal 82 | ); 83 | } else { 84 | content = ( 85 | 89 | ); 90 | } 91 | return content; 92 | } 93 | } 94 | 95 | Confirm.propTypes = { 96 | body: PropTypes.node.isRequired, 97 | buttonText: PropTypes.node, 98 | cancelText: PropTypes.node, 99 | className: PropTypes.string, 100 | confirmBSStyle: PropTypes.string, 101 | confirmText: PropTypes.node, 102 | dialogClassName: PropTypes.string, 103 | keyboard: PropTypes.bool, 104 | backdrop: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), 105 | enforceFocus: PropTypes.bool, 106 | onConfirm: PropTypes.func.isRequired, 107 | onClose: PropTypes.func, 108 | showCancelButton: PropTypes.bool.isRequired, 109 | title: PropTypes.node.isRequired, 110 | visible: PropTypes.bool 111 | }; 112 | 113 | Confirm.defaultProps = { 114 | cancelText: 'Cancel', 115 | confirmText: 'Confirm', 116 | confirmBSStyle: 'danger', 117 | showCancelButton: true 118 | }; 119 | 120 | export { Confirm }; 121 | export default Confirm; 122 | -------------------------------------------------------------------------------- /src/Confirm.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactTestUtils from 'react-dom/test-utils'; 3 | import Confirm from './Confirm'; 4 | 5 | it('renders properly without onClose prop', () => { 6 | let component = ReactTestUtils.renderIntoDocument( 7 | {}} 9 | body="Are you sure?" 10 | confirmText="Confirm" 11 | title="Confirmation"> 12 | 13 | 14 | ) 15 | 16 | // no modal dialog yet 17 | expect( 18 | ReactTestUtils.scryRenderedDOMComponentsWithClass(component, 'modal-dialog') 19 | ).toEqual([]); 20 | 21 | let actionButton = ReactTestUtils.findRenderedDOMComponentWithClass( 22 | component, 23 | 'btn' 24 | ); 25 | expect(actionButton.nodeType).toEqual(Node.ELEMENT_NODE); 26 | expect(actionButton.textContent).toMatch('Action'); 27 | }); 28 | 29 | it('renders properly with onClose prop', () => { 30 | let component = ReactTestUtils.renderIntoDocument( 31 | {}} 33 | onClose={() => {}} 34 | body="Are you sure?" 35 | confirmText="Confirm" 36 | title="Confirmation"> 37 | 38 | 39 | ) 40 | 41 | // no modal dialog yet 42 | expect( 43 | ReactTestUtils.scryRenderedDOMComponentsWithClass(component, 'modal-dialog') 44 | ).toEqual([]); 45 | 46 | let actionButton = ReactTestUtils.findRenderedDOMComponentWithClass( 47 | component, 48 | 'btn' 49 | ); 50 | expect(actionButton.nodeType).toEqual(Node.ELEMENT_NODE); 51 | expect(actionButton.textContent).toMatch('Action'); 52 | }); 53 | 54 | it('click on confirm calls onConfirm callback', (done) => { 55 | var onConfirmCallback = function () { 56 | console.log('Confimred!'); 57 | done(); 58 | }; 59 | 60 | let component = ReactTestUtils.renderIntoDocument( 61 | {onConfirmCallback();}} 63 | body="Are you sure?" 64 | confirmText="Confirm" 65 | confirmBSStyle="danger" 66 | title="Confirmation"> 67 | 68 | 69 | ) 70 | 71 | let actionButton = ReactTestUtils.findRenderedDOMComponentWithClass( 72 | component, 73 | 'btn' 74 | ); 75 | ReactTestUtils.Simulate.click(actionButton); 76 | 77 | let confirmationDialog = ReactTestUtils.findRenderedDOMComponentWithClass( 78 | component, 79 | 'modal-dialog' 80 | ); 81 | expect(confirmationDialog).toBeTruthy(); 82 | expect(confirmationDialog.nodeType).toEqual(Node.ELEMENT_NODE); 83 | 84 | let confirmButton = ReactTestUtils.findRenderedDOMComponentWithClass( 85 | component, 86 | 'btn-danger' 87 | ); 88 | expect(confirmButton).toBeTruthy(); 89 | expect(confirmButton.nodeType).toEqual(Node.ELEMENT_NODE); 90 | 91 | ReactTestUtils.Simulate.click(confirmButton); 92 | }); 93 | 94 | it('click on cancel calls onClose callback prop', (done) => { 95 | var onCloseCallback = function () { 96 | console.log('Closed!'); 97 | done(); 98 | }; 99 | 100 | let component = ReactTestUtils.renderIntoDocument( 101 | {console.log('Confirmed');}} 103 | onClose={() => {onCloseCallback();}} 104 | body="Are you sure?" 105 | confirmText="Confirm" 106 | confirmBSStyle="danger" 107 | title="Confirmation"> 108 | 109 | 110 | ) 111 | 112 | let actionButton = ReactTestUtils.findRenderedDOMComponentWithClass( 113 | component, 114 | 'btn' 115 | ); 116 | ReactTestUtils.Simulate.click(actionButton); 117 | 118 | let cancelButton = ReactTestUtils.findRenderedDOMComponentWithClass( 119 | component, 120 | 'btn-default' 121 | ); 122 | expect(cancelButton).toBeTruthy(); 123 | expect(cancelButton.nodeType).toEqual(Node.ELEMENT_NODE); 124 | 125 | ReactTestUtils.Simulate.click(cancelButton); 126 | }); 127 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | } 6 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import registerServiceWorker from './registerServiceWorker'; 6 | 7 | ReactDOM.render(, document.getElementById('root')); 8 | registerServiceWorker(); 9 | -------------------------------------------------------------------------------- /src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/registerServiceWorker.js: -------------------------------------------------------------------------------- 1 | // In production, we register a service worker to serve assets from local cache. 2 | 3 | // This lets the app load faster on subsequent visits in production, and gives 4 | // it offline capabilities. However, it also means that developers (and users) 5 | // will only see deployed updates on the "N+1" visit to a page, since previously 6 | // cached resources are updated in the background. 7 | 8 | // To learn more about the benefits of this model, read https://goo.gl/KwvDNy. 9 | // This link also includes instructions on opting out of this behavior. 10 | 11 | const isLocalhost = Boolean( 12 | window.location.hostname === 'localhost' || 13 | // [::1] is the IPv6 localhost address. 14 | window.location.hostname === '[::1]' || 15 | // 127.0.0.1/8 is considered localhost for IPv4. 16 | window.location.hostname.match(/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/) 17 | ); 18 | 19 | export default function register() { 20 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 21 | // The URL constructor is available in all browsers that support SW. 22 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location); 23 | if (publicUrl.origin !== window.location.origin) { 24 | // Our service worker won't work if PUBLIC_URL is on a different origin 25 | // from what our page is served on. This might happen if a CDN is used to 26 | // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374 27 | return; 28 | } 29 | 30 | window.addEventListener('load', () => { 31 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 32 | 33 | if (isLocalhost) { 34 | // This is running on localhost. Lets check if a service worker still exists or not. 35 | checkValidServiceWorker(swUrl); 36 | } else { 37 | // Is not local host. Just register service worker 38 | registerValidSW(swUrl); 39 | } 40 | }); 41 | } 42 | } 43 | 44 | function registerValidSW(swUrl) { 45 | navigator.serviceWorker 46 | .register(swUrl) 47 | .then(registration => { 48 | registration.onupdatefound = () => { 49 | const installingWorker = registration.installing; 50 | installingWorker.onstatechange = () => { 51 | if (installingWorker.state === 'installed') { 52 | if (navigator.serviceWorker.controller) { 53 | // At this point, the old content will have been purged and 54 | // the fresh content will have been added to the cache. 55 | // It's the perfect time to display a "New content is 56 | // available; please refresh." message in your web app. 57 | console.log('New content is available; please refresh.'); 58 | } else { 59 | // At this point, everything has been precached. 60 | // It's the perfect time to display a 61 | // "Content is cached for offline use." message. 62 | console.log('Content is cached for offline use.'); 63 | } 64 | } 65 | }; 66 | }; 67 | }) 68 | .catch(error => { 69 | console.error('Error during service worker registration:', error); 70 | }); 71 | } 72 | 73 | function checkValidServiceWorker(swUrl) { 74 | // Check if the service worker can be found. If it can't reload the page. 75 | fetch(swUrl) 76 | .then(response => { 77 | // Ensure service worker exists, and that we really are getting a JS file. 78 | if (response.status === 404 || response.headers.get('content-type').indexOf('javascript') === -1) { 79 | // No service worker found. Probably a different app. Reload the page. 80 | navigator.serviceWorker.ready.then(registration => { 81 | registration.unregister().then(() => { 82 | window.location.reload(); 83 | }); 84 | }); 85 | } else { 86 | // Service worker found. Proceed as normal. 87 | registerValidSW(swUrl); 88 | } 89 | }) 90 | .catch(() => { 91 | console.log('No internet connection found. App is running in offline mode.'); 92 | }); 93 | } 94 | 95 | export function unregister() { 96 | if ('serviceWorker' in navigator) { 97 | navigator.serviceWorker.ready.then(registration => { 98 | registration.unregister(); 99 | }); 100 | } 101 | } 102 | --------------------------------------------------------------------------------