Skip to content

Commit 76321f0

Browse files
authored
Merge pull request #7 from xJkit/feature/browser-reminder
Feature/browser reminder
2 parents fd4208f + a10cd34 commit 76321f0

File tree

9 files changed

+191
-78
lines changed

9 files changed

+191
-78
lines changed

__tests__/GoodBye.spec.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import React from 'react';
2+
import { shallow, mount } from 'enzyme';
3+
4+
import GoodBye from '../src';
5+
6+
describe('GoodBye', () => {
7+
test('should handleBeforeUnload handle function works expectedly', () => {
8+
const childFunction = jest.fn();
9+
const fakeMsg = "hello, world.";
10+
const evt = {};
11+
const wrapper = shallow(
12+
<GoodBye
13+
when
14+
alertBeforeUnload
15+
alertMessage={fakeMsg}
16+
children={childFunction}
17+
/>
18+
);
19+
expect(wrapper.instance().handleBeforeUnload(evt)).toBe(fakeMsg);
20+
expect(evt.returnValue).toBe(fakeMsg);
21+
});
22+
})

__tests__/provider.spec.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React from 'react';
22
import { shallow } from 'enzyme';
3-
import GoodBye, { Provider, withGoodBye } from '../src';
3+
import { Provider } from '../src';
44

