2018-02-02 19:09:23 +01:00
|
|
|
import React, { Component } from "react";
|
|
|
|
import PropTypes from "prop-types";
|
|
|
|
import Cookies from "js-cookie";
|
|
|
|
|
|
|
|
export const OPTIONS = {
|
|
|
|
TOP: "top",
|
2018-06-21 18:33:53 +02:00
|
|
|
BOTTOM: "bottom",
|
|
|
|
NONE: "none"
|
2018-02-02 19:09:23 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
class CookieConsent extends Component {
|
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
this.accept.bind(this);
|
|
|
|
|
|
|
|
this.state = {
|
2018-06-03 11:47:22 +02:00
|
|
|
visible: false,
|
2018-02-02 19:09:23 +01:00
|
|
|
style: {
|
2018-05-30 14:06:00 +02:00
|
|
|
alignItems: "baseline",
|
2018-02-02 19:09:23 +01:00
|
|
|
background: "#353535",
|
|
|
|
color: "white",
|
2018-05-30 14:06:00 +02:00
|
|
|
display: "flex",
|
2018-05-31 20:00:26 +02:00
|
|
|
flexWrap: "wrap",
|
2018-05-30 14:06:00 +02:00
|
|
|
justifyContent: "space-between",
|
2018-02-02 19:09:23 +01:00
|
|
|
left: "0",
|
2018-05-30 14:06:00 +02:00
|
|
|
position: "fixed",
|
|
|
|
width: "100%",
|
|
|
|
zIndex: "999"
|
2018-02-02 19:09:23 +01:00
|
|
|
},
|
|
|
|
buttonStyle: {
|
|
|
|
background: "#ffd42d",
|
2018-05-30 14:06:00 +02:00
|
|
|
border: "0",
|
2018-02-02 19:09:23 +01:00
|
|
|
borderRadius: "0px",
|
2018-05-30 14:06:00 +02:00
|
|
|
boxShadow: "none",
|
|
|
|
color: "black",
|
2019-03-05 15:11:18 +01:00
|
|
|
cursor: "pointer",
|
2018-05-30 14:06:00 +02:00
|
|
|
flex: "0 0 auto",
|
2018-05-30 14:22:24 +02:00
|
|
|
padding: "5px 10px",
|
2018-05-31 19:51:48 +02:00
|
|
|
margin: "15px"
|
2018-05-30 14:06:00 +02:00
|
|
|
},
|
2019-04-06 00:25:15 +02:00
|
|
|
declineButtonStyle: {
|
|
|
|
background: "#ffd42d",
|
|
|
|
border: "0",
|
|
|
|
borderRadius: "0px",
|
|
|
|
boxShadow: "none",
|
|
|
|
color: "black",
|
|
|
|
cursor: "pointer",
|
|
|
|
flex: "0 0 auto",
|
|
|
|
padding: "5px 10px",
|
|
|
|
margin: "15px"
|
|
|
|
},
|
2018-05-31 19:51:48 +02:00
|
|
|
contentStyle: {
|
|
|
|
flex: "1 0 300px",
|
|
|
|
margin: "15px"
|
|
|
|
}
|
2018-02-02 19:09:23 +01:00
|
|
|
};
|
2018-07-13 22:50:43 +02:00
|
|
|
|
|
|
|
this.handleScroll = this.handleScroll.bind(this);
|
2018-02-02 19:09:23 +01:00
|
|
|
}
|
|
|
|
|
2018-06-03 17:44:04 +02:00
|
|
|
componentDidMount() {
|
2018-05-31 19:51:48 +02:00
|
|
|
const { cookieName, debug } = this.props;
|
2018-02-02 19:09:23 +01:00
|
|
|
|
2018-06-03 17:44:04 +02:00
|
|
|
// if cookie undefined or debug
|
|
|
|
if (Cookies.get(cookieName) === undefined || debug) {
|
2018-06-03 11:47:22 +02:00
|
|
|
this.setState({ visible: true });
|
2018-02-02 19:09:23 +01:00
|
|
|
}
|
2018-07-13 22:50:43 +02:00
|
|
|
|
2019-04-06 00:25:15 +02:00
|
|
|
// 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) {
|
2018-07-13 22:50:43 +02:00
|
|
|
window.addEventListener("scroll", this.handleScroll, { passive: true });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
componentWillUnmount() {
|
|
|
|
// remove listener if still set
|
|
|
|
window.removeEventListener("scroll", this.handleScroll);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* checks whether scroll has exceeded set amount and fire accept if so.
|
|
|
|
*/
|
|
|
|
handleScroll() {
|
|
|
|
// (top / height) - height * 100
|
|
|
|
let rootNode = document.documentElement,
|
|
|
|
body = document.body,
|
|
|
|
top = "scrollTop",
|
|
|
|
height = "scrollHeight";
|
|
|
|
|
|
|
|
let percentage =
|
|
|
|
((rootNode[top] || body[top]) /
|
|
|
|
((rootNode[height] || body[height]) - rootNode.clientHeight)) *
|
|
|
|
100;
|
|
|
|
|
|
|
|
if (percentage > this.props.acceptOnScrollPercentage) {
|
|
|
|
this.accept();
|
|
|
|
}
|
2018-02-02 19:09:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2019-04-06 00:25:15 +02:00
|
|
|
* Set a persistent accept cookie
|
2018-02-02 19:09:23 +01:00
|
|
|
*/
|
|
|
|
accept() {
|
2018-09-27 16:22:13 +02:00
|
|
|
const { cookieName, cookieValue, expires, hideOnAccept, onAccept, extraCookieOptions } = this.props;
|
2018-07-13 22:50:43 +02:00
|
|
|
|
|
|
|
// fire onAccept
|
|
|
|
onAccept();
|
2019-02-04 20:38:46 +01:00
|
|
|
|
2018-07-13 22:50:43 +02:00
|
|
|
// remove listener if set
|
|
|
|
window.removeEventListener("scroll", this.handleScroll);
|
2018-02-02 19:09:23 +01:00
|
|
|
|
2018-09-27 16:22:13 +02:00
|
|
|
Cookies.set(cookieName, cookieValue, { expires: expires, ...extraCookieOptions });
|
2018-07-29 22:02:34 +02:00
|
|
|
|
2018-06-25 22:35:16 +02:00
|
|
|
if (hideOnAccept) {
|
|
|
|
this.setState({ visible: false });
|
|
|
|
}
|
2018-02-02 19:09:23 +01:00
|
|
|
}
|
|
|
|
|
2019-04-06 00:25:15 +02:00
|
|
|
/**
|
|
|
|
* 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 });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-02 19:09:23 +01:00
|
|
|
render() {
|
|
|
|
// If the bar shouldn't be visible don't render anything.
|
|
|
|
if (!this.state.visible) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
const {
|
|
|
|
location,
|
|
|
|
style,
|
|
|
|
buttonStyle,
|
2019-04-06 00:25:15 +02:00
|
|
|
declineButtonStyle,
|
2018-05-30 14:06:00 +02:00
|
|
|
contentStyle,
|
2018-02-02 19:09:23 +01:00
|
|
|
disableStyles,
|
2018-06-07 11:32:43 +02:00
|
|
|
buttonText,
|
2019-04-06 00:25:15 +02:00
|
|
|
declineButtonText,
|
2018-06-07 11:32:43 +02:00
|
|
|
containerClasses,
|
|
|
|
contentClasses,
|
2018-10-19 11:38:51 +02:00
|
|
|
buttonClasses,
|
2019-04-06 00:25:15 +02:00
|
|
|
declineButtonClasses,
|
2018-10-19 11:38:51 +02:00
|
|
|
buttonId,
|
2019-04-06 00:25:15 +02:00
|
|
|
declineButtonId,
|
2019-02-26 13:23:17 +01:00
|
|
|
disableButtonStyles,
|
2019-04-06 00:25:15 +02:00
|
|
|
enableDeclineButton,
|
2019-02-26 14:01:17 +01:00
|
|
|
ButtonComponent
|
2018-02-02 19:09:23 +01:00
|
|
|
} = this.props;
|
|
|
|
|
2018-05-30 14:06:00 +02:00
|
|
|
let myStyle = {};
|
|
|
|
let myButtonStyle = {};
|
2019-04-06 00:25:15 +02:00
|
|
|
let myDeclineButtonStyle = {};
|
2018-05-30 14:06:00 +02:00
|
|
|
let myContentStyle = {};
|
2018-02-02 19:09:23 +01:00
|
|
|
|
|
|
|
if (disableStyles) {
|
2019-02-04 20:38:46 +01:00
|
|
|
// if styles are disabled use the provided styles (or none)
|
2018-02-02 19:09:23 +01:00
|
|
|
myStyle = Object.assign({}, style);
|
|
|
|
myButtonStyle = Object.assign({}, buttonStyle);
|
2019-04-06 00:25:15 +02:00
|
|
|
myDeclineButtonStyle = Object.assign({}, declineButtonStyle);
|
2018-05-30 14:06:00 +02:00
|
|
|
myContentStyle = Object.assign({}, contentStyle);
|
2018-02-02 19:09:23 +01:00
|
|
|
} else {
|
|
|
|
// if styles aren't disabled merge them with the styles that are provided (or use default styles)
|
|
|
|
myStyle = Object.assign({}, { ...this.state.style, ...style });
|
2018-06-03 11:47:22 +02:00
|
|
|
myContentStyle = Object.assign({}, { ...this.state.contentStyle, ...contentStyle });
|
2019-02-04 20:38:46 +01:00
|
|
|
|
|
|
|
// switch to disable JUST the button styles
|
|
|
|
if(disableButtonStyles){
|
|
|
|
myButtonStyle = Object.assign({}, buttonStyle);
|
2019-04-06 00:25:15 +02:00
|
|
|
myDeclineButtonStyle = Object.assign({}, declineButtonStyle);
|
2019-02-04 20:38:46 +01:00
|
|
|
}else{
|
|
|
|
myButtonStyle = Object.assign({}, { ...this.state.buttonStyle, ...buttonStyle });
|
2019-04-06 00:25:15 +02:00
|
|
|
myDeclineButtonStyle = Object.assign({}, { ...this.state.declineButtonStyle, ...declineButtonStyle });
|
2019-02-04 20:38:46 +01:00
|
|
|
}
|
|
|
|
|
2018-02-02 19:09:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// syntactic sugar to enable user to easily select top / bottom
|
|
|
|
switch (location) {
|
|
|
|
case OPTIONS.TOP:
|
|
|
|
myStyle.top = "0";
|
2018-06-07 11:32:43 +02:00
|
|
|
myStyle.position = "fixed";
|
2018-02-02 19:09:23 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case OPTIONS.BOTTOM:
|
|
|
|
myStyle.bottom = "0";
|
2018-06-07 11:32:43 +02:00
|
|
|
myStyle.position = "fixed";
|
2018-02-02 19:09:23 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
2018-06-07 11:32:43 +02:00
|
|
|
<div className={`cookieConsent ${containerClasses}`} style={myStyle}>
|
|
|
|
<div style={myContentStyle} className={contentClasses}>
|
|
|
|
{this.props.children}
|
|
|
|
</div>
|
2019-02-26 14:01:17 +01:00
|
|
|
<ButtonComponent
|
2018-02-02 19:09:23 +01:00
|
|
|
style={myButtonStyle}
|
2018-06-07 11:32:43 +02:00
|
|
|
className={buttonClasses}
|
2018-10-19 11:38:51 +02:00
|
|
|
id={buttonId}
|
2018-02-02 19:09:23 +01:00
|
|
|
onClick={() => {
|
|
|
|
this.accept();
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
{buttonText}
|
2019-02-26 14:01:17 +01:00
|
|
|
</ButtonComponent>
|
2019-04-06 00:25:15 +02:00
|
|
|
{enableDeclineButton &&
|
|
|
|
<ButtonComponent
|
|
|
|
style={myDeclineButtonStyle}
|
|
|
|
className={declineButtonClasses}
|
|
|
|
id={declineButtonId}
|
|
|
|
onClick={() => {
|
|
|
|
this.decline();
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
{declineButtonText}
|
|
|
|
</ButtonComponent>
|
|
|
|
}
|
2018-02-02 19:09:23 +01:00
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CookieConsent.propTypes = {
|
2018-07-28 13:24:44 +02:00
|
|
|
location: PropTypes.oneOf(Object.keys(OPTIONS).map(key => OPTIONS[key])),
|
2018-02-02 19:09:23 +01:00
|
|
|
style: PropTypes.object,
|
|
|
|
buttonStyle: PropTypes.object,
|
2019-04-06 00:25:15 +02:00
|
|
|
declineButtonStyle: PropTypes.object,
|
2018-05-30 14:06:00 +02:00
|
|
|
contentStyle: PropTypes.object,
|
2018-02-02 19:09:23 +01:00
|
|
|
children: PropTypes.any, // eslint-disable-line react/forbid-prop-types
|
|
|
|
disableStyles: PropTypes.bool,
|
2018-06-25 22:35:16 +02:00
|
|
|
hideOnAccept: PropTypes.bool,
|
2019-04-06 00:25:15 +02:00
|
|
|
hideOnDecline: PropTypes.bool,
|
2018-02-02 19:09:23 +01:00
|
|
|
onAccept: PropTypes.func,
|
2019-04-06 00:25:15 +02:00
|
|
|
onDecline: PropTypes.func,
|
2018-07-13 22:50:43 +02:00
|
|
|
buttonText: PropTypes.oneOfType([
|
|
|
|
PropTypes.string,
|
|
|
|
PropTypes.func,
|
|
|
|
PropTypes.element
|
|
|
|
]),
|
2019-04-06 00:25:15 +02:00
|
|
|
declineButtonText: PropTypes.oneOfType([
|
|
|
|
PropTypes.string,
|
|
|
|
PropTypes.func,
|
|
|
|
PropTypes.element
|
|
|
|
]),
|
2018-05-31 20:00:26 +02:00
|
|
|
cookieName: PropTypes.string,
|
2018-09-27 16:22:13 +02:00
|
|
|
cookieValue: PropTypes.oneOfType([
|
|
|
|
PropTypes.string,
|
|
|
|
PropTypes.bool,
|
|
|
|
PropTypes.number
|
|
|
|
]),
|
2019-04-06 00:25:15 +02:00
|
|
|
declineCookieValue: PropTypes.oneOfType([
|
|
|
|
PropTypes.string,
|
|
|
|
PropTypes.bool,
|
|
|
|
PropTypes.number
|
|
|
|
]),
|
2018-06-07 10:09:05 +02:00
|
|
|
debug: PropTypes.bool,
|
2018-06-07 11:32:43 +02:00
|
|
|
expires: PropTypes.number,
|
|
|
|
containerClasses: PropTypes.string,
|
|
|
|
contentClasses: PropTypes.string,
|
2018-07-13 22:50:43 +02:00
|
|
|
buttonClasses: PropTypes.string,
|
2019-04-06 00:25:15 +02:00
|
|
|
declineButtonClasses: PropTypes.string,
|
2018-10-19 11:38:51 +02:00
|
|
|
buttonId: PropTypes.string,
|
2019-04-06 00:25:15 +02:00
|
|
|
declineButtonId: PropTypes.string,
|
2018-07-13 22:50:43 +02:00
|
|
|
acceptOnScroll: PropTypes.bool,
|
2018-07-29 22:02:34 +02:00
|
|
|
acceptOnScrollPercentage: PropTypes.number,
|
2019-02-04 20:38:46 +01:00
|
|
|
extraCookieOptions: PropTypes.object,
|
2019-02-26 13:23:17 +01:00
|
|
|
disableButtonStyles: PropTypes.bool,
|
2019-04-06 00:25:15 +02:00
|
|
|
enableDeclineButton: PropTypes.bool,
|
2019-02-26 14:01:17 +01:00
|
|
|
ButtonComponent: PropTypes.oneOfType([
|
2019-02-26 13:23:17 +01:00
|
|
|
PropTypes.func,
|
|
|
|
PropTypes.element
|
|
|
|
]),
|
2018-02-02 19:09:23 +01:00
|
|
|
};
|
2018-05-31 20:00:26 +02:00
|
|
|
|
2018-02-02 19:09:23 +01:00
|
|
|
CookieConsent.defaultProps = {
|
|
|
|
disableStyles: false,
|
2018-06-25 22:35:16 +02:00
|
|
|
hideOnAccept: true,
|
2019-04-06 00:25:15 +02:00
|
|
|
hideOnDecline: true,
|
2018-07-13 22:50:43 +02:00
|
|
|
acceptOnScroll: false,
|
|
|
|
acceptOnScrollPercentage: 25,
|
2018-02-02 19:09:23 +01:00
|
|
|
location: OPTIONS.BOTTOM,
|
2018-07-29 22:02:34 +02:00
|
|
|
onAccept: () => { },
|
2019-04-06 00:25:15 +02:00
|
|
|
onDecline: () => { },
|
2018-02-02 19:09:23 +01:00
|
|
|
cookieName: "CookieConsent",
|
2018-09-27 16:22:13 +02:00
|
|
|
cookieValue: true,
|
2019-04-06 00:25:15 +02:00
|
|
|
declineCookieValue: false,
|
2018-05-31 20:00:26 +02:00
|
|
|
buttonText: "I understand",
|
2019-04-06 00:25:15 +02:00
|
|
|
declineButtonText: "I decline",
|
2018-06-07 10:09:05 +02:00
|
|
|
debug: false,
|
2018-06-07 11:32:43 +02:00
|
|
|
expires: 365,
|
2018-07-13 22:50:43 +02:00
|
|
|
containerClasses: "",
|
|
|
|
contentClasses: "",
|
2018-07-29 22:02:34 +02:00
|
|
|
buttonClasses: "",
|
2019-04-06 00:25:15 +02:00
|
|
|
declineButtonClasses: "",
|
2018-10-19 11:38:51 +02:00
|
|
|
buttonId: "",
|
2019-04-06 00:25:15 +02:00
|
|
|
declineButtonId: "",
|
2019-02-04 20:38:46 +01:00
|
|
|
extraCookieOptions: {},
|
2019-02-26 13:23:17 +01:00
|
|
|
disableButtonStyles: false,
|
2019-04-06 00:25:15 +02:00
|
|
|
enableDeclineButton: false,
|
2019-02-26 14:01:17 +01:00
|
|
|
ButtonComponent: ({ children, ...props }) => <button {...props}>{children}</button>,
|
2018-02-02 19:09:23 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
export default CookieConsent;
|
2019-04-06 00:25:15 +02:00
|
|
|
export { Cookies };
|