From 2657af11f6e9231e82040d8e9b381101965eb569 Mon Sep 17 00:00:00 2001 From: Simon Backx Date: Wed, 20 Jul 2022 10:16:50 +0200 Subject: [PATCH] Restricted actions for logged in members and paid members refs https://github.com/TryGhost/Team/issues/1693 - Added a new data attribute to the injected stript tag: `data-comments-enabled`. This contains the commentsEnabled setting, and can be 'all' or 'paid' (when it is off the comments section is never injected). - Added a new component ``, which is visible when a member is signed in but doesn't have paid access to comment - Prevented clicking the reply and like buttons when a member doesn't have access --- apps/comments-ui/src/App.js | 1 + apps/comments-ui/src/components/Comment.js | 8 +++- .../comments-ui/src/components/CommentsBox.js | 8 +++- apps/comments-ui/src/components/Like.js | 43 +++++++++++-------- apps/comments-ui/src/components/NotPaidBox.js | 28 ++++++++++++ apps/comments-ui/src/index.js | 7 +-- apps/comments-ui/src/utils/helpers.js | 2 +- 7 files changed, 72 insertions(+), 25 deletions(-) create mode 100644 apps/comments-ui/src/components/NotPaidBox.js diff --git a/apps/comments-ui/src/App.js b/apps/comments-ui/src/App.js index fd6e32970e..589140c731 100644 --- a/apps/comments-ui/src/App.js +++ b/apps/comments-ui/src/App.js @@ -282,6 +282,7 @@ export default class App extends React.Component { colorScheme: this.props.colorScheme, avatarSaturation: this.props.avatarSaturation, accentColor: this.props.accentColor, + commentsEnabled: this.props.commentsEnabled, dispatchAction: (_action, data) => this.dispatchAction(_action, data), /** diff --git a/apps/comments-ui/src/components/Comment.js b/apps/comments-ui/src/components/Comment.js index ead1ed541a..e9fdb42e4d 100644 --- a/apps/comments-ui/src/components/Comment.js +++ b/apps/comments-ui/src/components/Comment.js @@ -21,7 +21,7 @@ const Comment = (props) => { setIsInReplyMode(current => !current); }; - const {admin, avatarSaturation} = useContext(AppContext); + const {admin, avatarSaturation, member, commentsEnabled} = useContext(AppContext); const comment = props.comment; const hasReplies = comment.replies && comment.replies.length > 0; const isNotPublished = comment.status !== 'published'; @@ -35,6 +35,10 @@ const Comment = (props) => { } } + const paidOnly = commentsEnabled === 'paid'; + const isPaidMember = member && !!member.paid; + const canReply = member && (isPaidMember || !paidOnly); + if (isInEditMode) { return (
@@ -55,7 +59,7 @@ const Comment = (props) => {
- {(isNotPublished || !props.parent) && } + {canReply && (isNotPublished || !props.parent) && }
{formatRelativeTime(comment.created_at)}
diff --git a/apps/comments-ui/src/components/CommentsBox.js b/apps/comments-ui/src/components/CommentsBox.js index 73d2cc4556..c06cde0cc0 100644 --- a/apps/comments-ui/src/components/CommentsBox.js +++ b/apps/comments-ui/src/components/CommentsBox.js @@ -5,6 +5,7 @@ import Loading from './Loading'; import Form from './Form'; import Comment from './Comment'; import Pagination from './Pagination'; +import NotPaidBox from './NotPaidBox'; const CommentsBox = (props) => { const luminance = (r, g, b) => { @@ -40,7 +41,7 @@ const CommentsBox = (props) => { } }; - const {accentColor, pagination, member, comments} = useContext(AppContext); + const {accentColor, pagination, member, comments, commentsEnabled} = useContext(AppContext); const commentsElements = comments.slice().reverse().map(comment => ); @@ -50,6 +51,9 @@ const CommentsBox = (props) => { '--gh-accent-color': accentColor ?? 'blue' }; + const paidOnly = commentsEnabled === 'paid'; + const isPaidMember = member && !!member.paid; + return (
@@ -59,7 +63,7 @@ const CommentsBox = (props) => { {commentsElements}
- { member ? : } + { member ? (isPaidMember || !paidOnly ? : ) : }
: } diff --git a/apps/comments-ui/src/components/Like.js b/apps/comments-ui/src/components/Like.js index 38fcae5aac..822d2ef74f 100644 --- a/apps/comments-ui/src/components/Like.js +++ b/apps/comments-ui/src/components/Like.js @@ -3,33 +3,42 @@ import {ReactComponent as LikeIcon} from '../images/icons/like.svg'; import AppContext from '../AppContext'; function Like(props) { - const {onAction, member} = useContext(AppContext); + const {dispatchAction, member, commentsEnabled} = useContext(AppContext); const [animationClass, setAnimation] = useState(''); - let likeCursor = 'cursor-pointer'; - if (!member) { - likeCursor = 'cursor-text'; - } + const paidOnly = commentsEnabled === 'paid'; + const isPaidMember = member && !!member.paid; + const canLike = member && (isPaidMember || !paidOnly); const toggleLike = () => { - if (member) { - if (!props.comment.liked) { - onAction('likeComment', props.comment); - setAnimation('animate-heartbeat'); - setTimeout(() => { - setAnimation(''); - }, 400); - } else { - onAction('unlikeComment', props.comment); - } + if (!canLike) { + return; + } + + if (!props.comment.liked) { + dispatchAction('likeComment', props.comment); + setAnimation('animate-heartbeat'); + setTimeout(() => { + setAnimation(''); + }, 400); + } else { + dispatchAction('unlikeComment', props.comment); } }; + // If can like: use + ); } diff --git a/apps/comments-ui/src/components/NotPaidBox.js b/apps/comments-ui/src/components/NotPaidBox.js new file mode 100644 index 0000000000..c4b12e10ac --- /dev/null +++ b/apps/comments-ui/src/components/NotPaidBox.js @@ -0,0 +1,28 @@ +import {useContext} from 'react'; +import AppContext from '../AppContext'; + +const NotPaidBox = (props) => { + const {accentColor} = useContext(AppContext); + + const boxStyle = { + background: accentColor + }; + + const buttonStyle = { + color: accentColor + }; + + return ( +
+

Want to join the discussion?

+ + Subscribe now + +

+ You need to be subscribed to a paid plan to be able to join the discussion. +

+
+ ); +}; + +export default NotPaidBox; diff --git a/apps/comments-ui/src/index.js b/apps/comments-ui/src/index.js index 79ff834d7c..d9a497ac25 100644 --- a/apps/comments-ui/src/index.js +++ b/apps/comments-ui/src/index.js @@ -37,8 +37,9 @@ function getSiteData() { const avatarSaturation = scriptTag.dataset.avatarSaturation; const accentColor = scriptTag.dataset.accentColor; const appVersion = scriptTag.dataset.appVersion; + const commentsEnabled = scriptTag.dataset.commentsEnabled; - return {siteUrl, apiKey, apiUrl, sentryDsn, postId, adminUrl, colorScheme, avatarSaturation, accentColor, appVersion}; + return {siteUrl, apiKey, apiUrl, sentryDsn, postId, adminUrl, colorScheme, avatarSaturation, accentColor, appVersion, commentsEnabled}; } return {}; } @@ -58,13 +59,13 @@ function setup({siteUrl}) { function init() { // const customSiteUrl = getSiteUrl(); - const {siteUrl: customSiteUrl, sentryDsn, postId, adminUrl, colorScheme, avatarSaturation, accentColor, appVersion} = getSiteData(); + const {siteUrl: customSiteUrl, ...siteData} = getSiteData(); const siteUrl = customSiteUrl || window.location.origin; setup({siteUrl}); ReactDOM.render( - {} + {} , document.getElementById(ROOT_DIV_ID) ); diff --git a/apps/comments-ui/src/utils/helpers.js b/apps/comments-ui/src/utils/helpers.js index bff45a9ff5..067bd52d44 100644 --- a/apps/comments-ui/src/utils/helpers.js +++ b/apps/comments-ui/src/utils/helpers.js @@ -109,6 +109,6 @@ export function getBundledCssLink({appVersion}) { if (process.env.NODE_ENV === 'production' && appVersion) { return `https://unpkg.com/@tryghost/comments-ui@~${appVersion}/umd/main.css`; } else { - return 'http://localhost:4000/main.css'; + return 'https://comments.localhost/main.css'; } }