chore: add event tracking for billing (#7277)

fix AFF-1226
This commit is contained in:
pengx17 2024-06-20 03:33:07 +00:00
parent ddf72733e1
commit a085e507b4
No known key found for this signature in database
GPG Key ID: 23F23D9E8B3971ED
8 changed files with 127 additions and 9 deletions

View File

@ -224,7 +224,16 @@ const SubscriptionSettings = () => {
>
<SettingRow
style={{ cursor: 'pointer' }}
onClick={() => setOpenCancelModal(true)}
onClick={() => {
mixpanel.track('PlanChangeStarted', {
segment: 'settings panel',
module: 'billing subscription list',
control: 'plan cancel action',
type: proSubscription.plan,
category: proSubscription.recurring,
});
setOpenCancelModal(true);
}}
className="dangerous-setting"
name={t[
'com.affine.payment.billing-setting.cancel-subscription'
@ -369,10 +378,21 @@ const PaymentMethodUpdater = () => {
const ResumeSubscription = () => {
const t = useI18n();
const [open, setOpen] = useState(false);
const subscription = useService(SubscriptionService).subscription;
const handleClick = useCallback(() => {
setOpen(true);
mixpanel.track('PlanChangeStarted', {
segment: 'settings panel',
module: 'pricing plan list',
control: 'plan resume action',
type: subscription.pro$.value?.plan,
category: subscription.pro$.value?.recurring,
});
}, [subscription.pro$.value?.plan, subscription.pro$.value?.recurring]);
return (
<ResumeAction open={open} onOpenChange={setOpen}>
<Button className={styles.button} onClick={() => setOpen(true)}>
<Button className={styles.button} onClick={handleClick}>
{t['com.affine.payment.billing-setting.resume-subscription']()}
</Button>
</ResumeAction>

View File

@ -1,4 +1,5 @@
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
import { mixpanel } from '@affine/core/utils';
import { useService } from '@toeverything/infra';
import { nanoid } from 'nanoid';
import type { PropsWithChildren } from 'react';
@ -33,6 +34,13 @@ export const CancelAction = ({
// refresh idempotency key
setIdempotencyKey(nanoid());
onOpenChange(false);
mixpanel.track('ChangePlanSucceeded', {
segment: 'settings panel',
module: 'pricing plan list',
control: 'plan cancel action',
type: subscription.pro$.value?.plan,
category: subscription.pro$.value?.recurring,
});
} finally {
setIsMutating(false);
}
@ -78,6 +86,13 @@ export const ResumeAction = ({
// refresh idempotency key
setIdempotencyKey(nanoid());
onOpenChange(false);
mixpanel.track('ChangePlanSucceeded', {
segment: 'settings panel',
module: 'pricing plan list',
control: 'plan resume action',
type: subscription.pro$.value?.plan,
category: subscription.pro$.value?.recurring,
});
} finally {
setIsMutating(false);
}

View File

@ -1,6 +1,7 @@
import { Button, type ButtonProps, useConfirmModal } from '@affine/component';
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
import { SubscriptionService } from '@affine/core/modules/cloud';
import { mixpanel } from '@affine/core/utils';
import { SubscriptionPlan } from '@affine/graphql';
import { useI18n } from '@affine/i18n';
import { useService } from '@toeverything/infra';
@ -17,6 +18,12 @@ export const AICancel = ({ ...btnProps }: AICancelProps) => {
const { openConfirmModal } = useConfirmModal();
const cancel = useAsyncCallback(async () => {
mixpanel.track('PlanChangeStarted', {
segment: 'settings panel',
control: 'plan cancel action',
type: subscription.ai$.value?.plan,
category: subscription.ai$.value?.recurring,
});
openConfirmModal({
title: t['com.affine.payment.ai.action.cancel.confirm.title'](),
description:
@ -40,6 +47,10 @@ export const AICancel = ({ ...btnProps }: AICancelProps) => {
SubscriptionPlan.AI
);
setIdempotencyKey(nanoid());
mixpanel.track('ChangePlanSucceeded', {
segment: 'settings panel',
control: 'plan cancel action',
});
} finally {
setMutating(false);
}

View File

@ -6,6 +6,7 @@ import {
} from '@affine/component';
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
import { SubscriptionService } from '@affine/core/modules/cloud';
import { mixpanel } from '@affine/core/utils';
import { SubscriptionPlan } from '@affine/graphql';
import { useI18n } from '@affine/i18n';
import { SingleSelectSelectSolidIcon } from '@blocksuite/icons/rc';
@ -26,6 +27,13 @@ export const AIResume = ({ ...btnProps }: AIResumeProps) => {
const { openConfirmModal } = useConfirmModal();
const resume = useAsyncCallback(async () => {
mixpanel.track('PlanChangeStarted', {
segment: 'settings panel',
control: 'plan resume action',
type: subscription.ai$.value?.plan,
category: subscription.ai$.value?.recurring,
});
openConfirmModal({
title: t['com.affine.payment.ai.action.resume.confirm.title'](),
description:
@ -43,6 +51,10 @@ export const AIResume = ({ ...btnProps }: AIResumeProps) => {
idempotencyKey,
SubscriptionPlan.AI
);
mixpanel.track('ChangePlanSucceeded', {
segment: 'settings panel',
control: 'plan resume action',
});
notify({
icon: <SingleSelectSelectSolidIcon />,
iconColor: cssVar('processingColor'),

View File

@ -42,7 +42,7 @@ export const AISubscribe = ({ ...btnProps }: AISubscribeProps) => {
const subscribe = useAsyncCallback(async () => {
setMutating(true);
mixpanel.track('plan upgrade started', {
mixpanel.track('PlanUpgradeStarted', {
category: SubscriptionRecurring.Yearly,
type: SubscriptionPlan.AI,
});

View File

@ -167,11 +167,23 @@ const CurrentPlan = () => {
const Downgrade = ({ disabled }: { disabled?: boolean }) => {
const t = useI18n();
const [open, setOpen] = useState(false);
const subscription = useService(SubscriptionService).subscription;
const tooltipContent = disabled
? t['com.affine.payment.downgraded-tooltip']()
: null;
const handleClick = useCallback(() => {
setOpen(true);
mixpanel.track('PlanChangeStarted', {
segment: 'settings panel',
module: 'pricing plan list',
control: 'billing cancel action',
type: subscription.pro$.value?.plan,
category: subscription.pro$.value?.recurring,
});
}, [subscription.pro$.value?.plan, subscription.pro$.value?.recurring]);
return (
<CancelAction open={open} onOpenChange={setOpen}>
<Tooltip content={tooltipContent} rootOptions={{ delayDuration: 0 }}>
@ -179,7 +191,7 @@ const Downgrade = ({ disabled }: { disabled?: boolean }) => {
<Button
className={styles.planAction}
type="primary"
onClick={() => setOpen(true)}
onClick={handleClick}
disabled={disabled}
>
{t['com.affine.payment.downgrade']()}
@ -257,6 +269,13 @@ const Upgrade = ({ recurring }: { recurring: SubscriptionRecurring }) => {
}
setMutating(true);
mixpanel.track('PlanUpgradeStarted', {
segment: 'settings panel',
module: 'pricing plan list',
control: 'pricing plan action',
type: 'cloud pro subscription',
category: recurring,
});
const link = await subscriptionService.createCheckoutSession({
recurring,
idempotencyKey,
@ -268,7 +287,6 @@ const Upgrade = ({ recurring }: { recurring: SubscriptionRecurring }) => {
setIdempotencyKey(nanoid());
popupWindow(link);
setOpenedExternalWindow(true);
mixpanel.track_forms('Subscription', SubscriptionPlan.Pro);
}, [openPaymentDisableModal, subscriptionService, recurring, idempotencyKey]);
return (
@ -302,6 +320,17 @@ const ChangeRecurring = ({
const [idempotencyKey, setIdempotencyKey] = useState(nanoid());
const subscription = useService(SubscriptionService).subscription;
const onStartChange = useCallback(() => {
mixpanel.track('PlanChangeStarted', {
segment: 'settings panel',
module: 'pricing plan list',
control: 'plan resume action',
type: 'cloud pro subscription',
category: to,
});
setOpen(true);
}, [to]);
const change = useAsyncCallback(async () => {
setIsMutating(true);
await subscription.setSubscriptionRecurring(idempotencyKey, to);
@ -327,7 +356,7 @@ const ChangeRecurring = ({
<Button
className={styles.planAction}
type="primary"
onClick={() => setOpen(true)}
onClick={onStartChange}
disabled={disabled || isMutating}
loading={isMutating}
>
@ -371,6 +400,18 @@ const ResumeButton = () => {
const t = useI18n();
const [open, setOpen] = useState(false);
const [hovered, setHovered] = useState(false);
const subscription = useService(SubscriptionService).subscription;
const handleClick = useCallback(() => {
setOpen(true);
mixpanel.track('PlanChangeStarted', {
segment: 'settings panel',
module: 'pricing plan list',
control: 'pricing plan action',
type: 'cloud pro subscription',
category: subscription.pro$.value?.recurring,
});
}, [subscription.pro$.value?.recurring]);
return (
<ResumeAction open={open} onOpenChange={setOpen}>
@ -378,7 +419,7 @@ const ResumeButton = () => {
className={styles.planAction}
onMouseEnter={() => setHovered(true)}
onMouseLeave={() => setHovered(false)}
onClick={() => setOpen(true)}
onClick={handleClick}
>
{hovered
? t['com.affine.payment.resume-renewal']()

View File

@ -1,8 +1,10 @@
import { AuthPageContainer } from '@affine/component/auth-components';
import { Button } from '@affine/component/ui/button';
import { useNavigateHelper } from '@affine/core/hooks/use-navigate-helper';
import { SubscriptionPlan } from '@affine/graphql';
import { Trans, useI18n } from '@affine/i18n';
import { type ReactNode, useCallback } from 'react';
import mixpanel from 'mixpanel-browser';
import { type ReactNode, useCallback, useEffect } from 'react';
import { useSearchParams } from 'react-router-dom';
import * as styles from './styles.css';
@ -56,6 +58,13 @@ const UpgradeSuccessLayout = ({
export const CloudUpgradeSuccess = () => {
const t = useI18n();
useEffect(() => {
mixpanel.track('PlanUpgradeSucceeded', {
segment: 'settings panel',
control: 'plan upgrade action',
plan: SubscriptionPlan.Pro,
});
}, []);
return (
<UpgradeSuccessLayout
title={t['com.affine.payment.upgrade-success-page.title']()}
@ -66,7 +75,13 @@ export const CloudUpgradeSuccess = () => {
export const AIUpgradeSuccess = () => {
const t = useI18n();
useEffect(() => {
mixpanel.track('PlanUpgradeSucceeded', {
segment: 'settings panel',
control: 'plan upgrade action',
plan: SubscriptionPlan.Pro,
});
}, []);
return (
<UpgradeSuccessLayout
title={t['com.affine.payment.ai-upgrade-success-page.title']()}

View File

@ -53,6 +53,10 @@ export const Component = () => {
: !!subscriptionService.subscription.pro$.value;
if (!subscribed) {
setMessage('Creating checkout...');
mixpanel.track('PlanUpgradeStarted', {
type: plan,
category: recurring,
});
try {
const checkout = await subscriptionService.createCheckoutSession({
idempotencyKey,