mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 04:18:54 +00:00
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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'),
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
|
||||
@@ -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']()
|
||||
|
||||
@@ -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']()}
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user