mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-10 23:36:14 -05:00
Added CTA popup to comments like button (#21484)
REF PLG-246 - Whenever a user clicks the like button and they are not allowed to like comments (either not signed in or not a paid member) we now show a CTA popup asking them to sign in or upgrade to a paid membership. --------- Co-authored-by: Kevin Ansfield <kevin@ghost.org>
This commit is contained in:
parent
c9f5b72b3c
commit
73884e8f69
7 changed files with 82 additions and 12 deletions
|
@ -6,7 +6,7 @@ type Props = {
|
|||
isPaid: boolean
|
||||
};
|
||||
const CTABox: React.FC<Props> = ({isFirst, isPaid}) => {
|
||||
const {accentColor, commentCount, publication, member, t} = useAppContext();
|
||||
const {accentColor, publication, member, t} = useAppContext();
|
||||
|
||||
const buttonStyle = {
|
||||
backgroundColor: accentColor
|
||||
|
@ -31,7 +31,7 @@ const CTABox: React.FC<Props> = ({isFirst, isPaid}) => {
|
|||
));
|
||||
|
||||
return (
|
||||
<section className={`flex flex-col items-center pt-[40px] ${member ? 'pb-[32px]' : 'pb-[48px]'} ${!isFirst && 'mt-4'} ${!member && commentCount ? 'border-t' : 'border-none'} border-[rgba(0,0,0,0.075)] sm:px-8 dark:border-[rgba(255,255,255,0.1)]`} data-testid="cta-box">
|
||||
<>
|
||||
<h1 className={`mb-[8px] text-center font-sans text-2xl tracking-tight text-black dark:text-[rgba(255,255,255,0.85)] ${isFirst ? 'font-semibold' : 'font-bold'}`}>
|
||||
{titleText}
|
||||
</h1>
|
||||
|
@ -45,7 +45,7 @@ const CTABox: React.FC<Props> = ({isFirst, isPaid}) => {
|
|||
<span className='mr-1 inline-block text-[15px]'>{t('Already a member?')}</span>
|
||||
<button className="rounded-md text-sm font-semibold transition-all hover:opacity-90" data-testid="signin-button" style={linkStyle} type="button" onClick={handleSignInClick}>{t('Sign in')}</button>
|
||||
</p>)}
|
||||
</section>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -40,8 +40,7 @@ const Content = () => {
|
|||
|
||||
const isPaidOnly = commentsEnabled === 'paid';
|
||||
const isPaidMember = member && !!member.paid;
|
||||
|
||||
// const showCTA = !member || (isPaidOnly && !isPaidMember);
|
||||
const isFirst = pagination?.total === 0;
|
||||
const hasOpenReplyForms = secundaryFormCount > 0;
|
||||
|
||||
return (
|
||||
|
@ -49,7 +48,13 @@ const Content = () => {
|
|||
<>
|
||||
<ContentTitle count={commentCount} showCount={showCount} title={title}/>
|
||||
<div>
|
||||
{member ? (isPaidMember || !isPaidOnly ? <MainForm commentsCount={commentCount} /> : <CTABox isFirst={pagination?.total === 0} isPaid={isPaidOnly} />) : <CTABox isFirst={pagination?.total === 0} isPaid={isPaidOnly} />}
|
||||
{(member && (isPaidMember || !isPaidOnly)) ? (
|
||||
<MainForm commentsCount={commentCount} />
|
||||
) : (
|
||||
<section className="flex flex-col items-center py-6 sm:px-8 sm:py-10" data-testid="cta-box">
|
||||
<CTABox isFirst={isFirst} isPaid={isPaidOnly} />
|
||||
</section>
|
||||
)}
|
||||
</div>
|
||||
<div className="z-20 mb-7 mt-3">
|
||||
<span className="flex items-center gap-1.5 text-sm font-medium text-neutral-900 dark:text-neutral-100">
|
||||
|
@ -73,7 +78,13 @@ const Content = () => {
|
|||
</div>
|
||||
<div>
|
||||
{!hasOpenReplyForms
|
||||
? (member ? (isPaidMember || !isPaidOnly ? <MainForm commentsCount={commentCount} /> : <CTABox isFirst={pagination?.total === 0} isPaid={isPaidOnly} />) : <CTABox isFirst={pagination?.total === 0} isPaid={isPaidOnly} />)
|
||||
? (member ? (isPaidMember || !isPaidOnly ? <MainForm commentsCount={commentCount} /> :
|
||||
<section className={`flex flex-col items-center pt-[40px] ${member ? 'pb-[32px]' : 'pb-[48px]'} ${!isFirst && 'mt-4'} ${(!member || (member && isPaidOnly)) && commentCount ? 'border-t' : 'border-none'} border-[rgba(0,0,0,0.075)] sm:px-8 dark:border-[rgba(255,255,255,0.1)]`} data-testid="cta-box">
|
||||
<CTABox isFirst={isFirst} isPaid={isPaidOnly} />
|
||||
</section>) :
|
||||
<section className={`flex flex-col items-center pt-[40px] ${member ? 'pb-[32px]' : 'pb-[48px]'} ${!isFirst && 'mt-4'} ${(!member || (member && isPaidOnly)) && commentCount ? 'border-t' : 'border-none'} border-[rgba(0,0,0,0.075)] sm:px-8 dark:border-[rgba(255,255,255,0.1)]`} data-testid="cta-box">
|
||||
<CTABox isFirst={isFirst} isPaid={isPaidOnly} />
|
||||
</section>)
|
||||
: null
|
||||
}
|
||||
</div>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {Comment, useAppContext} from '../../../AppContext';
|
||||
import {Comment, useAppContext, useLabs} from '../../../AppContext';
|
||||
import {ReactComponent as LikeIcon} from '../../../images/icons/like.svg';
|
||||
import {useState} from 'react';
|
||||
|
||||
|
@ -7,6 +7,7 @@ type Props = {
|
|||
};
|
||||
const LikeButton: React.FC<Props> = ({comment}) => {
|
||||
const {dispatchAction, member, commentsEnabled} = useAppContext();
|
||||
const labs = useLabs();
|
||||
const [animationClass, setAnimation] = useState('');
|
||||
|
||||
const paidOnly = commentsEnabled === 'paid';
|
||||
|
@ -14,7 +15,12 @@ const LikeButton: React.FC<Props> = ({comment}) => {
|
|||
const canLike = member && (isPaidMember || !paidOnly);
|
||||
|
||||
const toggleLike = () => {
|
||||
if (!canLike) {
|
||||
if (!canLike && labs && labs.commentImprovements) {
|
||||
dispatchAction('openPopup', {
|
||||
type: 'ctaPopup'
|
||||
});
|
||||
return;
|
||||
} else if (!canLike) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -37,6 +43,26 @@ const LikeButton: React.FC<Props> = ({comment}) => {
|
|||
likeCursor = 'cursor-text';
|
||||
}
|
||||
|
||||
if (labs && labs.commentImprovements) {
|
||||
return (
|
||||
<button
|
||||
className={`duration-50 group flex cursor-pointer items-center font-sans text-base outline-0 transition-all ease-linear sm:text-sm ${
|
||||
comment.liked ? 'text-black/90 dark:text-white/90' : 'text-black/50 hover:text-black/75 dark:text-white/60 dark:hover:text-white/75'
|
||||
}`}
|
||||
data-testid="like-button"
|
||||
type="button"
|
||||
onClick={toggleLike}
|
||||
>
|
||||
<LikeIcon
|
||||
className={animationClass + ` mr-[6px] ${
|
||||
comment.liked ? 'fill-black dark:fill-white stroke-black dark:stroke-white' : 'stroke-black/50 group-hover:stroke-black/75 dark:stroke-white/60 dark:group-hover:stroke-white/75'
|
||||
} ${!comment.liked && canLike && 'group-hover:stroke-black/75 dark:group-hover:stroke-white/75'} transition duration-50 ease-linear`}
|
||||
/>
|
||||
{comment.count.likes}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<CustomTag className={`duration-50 group flex items-center font-sans text-base outline-0 transition-all ease-linear sm:text-sm ${comment.liked ? 'text-black/90 dark:text-white/90' : 'text-black/50 hover:text-black/75 dark:text-white/60 dark:hover:text-white/75'} ${likeCursor}`} data-testid="like-button" type="button" onClick={toggleLike}>
|
||||
<LikeIcon className={animationClass + ` mr-[6px] ${comment.liked ? 'fill-black dark:fill-white stroke-black dark:stroke-white' : 'stroke-black/50 group-hover:stroke-black/75 dark:stroke-white/60 dark:group-hover:stroke-white/75'} ${!comment.liked && canLike && 'group-hover:stroke-black/75 dark:group-hover:stroke-white/75'} transition duration-50 ease-linear`} />
|
||||
|
|
31
apps/comments-ui/src/components/popups/CTAPopup.tsx
Normal file
31
apps/comments-ui/src/components/popups/CTAPopup.tsx
Normal file
|
@ -0,0 +1,31 @@
|
|||
import CTABox from '../content/CTABox';
|
||||
import CloseButton from './CloseButton';
|
||||
import {useAppContext} from '../../AppContext';
|
||||
|
||||
const CTAPopup = () => {
|
||||
const {dispatchAction, member, commentsEnabled} = useAppContext();
|
||||
|
||||
const stopPropagation = (event: React.MouseEvent) => {
|
||||
event.stopPropagation();
|
||||
};
|
||||
|
||||
const close = () => {
|
||||
dispatchAction('closePopup', {});
|
||||
};
|
||||
|
||||
const paidOnly = commentsEnabled === 'paid';
|
||||
const isFirst = !member;
|
||||
|
||||
return (
|
||||
<div className="shadow-modal relative h-screen w-screen rounded-none bg-white p-[28px] text-center sm:h-auto sm:w-[500px] sm:rounded-xl sm:p-8 sm:text-left" onClick={close} onMouseDown={stopPropagation}>
|
||||
<div className="flex h-full flex-col justify-center pt-10 sm:justify-normal sm:pt-0">
|
||||
<div className="flex flex-col items-center pb-3 pt-6" data-testid="cta-box">
|
||||
<CTABox isFirst={isFirst} isPaid={paidOnly} />
|
||||
</div>
|
||||
<CloseButton close={close} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CTAPopup;
|
|
@ -6,7 +6,7 @@ type Props = {
|
|||
}
|
||||
const CloseButton: React.FC<Props> = ({close}) => {
|
||||
return (
|
||||
<button className="absolute right-6 top-6 opacity-30 transition-opacity duration-100 ease-out hover:opacity-40 sm:right-8 sm:top-9" type="button" onClick={close}>
|
||||
<button className="absolute right-6 top-5 opacity-30 transition-opacity duration-100 ease-out hover:opacity-40 sm:right-8 sm:top-9" type="button" onClick={close}>
|
||||
<CloseIcon className="h-5 w-5 p-1 pr-0" />
|
||||
</button>
|
||||
);
|
||||
|
|
|
@ -45,7 +45,7 @@ const GenericPopup: React.FC<Props> = ({show, children, title, callback}) => {
|
|||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
>
|
||||
<div className="to-rgba(0,0,0,0.1) fixed left-0 top-0 flex h-screen w-screen justify-center overflow-hidden bg-gradient-to-b from-[rgba(0,0,0,0.2)] pt-0 backdrop-blur-[2px] sm:pt-12" onMouseDown={close}>
|
||||
<div className="to-rgba(0,0,0,0.1) fixed left-0 top-0 flex h-screen w-screen justify-center overflow-hidden bg-gradient-to-b from-[rgba(0,0,0,0.2)] pt-0 backdrop-blur-[2px] sm:pt-[4vmin]" onMouseDown={close}>
|
||||
<Transition.Child
|
||||
enter="transition duration-200 delay-150 linear"
|
||||
enterFrom="translate-y-4 opacity-0"
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import AddDetailsPopup from './components/popups/AddDetailsPopup';
|
||||
import CTAPopup from './components/popups/CTAPopup';
|
||||
import React from 'react';
|
||||
import ReportPopup from './components/popups/ReportPopup';
|
||||
|
||||
|
@ -7,7 +8,8 @@ import ReportPopup from './components/popups/ReportPopup';
|
|||
*/
|
||||
export const Pages = {
|
||||
addDetailsPopup: AddDetailsPopup,
|
||||
reportPopup: ReportPopup
|
||||
reportPopup: ReportPopup,
|
||||
ctaPopup: CTAPopup
|
||||
};
|
||||
export type PageName = keyof typeof Pages;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue