diff --git a/assets/css/src/components/_notice.scss b/assets/css/src/components/_notice.scss index dacba47373..4486b10822 100644 --- a/assets/css/src/components/_notice.scss +++ b/assets/css/src/components/_notice.scss @@ -10,6 +10,7 @@ box-shadow: 0 1px 1px 0 rgba(0, 0, 0, .1); margin: 5px 0 15px; padding: 1px 12px; + position: relative; } .mailpoet_success_notice { diff --git a/assets/js/src/notices/api_errors_notice.jsx b/assets/js/src/notices/api_errors_notice.jsx index 1c92bb40ff..9d3a6ccc6b 100644 --- a/assets/js/src/notices/api_errors_notice.jsx +++ b/assets/js/src/notices/api_errors_notice.jsx @@ -4,7 +4,7 @@ import Notice from 'notices/notice.jsx'; const APIErrorsNotice = ({ errors }) => { if (errors.length < 1) return null; - return {errors.map((err) =>

{err.message}

)}
; + return {errors.map((err) =>

{err.message}

)}
; }; APIErrorsNotice.propTypes = { errors: PropTypes.arrayOf(PropTypes.shape({ diff --git a/assets/js/src/notices/mailer_status_notice.jsx b/assets/js/src/notices/mailer_status_notice.jsx index 38b11aa767..7bf7e0eeae 100644 --- a/assets/js/src/notices/mailer_status_notice.jsx +++ b/assets/js/src/notices/mailer_status_notice.jsx @@ -4,7 +4,7 @@ import Notice from 'notices/notice.jsx'; const MailerStatusNotice = ({ error }) => { if (!error || error.operation !== 'authorization') return null; - return

{error.error_message}

; + return

{error.error_message}

; }; MailerStatusNotice.propTypes = { error: PropTypes.shape({ diff --git a/assets/js/src/notices/notice.jsx b/assets/js/src/notices/notice.jsx index 096496c8b2..eb7739b7e2 100644 --- a/assets/js/src/notices/notice.jsx +++ b/assets/js/src/notices/notice.jsx @@ -7,12 +7,19 @@ const Notice = (props) => { const elementRef = React.useRef(null); const timeoutRef = React.useRef(null); + const { onClose, onDisplay } = props; + + const close = React.useCallback(() => { + if (onClose) onClose(); + setHidden(true); + }, [onClose]); + React.useEffect(() => { if (props.timeout) { - timeoutRef.current = setTimeout(() => setHidden(true), props.timeout); + timeoutRef.current = setTimeout(close, props.timeout); } return () => (timeoutRef.current ? clearTimeout(timeoutRef.current) : null); - }, [props.timeout]); + }, [close, props.timeout]); React.useLayoutEffect(() => { if (props.scroll && elementRef.current) { @@ -20,15 +27,29 @@ const Notice = (props) => { } }, [props.scroll]); + React.useLayoutEffect(() => { + if (onDisplay) onDisplay(); + }, [onDisplay]); + if (hidden) return null; return ReactDOM.createPortal( -
{props.children}
, +
+ {props.children} + {props.closable && ( + + )} +
, document.getElementById('mailpoet_notices') ); }; Notice.propTypes = { type: PropTypes.oneOf(['success', 'info', 'warning', 'error']).isRequired, scroll: PropTypes.bool, + closable: PropTypes.bool, + onDisplay: PropTypes.func, + onClose: PropTypes.func, timeout: PropTypes.oneOfType([PropTypes.number, PropTypes.oneOf([false])]), children: PropTypes.oneOfType([ PropTypes.string, @@ -39,6 +60,9 @@ Notice.propTypes = { Notice.defaultProps = { timeout: 10000, scroll: false, + closable: true, + onDisplay: undefined, + onClose: undefined, }; export default Notice; diff --git a/assets/js/src/notices/subscribers_limit_notice.jsx b/assets/js/src/notices/subscribers_limit_notice.jsx index 7a8bf38036..41af035e03 100644 --- a/assets/js/src/notices/subscribers_limit_notice.jsx +++ b/assets/js/src/notices/subscribers_limit_notice.jsx @@ -5,7 +5,7 @@ import Notice from 'notices/notice.jsx'; const SubscribersLimitNotice = () => { if (!window.mailpoet_subscribers_limit_reached) return null; return ( - +

{ MailPoet.I18n.t('subscribersLimitNoticeTitle')