From 351b0e123321a15c47235b42d00984763f769ec6 Mon Sep 17 00:00:00 2001 From: Fannar Orn Hermannsson Date: Fri, 5 Apr 2019 22:25:15 +0000 Subject: [PATCH] Decline button added and bug fix for onAccept being triggered on scroll to accept when a cookie was already created --- README.md | 25 +++++++++-- build/index.d.ts | 9 +++- build/index.js | 112 +++++++++++++++++++++++++++++++++++++++-------- src/index.d.ts | 9 +++- src/index.js | 82 ++++++++++++++++++++++++++++++++-- 5 files changed, 210 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 8642a64..bb3ef39 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,17 @@ One of the props (onAccept) is a function, this function will be called after th ``` +If the decline button is enabled then the (onDecline) prop function can be used, this function will be called after the user has clicked the decline button. You can enable the button and provide a function like so: + +```js + {alert("nay!")}} +> + + +``` + ## Props | Prop | Type | Default value | Description | |---------------|:--------------------------------:|---------------|-------------------------------------------------------------------------------------------------------| @@ -84,20 +95,27 @@ One of the props (onAccept) is a function, this function will be called after th | acceptOnScroll | boolean | false | Defines whether "accept" should be fired after the user scrolls a certain distance (see acceptOnScrollPercentage) | | acceptOnScrollPercentage | number | 25 | Percentage of the page height the user has to scroll to trigger the accept function if acceptOnScroll is enabled | | buttonText | string or React component | "I understand" | Text to appear on the button | +| declineButtonText | string or React component | "I decline" | Text to appear on the decline button | | cookieName | string | "CookieConsent" | Name of the cookie used to track whether the user has agreed. | | cookieValue | string or boolean or number | true | Value to be saved under the cookieName. | +| declineCookieValue | string or boolean or number | false | Value to be saved under the cookieName when declined. | | onAccept | function | `() => {}` | Function to be called after the accept button has been clicked. | +| onDecline | function | `() => {}` | Function to be called after the decline button has been clicked. | | debug | boolean | undefined | Bar will be drawn regardless of cookie for debugging purposes. | | expires | number | 365 | Number of days before the cookie expires. | | extraCookieOptions | object | `{}` | Extra info (apart from expiry date) to add to the cookie| | containerClasses| string | "" | CSS classes to apply to the surrounding container | | buttonClasses | string | "" | CSS classes to apply to the button | +| declineButtonClasses | string | "" | CSS classes to apply to the decline button | | buttonId | string | "" | Id to apply to the button | +| declineButtonId | string | "" | Id to apply to the decline button | | contentClasses| string | "" | CSS classes to apply to the content | | style | object | [look at source][style] | React styling object for the bar. | | buttonStyle | object | [look at source][buttonStyle] | React styling object for the button. | +| declineButtonStyle | object | [look at source][declineButtonStyle] | React styling object for the decline button. | | contentStyle | object | [look at source][contentStyle] | React styling object for the content. | | disableButtonStyles | boolean | false | If enabled the button will have no default style. (you can still supply style through props) | +| enableDeclineButton | boolean | false | If enabled the decline button will be rendered | | ButtonComponent | React component | button | React Component to render as a button. ## Debugging it @@ -213,9 +231,10 @@ If you're crazy enough you can even make a rainbow colored bar: ``` -[style]: https://github.com/Mastermindzh/react-cookie-consent/blob/master/src/index.js#L17-L28 -[buttonStyle]: https://github.com/Mastermindzh/react-cookie-consent/blob/master/src/index.js#L29-L38 -[contentStyle]: https://github.com/Mastermindzh/react-cookie-consent/blob/master/src/index.js#L39-L42 +[style]: https://github.com/Mastermindzh/react-cookie-consent/blob/master/src/index.js#L18-L29 +[buttonStyle]: https://github.com/Mastermindzh/react-cookie-consent/blob/master/src/index.js#L30-L40 +[declineButtonStyle]: https://github.com/Mastermindzh/react-cookie-consent/blob/master/src/index.js#L41-L51 +[contentStyle]: https://github.com/Mastermindzh/react-cookie-consent/blob/master/src/index.js#L52-L55 ## Projects using react-cookie-consent diff --git a/build/index.d.ts b/build/index.d.ts index cf5a609..467d375 100644 --- a/build/index.d.ts +++ b/build/index.d.ts @@ -5,24 +5,31 @@ export interface CookieConsentProps { location?: "top" | "bottom" | "none"; style?: object; buttonStyle?: object; + declineButtonStyle?: object; contentStyle?: object; children?: React.ReactNode; disableStyles?: boolean; hideOnAccept?: boolean; onAccept?: Function; + onDecline?: Function; buttonText?: Function | React.ReactNode; + declineButtonText?: Function | React.ReactNode; cookieName?: string; cookieValue?: string | boolean | number; + declineCookieValue?: string | boolean | number; debug?: boolean; expires?: number; containerClasses?: string; contentClasses?: string; buttonClasses?: string; + declineButtonClasses?: string; buttonId?: string; + declineButtonId?: string; acceptOnScroll?: boolean; acceptOnScrollPercentage?: number; extraCookieOptions?: object; - disableButtonStyles ?: boolean; + disableButtonStyles?: boolean; + enableDeclineButton?: boolean; ButtonComponent?: Function | React.ReactElement; } diff --git a/build/index.js b/build/index.js index 1657561..fcf7e57 100644 --- a/build/index.js +++ b/build/index.js @@ -577,6 +577,17 @@ var CookieConsent = function (_Component) { padding: "5px 10px", margin: "15px" }, + declineButtonStyle: { + background: "#ffd42d", + border: "0", + borderRadius: "0px", + boxShadow: "none", + color: "black", + cursor: "pointer", + flex: "0 0 auto", + padding: "5px 10px", + margin: "15px" + }, contentStyle: { flex: "1 0 300px", margin: "15px" @@ -600,8 +611,8 @@ var CookieConsent = function (_Component) { this.setState({ visible: true }); } - // if acceptOnScroll is set to true, add a listener - if (this.props.acceptOnScroll) { + // if acceptOnScroll is set to true and cookie is undefined or debug is set to true, add a listener. + if (this.props.acceptOnScroll && _jsCookie2.default.get(cookieName) === undefined || debug) { window.addEventListener("scroll", this.handleScroll, { passive: true }); } } @@ -633,7 +644,7 @@ var CookieConsent = function (_Component) { } /** - * Set a persistent cookie + * Set a persistent accept cookie */ }, { @@ -660,6 +671,35 @@ var CookieConsent = function (_Component) { this.setState({ visible: false }); } } + + /** + * Set a persistent decline cookie + */ + + }, { + key: "decline", + value: function decline() { + var _props3 = this.props, + cookieName = _props3.cookieName, + declineCookieValue = _props3.declineCookieValue, + expires = _props3.expires, + hideOnDecline = _props3.hideOnDecline, + onDecline = _props3.onDecline, + extraCookieOptions = _props3.extraCookieOptions; + + // fire onDecline + + onDecline(); + + // remove listener if set + window.removeEventListener("scroll", this.handleScroll); + + _jsCookie2.default.set(cookieName, declineCookieValue, _extends({ expires: expires }, extraCookieOptions)); + + if (hideOnDecline) { + this.setState({ visible: false }); + } + } }, { key: "render", value: function render() { @@ -670,29 +710,36 @@ var CookieConsent = function (_Component) { return null; } - var _props3 = this.props, - location = _props3.location, - style = _props3.style, - buttonStyle = _props3.buttonStyle, - contentStyle = _props3.contentStyle, - disableStyles = _props3.disableStyles, - buttonText = _props3.buttonText, - containerClasses = _props3.containerClasses, - contentClasses = _props3.contentClasses, - buttonClasses = _props3.buttonClasses, - buttonId = _props3.buttonId, - disableButtonStyles = _props3.disableButtonStyles, - ButtonComponent = _props3.ButtonComponent; + var _props4 = this.props, + location = _props4.location, + style = _props4.style, + buttonStyle = _props4.buttonStyle, + declineButtonStyle = _props4.declineButtonStyle, + contentStyle = _props4.contentStyle, + disableStyles = _props4.disableStyles, + buttonText = _props4.buttonText, + declineButtonText = _props4.declineButtonText, + containerClasses = _props4.containerClasses, + contentClasses = _props4.contentClasses, + buttonClasses = _props4.buttonClasses, + declineButtonClasses = _props4.declineButtonClasses, + buttonId = _props4.buttonId, + declineButtonId = _props4.declineButtonId, + disableButtonStyles = _props4.disableButtonStyles, + enableDeclineButton = _props4.enableDeclineButton, + ButtonComponent = _props4.ButtonComponent; var myStyle = {}; var myButtonStyle = {}; + var myDeclineButtonStyle = {}; var myContentStyle = {}; if (disableStyles) { // if styles are disabled use the provided styles (or none) myStyle = _extends({}, style); myButtonStyle = _extends({}, buttonStyle); + myDeclineButtonStyle = _extends({}, declineButtonStyle); myContentStyle = _extends({}, contentStyle); } else { // if styles aren't disabled merge them with the styles that are provided (or use default styles) @@ -702,8 +749,10 @@ var CookieConsent = function (_Component) { // switch to disable JUST the button styles if (disableButtonStyles) { myButtonStyle = _extends({}, buttonStyle); + myDeclineButtonStyle = _extends({}, declineButtonStyle); } else { myButtonStyle = _extends({}, _extends({}, this.state.buttonStyle, buttonStyle)); + myDeclineButtonStyle = _extends({}, _extends({}, this.state.declineButtonStyle, declineButtonStyle)); } } @@ -739,6 +788,18 @@ var CookieConsent = function (_Component) { } }, buttonText + ), + enableDeclineButton && _react2.default.createElement( + ButtonComponent, + { + style: myDeclineButtonStyle, + className: declineButtonClasses, + id: declineButtonId, + onClick: function onClick() { + _this2.decline(); + } + }, + declineButtonText ) ); } @@ -753,45 +814,60 @@ CookieConsent.propTypes = { })), style: _propTypes2.default.object, buttonStyle: _propTypes2.default.object, + declineButtonStyle: _propTypes2.default.object, contentStyle: _propTypes2.default.object, children: _propTypes2.default.any, // eslint-disable-line react/forbid-prop-types disableStyles: _propTypes2.default.bool, hideOnAccept: _propTypes2.default.bool, + hideOnDecline: _propTypes2.default.bool, onAccept: _propTypes2.default.func, + onDecline: _propTypes2.default.func, buttonText: _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.func, _propTypes2.default.element]), + declineButtonText: _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.func, _propTypes2.default.element]), cookieName: _propTypes2.default.string, cookieValue: _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.bool, _propTypes2.default.number]), + declineCookieValue: _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.bool, _propTypes2.default.number]), debug: _propTypes2.default.bool, expires: _propTypes2.default.number, containerClasses: _propTypes2.default.string, contentClasses: _propTypes2.default.string, buttonClasses: _propTypes2.default.string, + declineButtonClasses: _propTypes2.default.string, buttonId: _propTypes2.default.string, + declineButtonId: _propTypes2.default.string, acceptOnScroll: _propTypes2.default.bool, acceptOnScrollPercentage: _propTypes2.default.number, extraCookieOptions: _propTypes2.default.object, disableButtonStyles: _propTypes2.default.bool, + enableDeclineButton: _propTypes2.default.bool, ButtonComponent: _propTypes2.default.oneOfType([_propTypes2.default.func, _propTypes2.default.element]) }; CookieConsent.defaultProps = { disableStyles: false, hideOnAccept: true, + hideOnDecline: true, acceptOnScroll: false, acceptOnScrollPercentage: 25, location: OPTIONS.BOTTOM, onAccept: function onAccept() {}, + onDecline: function onDecline() {}, cookieName: "CookieConsent", cookieValue: true, + declineCookieValue: false, buttonText: "I understand", + declineButtonText: "I decline", debug: false, expires: 365, containerClasses: "", contentClasses: "", buttonClasses: "", + declineButtonClasses: "", buttonId: "", + declineButtonId: "", extraCookieOptions: {}, disableButtonStyles: false, + enableDeclineButton: false, ButtonComponent: function ButtonComponent(_ref) { var children = _ref.children, props = _objectWithoutProperties(_ref, ["children"]); @@ -1689,7 +1765,7 @@ module.exports = function(isValidElement, throwOnDirectAccess) { /***/ (function(module, exports, __webpack_require__) { "use strict"; -/* WEBPACK VAR INJECTION */(function(process) {/** @license React v16.8.3 +/* WEBPACK VAR INJECTION */(function(process) {/** @license React v16.8.6 * react-is.development.js * * Copyright (c) Facebook, Inc. and its affiliates. @@ -1924,7 +2000,7 @@ exports.isSuspense = isSuspense; /***/ (function(module, exports, __webpack_require__) { "use strict"; -/** @license React v16.8.3 +/** @license React v16.8.6 * react-is.production.min.js * * Copyright (c) Facebook, Inc. and its affiliates. diff --git a/src/index.d.ts b/src/index.d.ts index cf5a609..467d375 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -5,24 +5,31 @@ export interface CookieConsentProps { location?: "top" | "bottom" | "none"; style?: object; buttonStyle?: object; + declineButtonStyle?: object; contentStyle?: object; children?: React.ReactNode; disableStyles?: boolean; hideOnAccept?: boolean; onAccept?: Function; + onDecline?: Function; buttonText?: Function | React.ReactNode; + declineButtonText?: Function | React.ReactNode; cookieName?: string; cookieValue?: string | boolean | number; + declineCookieValue?: string | boolean | number; debug?: boolean; expires?: number; containerClasses?: string; contentClasses?: string; buttonClasses?: string; + declineButtonClasses?: string; buttonId?: string; + declineButtonId?: string; acceptOnScroll?: boolean; acceptOnScrollPercentage?: number; extraCookieOptions?: object; - disableButtonStyles ?: boolean; + disableButtonStyles?: boolean; + enableDeclineButton?: boolean; ButtonComponent?: Function | React.ReactElement; } diff --git a/src/index.js b/src/index.js index beeb68c..2cec0ed 100644 --- a/src/index.js +++ b/src/index.js @@ -38,6 +38,17 @@ class CookieConsent extends Component { padding: "5px 10px", margin: "15px" }, + declineButtonStyle: { + background: "#ffd42d", + border: "0", + borderRadius: "0px", + boxShadow: "none", + color: "black", + cursor: "pointer", + flex: "0 0 auto", + padding: "5px 10px", + margin: "15px" + }, contentStyle: { flex: "1 0 300px", margin: "15px" @@ -55,8 +66,8 @@ class CookieConsent extends Component { this.setState({ visible: true }); } - // if acceptOnScroll is set to true, add a listener - if (this.props.acceptOnScroll) { + // if acceptOnScroll is set to true and cookie is undefined or debug is set to true, add a listener. + if ((this.props.acceptOnScroll && Cookies.get(cookieName) === undefined) || debug) { window.addEventListener("scroll", this.handleScroll, { passive: true }); } } @@ -87,7 +98,7 @@ class CookieConsent extends Component { } /** - * Set a persistent cookie + * Set a persistent accept cookie */ accept() { const { cookieName, cookieValue, expires, hideOnAccept, onAccept, extraCookieOptions } = this.props; @@ -105,6 +116,25 @@ class CookieConsent extends Component { } } + /** + * Set a persistent decline cookie + */ + decline() { + const { cookieName, declineCookieValue, expires, hideOnDecline, onDecline, extraCookieOptions } = this.props; + + // fire onDecline + onDecline(); + + // remove listener if set + window.removeEventListener("scroll", this.handleScroll); + + Cookies.set(cookieName, declineCookieValue, { expires: expires, ...extraCookieOptions }); + + if (hideOnDecline) { + this.setState({ visible: false }); + } + } + render() { // If the bar shouldn't be visible don't render anything. if (!this.state.visible) { @@ -115,25 +145,32 @@ class CookieConsent extends Component { location, style, buttonStyle, + declineButtonStyle, contentStyle, disableStyles, buttonText, + declineButtonText, containerClasses, contentClasses, buttonClasses, + declineButtonClasses, buttonId, + declineButtonId, disableButtonStyles, + enableDeclineButton, ButtonComponent } = this.props; let myStyle = {}; let myButtonStyle = {}; + let myDeclineButtonStyle = {}; let myContentStyle = {}; if (disableStyles) { // if styles are disabled use the provided styles (or none) myStyle = Object.assign({}, style); myButtonStyle = Object.assign({}, buttonStyle); + myDeclineButtonStyle = Object.assign({}, declineButtonStyle); myContentStyle = Object.assign({}, contentStyle); } else { // if styles aren't disabled merge them with the styles that are provided (or use default styles) @@ -143,8 +180,10 @@ class CookieConsent extends Component { // switch to disable JUST the button styles if(disableButtonStyles){ myButtonStyle = Object.assign({}, buttonStyle); + myDeclineButtonStyle = Object.assign({}, declineButtonStyle); }else{ myButtonStyle = Object.assign({}, { ...this.state.buttonStyle, ...buttonStyle }); + myDeclineButtonStyle = Object.assign({}, { ...this.state.declineButtonStyle, ...declineButtonStyle }); } } @@ -177,6 +216,18 @@ class CookieConsent extends Component { > {buttonText} + {enableDeclineButton && + { + this.decline(); + }} + > + {declineButtonText} + + } ); } @@ -186,32 +237,48 @@ CookieConsent.propTypes = { location: PropTypes.oneOf(Object.keys(OPTIONS).map(key => OPTIONS[key])), style: PropTypes.object, buttonStyle: PropTypes.object, + declineButtonStyle: PropTypes.object, contentStyle: PropTypes.object, children: PropTypes.any, // eslint-disable-line react/forbid-prop-types disableStyles: PropTypes.bool, hideOnAccept: PropTypes.bool, + hideOnDecline: PropTypes.bool, onAccept: PropTypes.func, + onDecline: PropTypes.func, buttonText: PropTypes.oneOfType([ PropTypes.string, PropTypes.func, PropTypes.element ]), + declineButtonText: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.func, + PropTypes.element + ]), cookieName: PropTypes.string, cookieValue: PropTypes.oneOfType([ PropTypes.string, PropTypes.bool, PropTypes.number ]), + declineCookieValue: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.bool, + PropTypes.number + ]), debug: PropTypes.bool, expires: PropTypes.number, containerClasses: PropTypes.string, contentClasses: PropTypes.string, buttonClasses: PropTypes.string, + declineButtonClasses: PropTypes.string, buttonId: PropTypes.string, + declineButtonId: PropTypes.string, acceptOnScroll: PropTypes.bool, acceptOnScrollPercentage: PropTypes.number, extraCookieOptions: PropTypes.object, disableButtonStyles: PropTypes.bool, + enableDeclineButton: PropTypes.bool, ButtonComponent: PropTypes.oneOfType([ PropTypes.func, PropTypes.element @@ -221,23 +288,30 @@ CookieConsent.propTypes = { CookieConsent.defaultProps = { disableStyles: false, hideOnAccept: true, + hideOnDecline: true, acceptOnScroll: false, acceptOnScrollPercentage: 25, location: OPTIONS.BOTTOM, onAccept: () => { }, + onDecline: () => { }, cookieName: "CookieConsent", cookieValue: true, + declineCookieValue: false, buttonText: "I understand", + declineButtonText: "I decline", debug: false, expires: 365, containerClasses: "", contentClasses: "", buttonClasses: "", + declineButtonClasses: "", buttonId: "", + declineButtonId: "", extraCookieOptions: {}, disableButtonStyles: false, + enableDeclineButton: false, ButtonComponent: ({ children, ...props }) => , }; export default CookieConsent; -export { Cookies }; +export { Cookies }; \ No newline at end of file