55
describe('<Provider />', () => {
66
test('should receive handleGetUserConfirm render prop', () => {

example/src/Containers/Settings.js

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@ class Settings extends React.Component {
1717
const isModified = initialValue !== currentValue;
1818
return (
1919
<div>
20-
<GoodBye when={isModified}>
20+
<GoodBye
21+
when={isModified}
22+
alertBeforeUnload
23+
alertMessage="Save before leave. Do you want to continue?" // only work for IE
24+
>
2125
{({ isShow, handleOk, handleCancel }) =>
2226
isShow && (
2327
<Modal>
@@ -50,7 +54,12 @@ class Settings extends React.Component {
5054
}
5155
</GoodBye>
5256
<h2>Settings Page</h2>
53-
<div style={{ color: isModified ? 'red' : 'black' }}>
57+
<div
58+
style={{
59+
color: isModified ? 'red' : 'black',
60+
marginBottom: 24
61+
}}
62+
>
5463
<span>Portfolio Status: </span>
5564
<select
5665
value={currentValue}
@@ -60,6 +69,13 @@ class Settings extends React.Component {
6069
<option value="private">Private</option>
6170
</select>
6271
</div>
72+
<div style={{ color: 'grey' }}>
73+
<p>change status and do the following:</p>
74+
<ul className="note">
75+
<li>change route will popup custom dialogue</li>
76+
<li>reload or close window will trigger browser alert </li>
77+
</ul>
78+
</div>
6379
</div>
6480
);
6581
}

package.json

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
"deploy": "gh-pages -d example/build"
2727
},
2828
"dependencies": {
29-
"invariant": "^2.2.4"
29+
"invariant": "^2.2.4",
30+
"prop-types": "^15.6.1"
3031
},
3132
"peerDependencies": {
3233
"react": ">=16.3.0",
@@ -62,12 +63,21 @@
6263
"rollup-plugin-postcss": "^1.1.0",
6364
"rollup-plugin-url": "^1.3.0"
6465
},
65-
"files": ["dist"],
66+
"files": [
67+
"dist"
68+
],
6669
"jest": {
6770
"setupTestFrameworkScriptFile": "<rootDir>/scripts/jest.setup.js",
68-
"testMatch": ["<rootDir>/__tests__/*.spec.js"],
69-
"collectCoverageFrom": ["src/**/*.{js,jsx}"],
71+
"testMatch": [
72+
"<rootDir>/__tests__/*.spec.js"
73+
],
74+
"collectCoverageFrom": [
75+
"src/**/*.{js,jsx}"
76+
],
7077
"coverageDirectory": "coverage",
71-
"coverageReporters": ["html", "lcov"]
78+
"coverageReporters": [
79+
"html",
80+
"lcov"
81+
]
7282
}
7383
}

src/GoodByeContext.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import React from 'react';
2+
3+
const GoodByeContext = React.createContext();
4+
5+
export default GoodByeContext;

src/GoodByeProvider.js

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
import invariant from 'invariant';
4+
5+
import GoodByeContext from './GoodByeContext';
6+
7+
class Provider extends React.Component {
8+
constructor(props) {
9+
super(props);
10+
this.state = {
11+
isShow: false
12+
};
13+
this.pass = undefined;
14+
invariant(
15+
React.createContext,
16+
'react-goodbye only support React 16.3+ context api, please upgrade your react to the latest version.'
17+
)
18+
}
19+
20+
handleGetUserConfirm = (message, pass) => {
21+
this.pass = pass;
22+
this.setState({
23+
isShow: true
24+
});
25+
};
26+
27+
handleOk = () => {
28+
this.pass(true);
29+
this.setState({ isShow: false });
30+
};
31+
32+
handleCancel = () => {
33+
this.pass(false);
34+
this.setState({ isShow: false });
35+
};
36+
37+
render() {
38+
return (
39+
<GoodByeContext.Provider
40+
value={{
41+
isShow: this.state.isShow,
42+
handleOk: this.handleOk,
43+
handleCancel: this.handleCancel,
44+
pass: this.pass
45+
}}
46+
>
47+
{this.props.children({
48+
handleGetUserConfirm: this.handleGetUserConfirm
49+
})}
50+
</GoodByeContext.Provider>
51+
);
52+
}
53+
}
54+
55+
Provider.propTypes = {
56+
children: PropTypes.func
57+
}
58+
59+
export default Provider;

src/index.js

Lines changed: 41 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,88 +1,60 @@
11
import React, { Fragment, createFactory } from 'react';
2+
import PropTypes from 'prop-types';
23
import { Prompt as ReactRouterPrompt } from 'react-router';
3-
import invariant from 'invariant';
44

5-
const __DEV__ = process.env.NODE_ENV !== 'production';
6-
const GoodByeContext = React.createContext();
5+
import GoodByeContext from './GoodByeContext';
6+
import Provider from './GoodByeProvider';
7+
import withGoodBye from './withGoodBye';
78

8-
export class Provider extends React.Component {
9-
constructor(props) {
10-
super(props);
11-
this.state = {
12-
isShow: false
13-
};
14-
this.pass = undefined;
15-
invariant(
16-
React.createContext,
17-
'react-goodbye only support React 16.3+ context api, please upgrade your react to the latest version.'
18-
)
19-
}
9+
const __DEV__ = process.env.NODE_ENV !== 'production';
2010

21-
handleGetUserConfirm = (message, pass) => {
22-
this.pass = pass;
23-
this.setState({
24-
isShow: true
25-
});
11+
class GoodBye extends React.Component {
12+
handleBeforeUnload = evt => {
13+
const { alertMessage } = this.props;
14+
evt.returnValue = alertMessage;
15+
return alertMessage;
2616
};
2717

28-
handleOk = () => {
29-
this.pass(true);
30-
this.setState({ isShow: false });
31-
};
18+
componentDidUpdate() {
19+
const { when, alertBeforeUnload } = this.props;
20+
window.onbeforeunload = when && alertBeforeUnload
21+
? this.handleBeforeUnload
22+
: null;
23+
}
3224

33-
handleCancel = () => {
34-
this.pass(false);
35-
this.setState({ isShow: false });
36-
};
25+
componentWillUnmount() {
26+
window.onbeforeunload = null;
27+
}
3728

3829
render() {
30+
const { when, children } = this.props;
3931
return (
40-
<GoodByeContext.Provider
41-
value={{
42-
isShow: this.state.isShow,
43-
handleOk: this.handleOk,
44-
handleCancel: this.handleCancel,
45-
pass: this.pass
46-
}}
47-
>
48-
{this.props.children({
49-
handleGetUserConfirm: this.handleGetUserConfirm
50-
})}
51-
</GoodByeContext.Provider>
32+
<Fragment>
33+
<ReactRouterPrompt when={when} message="" />
34+
<GoodByeContext.Consumer>
35+
{renderProps => children({ ...renderProps })}
36+
</GoodByeContext.Consumer>
37+
</Fragment>
5238
);
5339
}
5440
}
5541

56-
export const withGoodBye = BaseRouterComponent => {
57-
const factory = createFactory(BaseRouterComponent);
58-
const WithGoodBye = props => (
59-
<Provider>
60-
{({ handleGetUserConfirm }) => (
61-
factory({
62-
...props,
63-
getUserConfirmation: handleGetUserConfirm
64-
})
65-
)}
66-
</Provider>
67-
);
68-
69-
if (__DEV__) {
70-
const baseRouterName = BaseRouterComponent.displayName || BaseRouterComponent.name || 'Component';
71-
WithGoodBye.displayName = `withGoodBye(${baseRouterName})`;
72-
73-
return WithGoodBye;
74-
}
42+
GoodBye.propTypes = {
43+
when: PropTypes.bool,
44+
alertBeforeUnload: PropTypes.bool,
45+
alertMessage: PropTypes.string,
46+
children: PropTypes.func.isRequired,
47+
};
7548

76-
return WithGoodBye;
49+
GoodBye.defaultProps = {
50+
when: false,
51+
alertBeforeUnload: false,
52+
alertMessage: '' // only work for IE
7753
};
7854

79-
export default ({ when = false, children }) => {
80-
return (
81-
<Fragment>
82-
<ReactRouterPrompt when={when} message="" />
83-
<GoodByeContext.Consumer>
84-
{renderProps => children({ ...renderProps })}
85-
</GoodByeContext.Consumer>
86-
</Fragment>
87-
);
55+
export {
56+
Provider,
57+
withGoodBye,
8858
};
59+
60+
export default GoodBye;

src/withGoodBye.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import React from 'react';
2+
import Provider from './GoodByeProvider';
3+
4+
const __DEV__ = process.env.NODE_ENV !== 'production';
5+
6+
const withGoodBye = BaseRouterComponent => {
7+
const factory = React.createFactory(BaseRouterComponent);
8+
const WithGoodBye = props => (
9+
<Provider>
10+
{({ handleGetUserConfirm }) => (
11+
factory({
12+
...props,
13+
getUserConfirmation: handleGetUserConfirm
14+
})
15+
)}
16+
</Provider>
17+
);
18+
19+
if (__DEV__) {
20+
const baseRouterName = BaseRouterComponent.displayName || BaseRouterComponent.name || 'Component';
21+
WithGoodBye.displayName = `withGoodBye(${baseRouterName})`;
22+
23+
return WithGoodBye;
24+
}
25+
26+
return WithGoodBye;
27+
};
28+
29+
export default withGoodBye;

yarn.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4204,7 +4204,7 @@ promise@^7.1.1:
42044204
dependencies:
42054205
asap "~2.0.3"
42064206

4207-
prop-types@^15.5.4, prop-types@^15.6.0:
4207+
prop-types@^15.5.4, prop-types@^15.6.0, prop-types@^15.6.1:
42084208
version "15.6.1"
42094209
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.1.tgz#36644453564255ddda391191fb3a125cbdf654ca"
42104210
dependencies:

0 commit comments

Comments
 (0)