Skip to content

Commit 7583aa6

Browse files
committed
Merge pull request #16 from georgeOsdDev/hotfix/#15
Fix #15 Add askAgain prop
2 parents 832580c + 31f00c2 commit 7583aa6

File tree

7 files changed

+129
-32
lines changed

7 files changed

+129
-32
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
### Ver 0.2.2 (Next Release)
44

5+
* [#15 Permission being repeatedly asked for in Safari](https://github.com/georgeOsdDev/react-web-notification/issues/11)
6+
57
### Ver 0.2.1
68

79
* [#11 depending on library](https://github.com/georgeOsdDev/react-web-notification/issues/11)

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ Notification.propTypes = {
4343

4444
* `disableActiveWindow` : if true, nothing will be happen when window is active
4545

46+
* `askAgain` : if true, `window.Notification.requestPermission` will be called on `componentDidMount`, even if it was denied before,
47+
4648
* `notSupported()` : Called when [HTML5 Web Notification API](https://developer.mozilla.org/en/docs/Web/API/notification) is not supported.
4749

4850
* `onPermissionGranted()` : Called when permission granted.

example/app.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import React from 'react';
44
import ReactDom from 'react-dom';
5-
import Notification from '../src/components/Notification';
5+
import Notification from '../lib/components/Notification';
66

77
//allow react dev tools work
88
window.React = React;

lib/components/Notification.js

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ function _possibleConstructorReturn(self, call) { if (!self) { throw new Referen
1919
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
2020

2121
var PERMISSION_GRANTED = 'granted';
22+
var PERMISSION_DENIED = 'denied';
2223

2324
var seqGen = function seqGen() {
2425
var i = 0;
@@ -70,10 +71,26 @@ var Notification = (function (_React$Component) {
7071
this.windowFocus = false;
7172
}
7273
}, {
73-
key: 'componentDidMount',
74-
value: function componentDidMount() {
74+
key: '_askPermission',
75+
value: function _askPermission() {
7576
var _this2 = this;
7677

78+
window.Notification.requestPermission(function (permission) {
79+
var result = permission === PERMISSION_GRANTED;
80+
_this2.setState({
81+
granted: result
82+
}, function () {
83+
if (result) {
84+
_this2.props.onPermissionGranted();
85+
} else {
86+
_this2.props.onPermissionDenied();
87+
}
88+
});
89+
});
90+
}
91+
}, {
92+
key: 'componentDidMount',
93+
value: function componentDidMount() {
7794
if (this.props.disableActiveWindow) {
7895
if (window.addEventListener) {
7996
window.addEventListener('focus', this.onWindowFocus);
@@ -86,22 +103,17 @@ var Notification = (function (_React$Component) {
86103

87104
if (!this.state.supported) {
88105
this.props.notSupported();
106+
} else if (this.state.granted) {
107+
this.props.onPermissionGranted();
89108
} else {
90-
if (this.state.granted) {
91-
this.props.onPermissionGranted();
109+
if (window.Notification.permission === PERMISSION_DENIED) {
110+
if (this.props.askAgain) {
111+
this._askPermission();
112+
} else {
113+
this.props.onPermissionDenied();
114+
}
92115
} else {
93-
window.Notification.requestPermission(function (permission) {
94-
var result = permission === PERMISSION_GRANTED;
95-
_this2.setState({
96-
granted: result
97-
}, function () {
98-
if (result) {
99-
_this2.props.onPermissionGranted();
100-
} else {
101-
_this2.props.onPermissionDenied();
102-
}
103-
});
104-
});
116+
this._askPermission();
105117
}
106118
}
107119
}
@@ -182,6 +194,7 @@ var Notification = (function (_React$Component) {
182194
Notification.propTypes = {
183195
ignore: _react2.default.PropTypes.bool,
184196
disableActiveWindow: _react2.default.PropTypes.bool,
197+
askAgain: _react2.default.PropTypes.bool,
185198
notSupported: _react2.default.PropTypes.func,
186199
onPermissionGranted: _react2.default.PropTypes.func,
187200
onPermissionDenied: _react2.default.PropTypes.func,
@@ -197,6 +210,7 @@ Notification.propTypes = {
197210
Notification.defaultProps = {
198211
ignore: false,
199212
disableActiveWindow: false,
213+
askAgain: false,
200214
notSupported: function notSupported() {},
201215
onPermissionGranted: function onPermissionGranted() {},
202216
onPermissionDenied: function onPermissionDenied() {},

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-web-notification",
3-
"version": "0.2.1",
3+
"version": "0.2.2",
44
"description": "React component with HTML5 Web Notification API",
55
"main": "./lib/components/Notification.js",
66
"scripts": {

src/components/Notification.js

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import React from 'react';
44

55
const PERMISSION_GRANTED = 'granted';
6+
const PERMISSION_DENIED = 'denied';
67

78
const seqGen = () => {
89
let i = 0;
@@ -46,6 +47,21 @@ class Notification extends React.Component {
4647
this.windowFocus = false;
4748
}
4849

50+
_askPermission(){
51+
window.Notification.requestPermission((permission) => {
52+
let result = permission === PERMISSION_GRANTED;
53+
this.setState({
54+
granted: result
55+
}, () => {
56+
if (result) {
57+
this.props.onPermissionGranted();
58+
} else {
59+
this.props.onPermissionDenied();
60+
}
61+
});
62+
});
63+
}
64+
4965
componentDidMount(){
5066
if (this.props.disableActiveWindow) {
5167
if (window.addEventListener){
@@ -59,22 +75,17 @@ class Notification extends React.Component {
5975

6076
if (!this.state.supported) {
6177
this.props.notSupported();
62-
} else {
63-
if(this.state.granted) {
78+
} else if (this.state.granted) {
6479
this.props.onPermissionGranted();
80+
} else {
81+
if (window.Notification.permission === PERMISSION_DENIED){
82+
if (this.props.askAgain){
83+
this._askPermission();
84+
} else {
85+
this.props.onPermissionDenied();
86+
}
6587
} else {
66-
window.Notification.requestPermission( (permission) => {
67-
let result = permission === PERMISSION_GRANTED;
68-
this.setState({
69-
granted: result
70-
}, () => {
71-
if (result) {
72-
this.props.onPermissionGranted();
73-
} else {
74-
this.props.onPermissionDenied();
75-
}
76-
});
77-
});
88+
this._askPermission();
7889
}
7990
}
8091
}
@@ -91,6 +102,8 @@ class Notification extends React.Component {
91102
}
92103
}
93104

105+
106+
94107
render() {
95108
let doNotShowOnActiveWindow = this.props.disableActiveWindow && this.windowFocus;
96109
if (!this.props.ignore && this.props.title && this.state.supported && this.state.granted && !doNotShowOnActiveWindow) {
@@ -138,6 +151,7 @@ class Notification extends React.Component {
138151
Notification.propTypes = {
139152
ignore: React.PropTypes.bool,
140153
disableActiveWindow: React.PropTypes.bool,
154+
askAgain: React.PropTypes.bool,
141155
notSupported: React.PropTypes.func,
142156
onPermissionGranted: React.PropTypes.func,
143157
onPermissionDenied: React.PropTypes.func,
@@ -153,6 +167,7 @@ Notification.propTypes = {
153167
Notification.defaultProps = {
154168
ignore: false,
155169
disableActiveWindow: false,
170+
askAgain: false,
156171
notSupported: () => {},
157172
onPermissionGranted: () => {},
158173
onPermissionDenied: () => {},

test/components/Notification_spec.js

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import Notification from '../../src/components/Notification';
1313

1414
const PERMISSION_GRANTED = 'granted';
1515
const PERMISSION_DENIED = 'denied';
16+
const PERMISSION_DEFAULT = 'default';
1617

1718
describe('Test of Notification', () => {
1819

@@ -26,6 +27,7 @@ describe('Test of Notification', () => {
2627
component = TestUtils.renderIntoDocument(<Notification title='test'/>);
2728
expect(component.props.ignore).to.be.eql(false);
2829
expect(component.props.disableActiveWindow).to.be.eql(false);
30+
expect(component.props.askAgain).to.be.eql(false);
2931
expect(typeof component.props.notSupported).to.be.eql('function');
3032
expect(typeof component.props.onPermissionGranted).to.be.eql('function');
3133
expect(typeof component.props.onPermissionDenied).to.be.eql('function');
@@ -98,6 +100,68 @@ describe('Test of Notification', () => {
98100
});
99101
});
100102

103+
describe('When Notification is already denied', () => {
104+
describe('Check callbacks', ()=> {
105+
106+
let stub1, stub2, spy1, spy2;
107+
before(() => {
108+
spy1 = sinon.spy();
109+
spy2 = sinon.spy();
110+
stub1 = sinon.stub(window.Notification, 'permission', { get: function () { return PERMISSION_DENIED; } });
111+
stub2 = sinon.stub(window.Notification, 'requestPermission', function(cb){
112+
return cb(PERMISSION_DENIED);
113+
});
114+
component = TestUtils.renderIntoDocument(<Notification title='test' notSupported={spy1} onPermissionDenied={spy2}/>);
115+
});
116+
117+
after(() => {
118+
stub1.restore();
119+
stub2.restore();
120+
});
121+
122+
it('should not call window.Notification.requestPermission', () => {
123+
expect(stub2.calledOnce).to.be.eql(false);
124+
});
125+
126+
it('should call onPermissionDenied prop', () => {
127+
expect(spy1.called).to.be.eql(false);
128+
expect(spy2.calledOnce).to.be.eql(true);
129+
});
130+
});
131+
});
132+
133+
describe('When Notification is already denied, but `askAgain` prop is true', () => {
134+
describe('Check callbacks', ()=> {
135+
136+
let stub1, stub2, spy1, spy2, spy3;
137+
before(() => {
138+
spy1 = sinon.spy();
139+
spy2 = sinon.spy();
140+
spy3 = sinon.spy();
141+
stub1 = sinon.stub(window.Notification, 'permission', { get: function () { return PERMISSION_DENIED; } });
142+
stub2 = sinon.stub(window.Notification, 'requestPermission', function(cb){
143+
return cb(PERMISSION_GRANTED);
144+
});
145+
component = TestUtils.renderIntoDocument(<Notification title='test' notSupported={spy1} onPermissionDenied={spy2} onPermissionGranted={spy3} askAgain={true}/>);
146+
});
147+
148+
after(() => {
149+
stub1.restore();
150+
stub2.restore();
151+
});
152+
153+
it('should call window.Notification.requestPermission', () => {
154+
expect(stub2.calledOnce).to.be.eql(true);
155+
});
156+
157+
it('should call onPermissionGranted prop', () => {
158+
expect(spy1.called).to.be.eql(false);
159+
expect(spy2.called).to.be.eql(false);
160+
expect(spy3.calledOnce).to.be.eql(true);
161+
});
162+
});
163+
});
164+
101165
describe('When Notification is granted', () => {
102166
let stub;
103167
before(() => {

0 commit comments

Comments
 (0)