From 04c39e0351b192eda0f958f53edd7ea651be85de Mon Sep 17 00:00:00 2001 From: Luca Pagliaro Date: Fri, 31 Jan 2025 10:57:19 +0100 Subject: [PATCH 1/6] feat: add tracking events for gift modal --- packages/shared/src/components/ProfileMenu.tsx | 13 +++++++++++-- .../components/comments/CommentActionButtons.tsx | 14 +++++++++++--- packages/shared/src/components/plus/PlusInfo.tsx | 13 +++++++++++-- packages/shared/src/components/profile/Header.tsx | 14 +++++++++++--- .../src/components/squads/SquadMemberMenu.tsx | 13 +++++++++++-- packages/shared/src/lib/log.ts | 3 +++ packages/webapp/pages/account/invite.tsx | 11 ++++++++--- 7 files changed, 66 insertions(+), 15 deletions(-) diff --git a/packages/shared/src/components/ProfileMenu.tsx b/packages/shared/src/components/ProfileMenu.tsx index 6b2bf11fd9..0f1a4ca16e 100644 --- a/packages/shared/src/components/ProfileMenu.tsx +++ b/packages/shared/src/components/ProfileMenu.tsx @@ -35,8 +35,9 @@ import { checkIsExtension, isIOSNative } from '../lib/func'; import { useDndContext } from '../contexts/DndContext'; import { LazyModal } from './modals/common/types'; import { usePlusSubscription } from '../hooks/usePlusSubscription'; -import { LogEvent, TargetId } from '../lib/log'; +import { LogEvent, TargetId, TargetType } from '../lib/log'; import { GiftIcon } from './icons/gift'; +import { useLogContext } from '../contexts/LogContext'; interface ListItem { title: string; @@ -55,6 +56,7 @@ export default function ProfileMenu({ const { user, logout, isGdprCovered } = useAuthContext(); const { isActive: isDndActive, setShowDnd } = useDndContext(); const { isPlus, logSubscriptionEvent } = usePlusSubscription(); + const { logEvent } = useLogContext(); const items: ListItem[] = useMemo(() => { const list: ListItem[] = [ @@ -160,7 +162,14 @@ export default function ProfileMenu({ title: 'Gift daily.dev Plus', buttonProps: { icon: , - onClick: () => openModal({ type: LazyModal.GiftPlus }), + onClick: () => { + logEvent({ + event_name: LogEvent.GiftSubscription, + target_id: TargetId.ProfileDropdown, + target_type: TargetType.Plus, + }); + openModal({ type: LazyModal.GiftPlus }); + }, }, }); diff --git a/packages/shared/src/components/comments/CommentActionButtons.tsx b/packages/shared/src/components/comments/CommentActionButtons.tsx index c258866e16..7017a5621d 100644 --- a/packages/shared/src/components/comments/CommentActionButtons.tsx +++ b/packages/shared/src/components/comments/CommentActionButtons.tsx @@ -25,7 +25,7 @@ import { } from '../buttons/Button'; import { ClickableText } from '../buttons/ClickableText'; import { SimpleTooltip } from '../tooltips/SimpleTooltip'; -import { Origin } from '../../lib/log'; +import { LogEvent, Origin, TargetId, TargetType } from '../../lib/log'; import type { Post } from '../../graphql/posts'; import { UserVote } from '../../graphql/posts'; import { AuthTriggers } from '../../lib/auth'; @@ -48,6 +48,7 @@ import { ContentPreferenceType } from '../../graphql/contentPreference'; import { isFollowingContent } from '../../hooks/contentPreference/types'; import { useIsSpecialUser } from '../../hooks/auth/useIsSpecialUser'; import { GiftIcon } from '../icons/gift'; +import { useLogContext } from '../../contexts/LogContext'; export interface CommentActionProps { onComment: (comment: Comment, parentId: string | null) => void; @@ -84,6 +85,7 @@ export default function CommentActionButtons({ const { onMenuClick, isOpen, onHide } = useContextMenu({ id }); const { openModal } = useLazyModal(); const { displayToast } = useToastNotification(); + const { logEvent } = useLogContext(); const [voteState, setVoteState] = useState(() => { return { id: comment.id, @@ -265,13 +267,19 @@ export default function CommentActionButtons({ if (comment.author.id !== user?.id && !comment.author.isPlus) { commentOptions.push({ label: 'Gift daily.dev Plus', - action: () => + action: () => { + logEvent({ + event_name: LogEvent.GiftSubscription, + target_id: TargetId.ContextMenu, + target_type: TargetType.Plus, + }); openModal({ type: LazyModal.GiftPlus, props: { preselected: comment.author as UserShortProfile, }, - }), + }); + }, icon: , }); } diff --git a/packages/shared/src/components/plus/PlusInfo.tsx b/packages/shared/src/components/plus/PlusInfo.tsx index e0bffacece..44f1658dda 100644 --- a/packages/shared/src/components/plus/PlusInfo.tsx +++ b/packages/shared/src/components/plus/PlusInfo.tsx @@ -20,7 +20,7 @@ import { ButtonVariant, } from '../buttons/Button'; import { usePlusSubscription } from '../../hooks/usePlusSubscription'; -import { LogEvent } from '../../lib/log'; +import { LogEvent, TargetId, TargetType } from '../../lib/log'; import { useGiftUserContext } from './GiftUserContext'; import { PlusOptionRadio } from './PlusOptionRadio'; import { GiftingSelectedUser } from './GiftingSelectedUser'; @@ -28,6 +28,7 @@ import ConditionalWrapper from '../ConditionalWrapper'; import { useLazyModal } from '../../hooks/useLazyModal'; import { LazyModal } from '../modals/common/types'; import { GiftIcon } from '../icons/gift'; +import { useLogContext } from '../../contexts/LogContext'; type PlusInfoProps = { productOptions: ProductOption[]; @@ -73,6 +74,7 @@ export const PlusInfo = ({ const { openModal } = useLazyModal(); const { logSubscriptionEvent } = usePlusSubscription(); const { giftToUser } = useGiftUserContext(); + const { logEvent } = useLogContext(); const { title, description, subtitle } = copy[giftToUser ? PlusType.Gift : PlusType.Self]; @@ -109,7 +111,14 @@ export const PlusInfo = ({ icon={} size={ButtonSize.XSmall} variant={ButtonVariant.Float} - onClick={() => openModal({ type: LazyModal.GiftPlus })} + onClick={() => { + logEvent({ + event_name: LogEvent.GiftSubscription, + target_id: TargetId.PlusPage, + target_type: TargetType.Plus, + }); + openModal({ type: LazyModal.GiftPlus }); + }} > Buy as a gift diff --git a/packages/shared/src/components/profile/Header.tsx b/packages/shared/src/components/profile/Header.tsx index 920f3353bb..6b8677354f 100644 --- a/packages/shared/src/components/profile/Header.tsx +++ b/packages/shared/src/components/profile/Header.tsx @@ -19,7 +19,7 @@ import { import { UpgradeToPlus } from '../UpgradeToPlus'; import { useContentPreferenceStatusQuery } from '../../hooks/contentPreference/useContentPreferenceStatusQuery'; import { usePlusSubscription } from '../../hooks/usePlusSubscription'; -import { LogEvent, TargetId } from '../../lib/log'; +import { LogEvent, TargetId, TargetType } from '../../lib/log'; import CustomFeedOptionsMenu from '../CustomFeedOptionsMenu'; import { useContentPreference } from '../../hooks/contentPreference/useContentPreference'; import { useLazyModal } from '../../hooks/useLazyModal'; @@ -27,6 +27,7 @@ import { LazyModal } from '../modals/common/types'; import { MenuIcon } from '../MenuIcon'; import { GiftIcon } from '../icons/gift'; import type { MenuItemProps } from '../fields/ContextMenu'; +import { useLogContext } from '../../contexts/LogContext'; export interface HeaderProps { user: PublicProfile; @@ -55,6 +56,7 @@ export function Header({ entity: ContentPreferenceType.User, }); const { unblock, block } = useContentPreference(); + const { logEvent } = useLogContext(); const onReportUser = React.useCallback( (defaultBlocked = false) => { @@ -103,11 +105,17 @@ export function Header({ options.push({ icon: , label: 'Gift daily.dev Plus', - action: () => + action: () => { + logEvent({ + event_name: LogEvent.GiftSubscription, + target_id: TargetId.ProfilePage, + target_type: TargetType.Plus, + }); openModal({ type: LazyModal.GiftPlus, props: { preselected: user as UserShortProfile }, - }), + }); + }, }); } diff --git a/packages/shared/src/components/squads/SquadMemberMenu.tsx b/packages/shared/src/components/squads/SquadMemberMenu.tsx index 8fb5260511..051ba66654 100644 --- a/packages/shared/src/components/squads/SquadMemberMenu.tsx +++ b/packages/shared/src/components/squads/SquadMemberMenu.tsx @@ -18,6 +18,8 @@ import { ContextMenu as ContextMenuIds } from '../../hooks/constants'; import { LazyModal } from '../modals/common/types'; import { GiftIcon } from '../icons/gift'; import { useLazyModal } from '../../hooks/useLazyModal'; +import { LogEvent, TargetId, TargetType } from '../../lib/log'; +import { useLogContext } from '../../contexts/LogContext'; interface SquadMemberMenuProps extends Pick { squad: Squad; @@ -127,6 +129,7 @@ export default function SquadMemberMenu({ const { user } = useContext(AuthContext); const { showPrompt } = usePrompt(); const { displayToast } = useToastNotification(); + const { logEvent } = useLogContext(); const onUpdateMember = async ( role: SourceMemberRole, title: MenuItemTitle, @@ -216,11 +219,17 @@ export default function SquadMemberMenu({ if (!member.user.isPlus) { menu.push({ label: 'Gift daily.dev Plus', - action: () => + action: () => { + logEvent({ + event_name: LogEvent.GiftSubscription, + target_id: TargetId.Squad, + target_type: TargetType.Plus, + }); openModal({ type: LazyModal.GiftPlus, props: { preselected: member.user }, - }), + }); + }, icon: , }); } diff --git a/packages/shared/src/lib/log.ts b/packages/shared/src/lib/log.ts index 3677d5769c..1aeb240664 100644 --- a/packages/shared/src/lib/log.ts +++ b/packages/shared/src/lib/log.ts @@ -226,6 +226,7 @@ export enum LogEvent { ReceivePayment = 'receive payment', OnboardingSkipPlus = 'skip upgrade subscription', OnboardingUpgradePlus = 'upgrade subscription', + GiftSubscription = 'gift subscription', // End Plus subscription // Clickbait Shield ToggleClickbaitShield = 'toggle clickbait shield', @@ -308,6 +309,7 @@ export enum TargetId { Ads = 'ads', MyProfile = 'my profile', PlusBadge = 'plus badge', + PlusPage = 'plus page', Onboarding = 'onboarding', BlockedWords = 'block words', CustomFeed = 'custom feed', @@ -316,6 +318,7 @@ export enum TargetId { ClickbaitShield = 'clickbait shield', StreakTimezoneLabel = 'streak timezone label', StreakTimezoneMismatchPrompt = 'streak timezone mismatch prompt', + ContextMenu = 'context', } export enum NotificationChannel { diff --git a/packages/webapp/pages/account/invite.tsx b/packages/webapp/pages/account/invite.tsx index cbc6cd5947..6fa6b98919 100644 --- a/packages/webapp/pages/account/invite.tsx +++ b/packages/webapp/pages/account/invite.tsx @@ -128,11 +128,16 @@ const AccountInvitePage = (): ReactElement => { icon={} variant={ButtonVariant.Secondary} color={ButtonColor.Bacon} - onClick={() => + onClick={() => { + logEvent({ + event_name: LogEvent.GiftSubscription, + target_id: TargetId.InviteFriendsPage, + target_type: TargetType.Plus, + }); openModal({ type: LazyModal.GiftPlus, - }) - } + }); + }} className="max-w-fit border-action-plus-default text-action-plus-default" > Buy as gift From 6d12bbe90f07ca8d1d77994e1d94da4e56c13c9b Mon Sep 17 00:00:00 2001 From: Luca Pagliaro Date: Fri, 31 Jan 2025 11:01:18 +0100 Subject: [PATCH 2/6] fix: lint dependencies --- packages/shared/src/components/ProfileMenu.tsx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/shared/src/components/ProfileMenu.tsx b/packages/shared/src/components/ProfileMenu.tsx index 0f1a4ca16e..bc09e23b1d 100644 --- a/packages/shared/src/components/ProfileMenu.tsx +++ b/packages/shared/src/components/ProfileMenu.tsx @@ -183,14 +183,15 @@ export default function ProfileMenu({ return list.filter(Boolean); }, [ + user.permalink, isGdprCovered, - isDndActive, isPlus, logSubscriptionEvent, - logout, - openModal, + isDndActive, setShowDnd, - user.permalink, + openModal, + logEvent, + logout, ]); if (!user) { From 5bb48d0b972506a81982053d15925fc14be975a8 Mon Sep 17 00:00:00 2001 From: Luca Pagliaro Date: Fri, 31 Jan 2025 16:48:15 +0100 Subject: [PATCH 3/6] refactor: moved to `logSubscriptionEvent` and add check for `isPlusAvailable` --- .../shared/src/components/ProfileMenu.tsx | 8 +- .../comments/CommentActionButtons.tsx | 22 ++++-- .../shared/src/components/plus/PlusInfo.tsx | 7 +- .../shared/src/components/profile/Header.tsx | 8 +- .../src/components/squads/SquadMemberMenu.tsx | 14 ++-- packages/webapp/pages/account/invite.tsx | 75 ++++++++++--------- 6 files changed, 69 insertions(+), 65 deletions(-) diff --git a/packages/shared/src/components/ProfileMenu.tsx b/packages/shared/src/components/ProfileMenu.tsx index bc09e23b1d..0db02eb376 100644 --- a/packages/shared/src/components/ProfileMenu.tsx +++ b/packages/shared/src/components/ProfileMenu.tsx @@ -35,9 +35,8 @@ import { checkIsExtension, isIOSNative } from '../lib/func'; import { useDndContext } from '../contexts/DndContext'; import { LazyModal } from './modals/common/types'; import { usePlusSubscription } from '../hooks/usePlusSubscription'; -import { LogEvent, TargetId, TargetType } from '../lib/log'; +import { LogEvent, TargetId } from '../lib/log'; import { GiftIcon } from './icons/gift'; -import { useLogContext } from '../contexts/LogContext'; interface ListItem { title: string; @@ -56,7 +55,6 @@ export default function ProfileMenu({ const { user, logout, isGdprCovered } = useAuthContext(); const { isActive: isDndActive, setShowDnd } = useDndContext(); const { isPlus, logSubscriptionEvent } = usePlusSubscription(); - const { logEvent } = useLogContext(); const items: ListItem[] = useMemo(() => { const list: ListItem[] = [ @@ -163,10 +161,9 @@ export default function ProfileMenu({ buttonProps: { icon: , onClick: () => { - logEvent({ + logSubscriptionEvent({ event_name: LogEvent.GiftSubscription, target_id: TargetId.ProfileDropdown, - target_type: TargetType.Plus, }); openModal({ type: LazyModal.GiftPlus }); }, @@ -190,7 +187,6 @@ export default function ProfileMenu({ isDndActive, setShowDnd, openModal, - logEvent, logout, ]); diff --git a/packages/shared/src/components/comments/CommentActionButtons.tsx b/packages/shared/src/components/comments/CommentActionButtons.tsx index 7017a5621d..a674c5ad58 100644 --- a/packages/shared/src/components/comments/CommentActionButtons.tsx +++ b/packages/shared/src/components/comments/CommentActionButtons.tsx @@ -25,7 +25,7 @@ import { } from '../buttons/Button'; import { ClickableText } from '../buttons/ClickableText'; import { SimpleTooltip } from '../tooltips/SimpleTooltip'; -import { LogEvent, Origin, TargetId, TargetType } from '../../lib/log'; +import { LogEvent, Origin, TargetId } from '../../lib/log'; import type { Post } from '../../graphql/posts'; import { UserVote } from '../../graphql/posts'; import { AuthTriggers } from '../../lib/auth'; @@ -39,7 +39,11 @@ import { useLazyModal } from '../../hooks/useLazyModal'; import { labels, largeNumberFormat } from '../../lib'; import { useToastNotification } from '../../hooks/useToastNotification'; import type { VoteEntityPayload } from '../../hooks'; -import { useVoteComment, voteMutationHandlers } from '../../hooks'; +import { + usePlusSubscription, + useVoteComment, + voteMutationHandlers, +} from '../../hooks'; import { generateQueryKey, RequestKey } from '../../lib/query'; import { useRequestProtocol } from '../../hooks/useRequestProtocol'; import { getCompanionWrapper } from '../../lib/extension'; @@ -48,7 +52,7 @@ import { ContentPreferenceType } from '../../graphql/contentPreference'; import { isFollowingContent } from '../../hooks/contentPreference/types'; import { useIsSpecialUser } from '../../hooks/auth/useIsSpecialUser'; import { GiftIcon } from '../icons/gift'; -import { useLogContext } from '../../contexts/LogContext'; +import { usePaymentContext } from '../../contexts/PaymentContext'; export interface CommentActionProps { onComment: (comment: Comment, parentId: string | null) => void; @@ -85,7 +89,8 @@ export default function CommentActionButtons({ const { onMenuClick, isOpen, onHide } = useContextMenu({ id }); const { openModal } = useLazyModal(); const { displayToast } = useToastNotification(); - const { logEvent } = useLogContext(); + const { isPlusAvailable } = usePaymentContext(); + const { logSubscriptionEvent } = usePlusSubscription(); const [voteState, setVoteState] = useState(() => { return { id: comment.id, @@ -264,14 +269,17 @@ export default function CommentActionButtons({ }); } - if (comment.author.id !== user?.id && !comment.author.isPlus) { + if ( + isPlusAvailable && + comment.author.id !== user?.id && + !comment.author.isPlus + ) { commentOptions.push({ label: 'Gift daily.dev Plus', action: () => { - logEvent({ + logSubscriptionEvent({ event_name: LogEvent.GiftSubscription, target_id: TargetId.ContextMenu, - target_type: TargetType.Plus, }); openModal({ type: LazyModal.GiftPlus, diff --git a/packages/shared/src/components/plus/PlusInfo.tsx b/packages/shared/src/components/plus/PlusInfo.tsx index 44f1658dda..631892d68c 100644 --- a/packages/shared/src/components/plus/PlusInfo.tsx +++ b/packages/shared/src/components/plus/PlusInfo.tsx @@ -20,7 +20,7 @@ import { ButtonVariant, } from '../buttons/Button'; import { usePlusSubscription } from '../../hooks/usePlusSubscription'; -import { LogEvent, TargetId, TargetType } from '../../lib/log'; +import { LogEvent, TargetId } from '../../lib/log'; import { useGiftUserContext } from './GiftUserContext'; import { PlusOptionRadio } from './PlusOptionRadio'; import { GiftingSelectedUser } from './GiftingSelectedUser'; @@ -28,7 +28,6 @@ import ConditionalWrapper from '../ConditionalWrapper'; import { useLazyModal } from '../../hooks/useLazyModal'; import { LazyModal } from '../modals/common/types'; import { GiftIcon } from '../icons/gift'; -import { useLogContext } from '../../contexts/LogContext'; type PlusInfoProps = { productOptions: ProductOption[]; @@ -74,7 +73,6 @@ export const PlusInfo = ({ const { openModal } = useLazyModal(); const { logSubscriptionEvent } = usePlusSubscription(); const { giftToUser } = useGiftUserContext(); - const { logEvent } = useLogContext(); const { title, description, subtitle } = copy[giftToUser ? PlusType.Gift : PlusType.Self]; @@ -112,10 +110,9 @@ export const PlusInfo = ({ size={ButtonSize.XSmall} variant={ButtonVariant.Float} onClick={() => { - logEvent({ + logSubscriptionEvent({ event_name: LogEvent.GiftSubscription, target_id: TargetId.PlusPage, - target_type: TargetType.Plus, }); openModal({ type: LazyModal.GiftPlus }); }} diff --git a/packages/shared/src/components/profile/Header.tsx b/packages/shared/src/components/profile/Header.tsx index 6b8677354f..21c8743592 100644 --- a/packages/shared/src/components/profile/Header.tsx +++ b/packages/shared/src/components/profile/Header.tsx @@ -19,7 +19,7 @@ import { import { UpgradeToPlus } from '../UpgradeToPlus'; import { useContentPreferenceStatusQuery } from '../../hooks/contentPreference/useContentPreferenceStatusQuery'; import { usePlusSubscription } from '../../hooks/usePlusSubscription'; -import { LogEvent, TargetId, TargetType } from '../../lib/log'; +import { LogEvent, TargetId } from '../../lib/log'; import CustomFeedOptionsMenu from '../CustomFeedOptionsMenu'; import { useContentPreference } from '../../hooks/contentPreference/useContentPreference'; import { useLazyModal } from '../../hooks/useLazyModal'; @@ -27,7 +27,6 @@ import { LazyModal } from '../modals/common/types'; import { MenuIcon } from '../MenuIcon'; import { GiftIcon } from '../icons/gift'; import type { MenuItemProps } from '../fields/ContextMenu'; -import { useLogContext } from '../../contexts/LogContext'; export interface HeaderProps { user: PublicProfile; @@ -56,7 +55,7 @@ export function Header({ entity: ContentPreferenceType.User, }); const { unblock, block } = useContentPreference(); - const { logEvent } = useLogContext(); + const { logSubscriptionEvent } = usePlusSubscription(); const onReportUser = React.useCallback( (defaultBlocked = false) => { @@ -106,10 +105,9 @@ export function Header({ icon: , label: 'Gift daily.dev Plus', action: () => { - logEvent({ + logSubscriptionEvent({ event_name: LogEvent.GiftSubscription, target_id: TargetId.ProfilePage, - target_type: TargetType.Plus, }); openModal({ type: LazyModal.GiftPlus, diff --git a/packages/shared/src/components/squads/SquadMemberMenu.tsx b/packages/shared/src/components/squads/SquadMemberMenu.tsx index 051ba66654..24e3f1879f 100644 --- a/packages/shared/src/components/squads/SquadMemberMenu.tsx +++ b/packages/shared/src/components/squads/SquadMemberMenu.tsx @@ -11,15 +11,15 @@ import { UserShortInfo } from '../profile/UserShortInfo'; import type { MenuItemProps } from '../fields/ContextMenu'; import ContextMenu from '../fields/ContextMenu'; import type { UseSquadActions } from '../../hooks'; -import { useToastNotification } from '../../hooks'; +import { usePlusSubscription, useToastNotification } from '../../hooks'; import { verifyPermission } from '../../graphql/squads'; import { ButtonColor, ButtonVariant } from '../buttons/Button'; import { ContextMenu as ContextMenuIds } from '../../hooks/constants'; import { LazyModal } from '../modals/common/types'; import { GiftIcon } from '../icons/gift'; import { useLazyModal } from '../../hooks/useLazyModal'; -import { LogEvent, TargetId, TargetType } from '../../lib/log'; -import { useLogContext } from '../../contexts/LogContext'; +import { LogEvent, TargetId } from '../../lib/log'; +import { usePaymentContext } from '../../contexts/PaymentContext'; interface SquadMemberMenuProps extends Pick { squad: Squad; @@ -129,7 +129,8 @@ export default function SquadMemberMenu({ const { user } = useContext(AuthContext); const { showPrompt } = usePrompt(); const { displayToast } = useToastNotification(); - const { logEvent } = useLogContext(); + const { isPlusAvailable } = usePaymentContext(); + const { logSubscriptionEvent } = usePlusSubscription(); const onUpdateMember = async ( role: SourceMemberRole, title: MenuItemTitle, @@ -216,14 +217,13 @@ export default function SquadMemberMenu({ }); } - if (!member.user.isPlus) { + if (!member.user.isPlus && isPlusAvailable) { menu.push({ label: 'Gift daily.dev Plus', action: () => { - logEvent({ + logSubscriptionEvent({ event_name: LogEvent.GiftSubscription, target_id: TargetId.Squad, - target_type: TargetType.Plus, }); openModal({ type: LazyModal.GiftPlus, diff --git a/packages/webapp/pages/account/invite.tsx b/packages/webapp/pages/account/invite.tsx index 6fa6b98919..0a16bbc0b3 100644 --- a/packages/webapp/pages/account/invite.tsx +++ b/packages/webapp/pages/account/invite.tsx @@ -2,6 +2,7 @@ import type { ReactElement } from 'react'; import React, { useMemo, useRef } from 'react'; import { ReferralCampaignKey, + usePlusSubscription, useReferralCampaign, } from '@dailydotdev/shared/src/hooks'; import { link } from '@dailydotdev/shared/src/lib/links'; @@ -23,7 +24,6 @@ import type { UserShortProfile } from '@dailydotdev/shared/src/lib/user'; import { format } from 'date-fns'; import { IconSize } from '@dailydotdev/shared/src/components/Icon'; import { useInfiniteQuery } from '@tanstack/react-query'; -import { useLogContext } from '@dailydotdev/shared/src/contexts/LogContext'; import { LogEvent, TargetId, @@ -47,6 +47,8 @@ import { import { GiftIcon } from '@dailydotdev/shared/src/components/icons/gift'; import { useLazyModal } from '@dailydotdev/shared/src/hooks/useLazyModal'; import { LazyModal } from '@dailydotdev/shared/src/components/modals/common/types'; +import { usePaymentContext } from '@dailydotdev/shared/src/contexts/PaymentContext'; +import { useLogContext } from '@dailydotdev/shared/src/contexts/LogContext'; import AccountContentSection from '../../components/layouts/AccountLayout/AccountContentSection'; import { AccountPageContainer } from '../../components/layouts/AccountLayout/AccountPageContainer'; import { getAccountLayout } from '../../components/layouts/AccountLayout'; @@ -64,6 +66,8 @@ const AccountInvitePage = (): ReactElement => { const { url, referredUsersCount } = useReferralCampaign({ campaignKey: ReferralCampaignKey.Generic, }); + const { isPlusAvailable } = usePaymentContext(); + const { logSubscriptionEvent } = usePlusSubscription(); const { logEvent } = useLogContext(); const inviteLink = url || link.referral.defaultUrl; const [, onShareOrCopyLink] = useShareOrCopyLink({ @@ -105,44 +109,45 @@ const AccountInvitePage = (): ReactElement => { return ( -
-
-
- - Gift daily.dev Plus + {isPlusAvailable && ( +
+
+
+ + Gift daily.dev Plus + + +
+ + Gifting daily.dev Plus to a friend is the ultimate way to say, + 'I've got your back.' It unlocks an ad-free + experience, advanced content filtering and customizations, plus AI + superpowers to supercharge their daily.dev journey. -
- } + variant={ButtonVariant.Secondary} + color={ButtonColor.Bacon} + onClick={() => { + logSubscriptionEvent({ + event_name: LogEvent.GiftSubscription, + target_id: TargetId.InviteFriendsPage, + }); + openModal({ + type: LazyModal.GiftPlus, + }); + }} + className="max-w-fit border-action-plus-default text-action-plus-default" > - Gifting daily.dev Plus to a friend is the ultimate way to say, - 'I've got your back.' It unlocks an ad-free - experience, advanced content filtering and customizations, plus AI - superpowers to supercharge their daily.dev journey. - + Buy as gift +
- -
+ )} Date: Fri, 31 Jan 2025 16:55:08 +0100 Subject: [PATCH 4/6] fix: add test context provider --- .../shared/src/components/cards/squad/SquadGrid.spec.tsx | 5 ++++- .../src/components/comments/CommentActionButtons.spec.tsx | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/shared/src/components/cards/squad/SquadGrid.spec.tsx b/packages/shared/src/components/cards/squad/SquadGrid.spec.tsx index e5735f80d8..f6c526668f 100644 --- a/packages/shared/src/components/cards/squad/SquadGrid.spec.tsx +++ b/packages/shared/src/components/cards/squad/SquadGrid.spec.tsx @@ -26,6 +26,7 @@ import { import { waitForNock } from '../../../../__tests__/helpers/utilities'; import { cloudinarySquadsDirectoryCardBannerDefault } from '../../../lib/image'; import { ActionType, COMPLETE_ACTION_MUTATION } from '../../../graphql/actions'; +import { PaymentContextProvider } from '../../../contexts/PaymentContext'; const routerReplace = jest.fn(); const squads = [generateTestSquad()]; @@ -77,7 +78,9 @@ const renderComponent = (): RenderResult => { squads={squads} > - + + + , ); diff --git a/packages/shared/src/components/comments/CommentActionButtons.spec.tsx b/packages/shared/src/components/comments/CommentActionButtons.spec.tsx index 3707902c68..2d0e90f107 100644 --- a/packages/shared/src/components/comments/CommentActionButtons.spec.tsx +++ b/packages/shared/src/components/comments/CommentActionButtons.spec.tsx @@ -22,6 +22,7 @@ import { UserVoteEntity } from '../../hooks'; import { UserVote } from '../../graphql/posts'; import LogContext from '../../contexts/LogContext'; import { ActionType } from '../../graphql/actions'; +import { PaymentContextProvider } from '../../contexts/PaymentContext'; const showLogin = jest.fn(); const onComment = jest.fn(); @@ -76,7 +77,9 @@ const renderComponent = ( sendBeacon: jest.fn(), }} > - + + + , From 3cf9e057a8ed8833f4762a6716d144d43df25188 Mon Sep 17 00:00:00 2001 From: Luca Pagliaro Date: Fri, 31 Jan 2025 17:01:54 +0100 Subject: [PATCH 5/6] fix: add test context provider --- .../shared/src/components/cards/squad/SquadGrid.spec.tsx | 2 +- packages/shared/src/components/comments/MainComment.spec.tsx | 5 ++++- packages/shared/src/components/comments/SubComment.spec.tsx | 5 ++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/shared/src/components/cards/squad/SquadGrid.spec.tsx b/packages/shared/src/components/cards/squad/SquadGrid.spec.tsx index f6c526668f..1bf017679a 100644 --- a/packages/shared/src/components/cards/squad/SquadGrid.spec.tsx +++ b/packages/shared/src/components/cards/squad/SquadGrid.spec.tsx @@ -77,8 +77,8 @@ const renderComponent = (): RenderResult => { loadedUserFromCache squads={squads} > - + diff --git a/packages/shared/src/components/comments/MainComment.spec.tsx b/packages/shared/src/components/comments/MainComment.spec.tsx index 1ba46d3e63..2fbdd6076f 100644 --- a/packages/shared/src/components/comments/MainComment.spec.tsx +++ b/packages/shared/src/components/comments/MainComment.spec.tsx @@ -11,6 +11,7 @@ import comment from '../../../__tests__/fixture/comment'; import post from '../../../__tests__/fixture/post'; import { Origin } from '../../lib/log'; import { useViewSize } from '../../hooks'; +import { PaymentContextProvider } from '../../contexts/PaymentContext'; const onDelete = jest.fn(); const mockUseViewSize = useViewSize as jest.MockedFunction; @@ -60,7 +61,9 @@ const renderLayout = ( tokenRefreshed: true, }} > - + + + , ); diff --git a/packages/shared/src/components/comments/SubComment.spec.tsx b/packages/shared/src/components/comments/SubComment.spec.tsx index 85c96bc9d7..3c22b006d9 100644 --- a/packages/shared/src/components/comments/SubComment.spec.tsx +++ b/packages/shared/src/components/comments/SubComment.spec.tsx @@ -11,6 +11,7 @@ import comment from '../../../__tests__/fixture/comment'; import { Origin } from '../../lib/log'; import post from '../../../__tests__/fixture/post'; import { useViewSize } from '../../hooks'; +import { PaymentContextProvider } from '../../contexts/PaymentContext'; const onDelete = jest.fn(); const mockUseViewSize = useViewSize as jest.MockedFunction; @@ -64,7 +65,9 @@ const renderLayout = ( tokenRefreshed: true, }} > - + + + , ); From ece404661b46c3499deb37a960fb155f9406006d Mon Sep 17 00:00:00 2001 From: Luca Pagliaro Date: Fri, 31 Jan 2025 17:08:09 +0100 Subject: [PATCH 6/6] fix: add test context provider --- packages/shared/__tests__/helpers/boot.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/shared/__tests__/helpers/boot.tsx b/packages/shared/__tests__/helpers/boot.tsx index 679d9cc76e..8452a720e1 100644 --- a/packages/shared/__tests__/helpers/boot.tsx +++ b/packages/shared/__tests__/helpers/boot.tsx @@ -19,6 +19,7 @@ import { LazyModalElement } from '../../src/components/modals/LazyModalElement'; import LogContext from '../../src/contexts/LogContext'; import type { LogContextData } from '../../src/hooks/log/useLogContextData'; import { ChecklistViewState } from '../../src/lib/checklist'; +import { PaymentContextProvider } from '../../src/contexts/PaymentContext'; interface TestBootProviderProps { children: ReactNode; @@ -116,8 +117,10 @@ export const TestBootProvider = ({ value={{ ...defaultLogContextData, ...log }} > - {children} - + + {children} + +