diff --git a/packages/frontend/core/src/components/affine/auth/oauth.tsx b/packages/frontend/core/src/components/affine/auth/oauth.tsx index c532024776e52..614e3f8dd3391 100644 --- a/packages/frontend/core/src/components/affine/auth/oauth.tsx +++ b/packages/frontend/core/src/components/affine/auth/oauth.tsx @@ -8,6 +8,7 @@ import { GithubIcon, GoogleDuotoneIcon } from '@blocksuite/icons'; import type { ReactElement } from 'react'; import { useCallback, useState } from 'react'; +import { mixpanel } from '../../../utils'; import { useAuth } from './use-auth'; const OAuthProviderMap: Record< @@ -51,6 +52,7 @@ function OAuthProvider({ provider }: { provider: OAuthProviderType }) { const onClick = useCallback(() => { setIsConnecting(true); oauthSignIn(provider); + mixpanel.track('OAuth', { provider }); }, [provider, oauthSignIn]); return ( diff --git a/packages/frontend/core/src/components/affine/auth/sign-in.tsx b/packages/frontend/core/src/components/affine/auth/sign-in.tsx index 390d87729ab32..da9ed5da34836 100644 --- a/packages/frontend/core/src/components/affine/auth/sign-in.tsx +++ b/packages/frontend/core/src/components/affine/auth/sign-in.tsx @@ -91,6 +91,9 @@ export const SignIn: FC = ({ if (user.hasPassword && !subscriptionData) { setAuthState('signInWithPassword'); } else { + mixpanel.track_forms('SignIn', 'Email', { + email, + }); const res = await signIn(email, verifyToken, challenge); if (res?.status === 403 && res?.url === INTERNAL_BETA_URL) { return setAuthState('noAccess'); @@ -103,6 +106,9 @@ export const SignIn: FC = ({ } } else { const res = await signUp(email, verifyToken, challenge); + mixpanel.track_forms('SignUp', 'Email', { + email, + }); if (res?.status === 403 && res?.url === INTERNAL_BETA_URL) { return setAuthState('noAccess'); } else if (!res || res.status >= 400) { diff --git a/packages/frontend/core/src/components/affine/create-workspace-modal/index.tsx b/packages/frontend/core/src/components/affine/create-workspace-modal/index.tsx index 62210d1a19b7c..f9f4347d54e87 100644 --- a/packages/frontend/core/src/components/affine/create-workspace-modal/index.tsx +++ b/packages/frontend/core/src/components/affine/create-workspace-modal/index.tsx @@ -19,6 +19,7 @@ import { useSetAtom } from 'jotai'; import type { KeyboardEvent } from 'react'; import { useCallback, useLayoutEffect, useState } from 'react'; +import { mixpanel } from '../../../utils'; import { CloudSvg } from '../share-page-modal/cloud-svg'; import * as styles from './index.css'; @@ -226,6 +227,9 @@ export const CreateWorkspaceModal = ({ const onConfirmName = useAsyncCallback( async (name: string, workspaceFlavour: WorkspaceFlavour) => { + mixpanel.track_forms('CreateWorkspaceModel', 'CreateWorkspace', { + workspaceFlavour, + }); if (loading) return; setLoading(true); diff --git a/packages/frontend/core/src/components/affine/page-history-modal/history-modal.tsx b/packages/frontend/core/src/components/affine/page-history-modal/history-modal.tsx index 3fbe56b22003c..de9afb24a42be 100644 --- a/packages/frontend/core/src/components/affine/page-history-modal/history-modal.tsx +++ b/packages/frontend/core/src/components/affine/page-history-modal/history-modal.tsx @@ -27,7 +27,7 @@ import { import { encodeStateAsUpdate } from 'yjs'; import { pageHistoryModalAtom } from '../../../atoms/page-history'; -import { timestampToLocalTime } from '../../../utils'; +import { mixpanel, timestampToLocalTime } from '../../../utils'; import { BlockSuiteEditor } from '../../blocksuite/block-suite-editor'; import { StyledEditorModeSwitch } from '../../blocksuite/block-suite-mode-switch/style'; import { @@ -104,9 +104,15 @@ const HistoryEditorPreview = ({ title, }: HistoryEditorPreviewProps) => { const onSwitchToPageMode = useCallback(() => { + mixpanel.track('Button', { + resolve: 'HistorySwitchToPageMode', + }); onModeChange('page'); }, [onModeChange]); const onSwitchToEdgelessMode = useCallback(() => { + mixpanel.track('Button', { + resolve: 'HistorySwitchToEdgelessMode', + }); onModeChange('edgeless'); }, [onModeChange]); @@ -528,6 +534,9 @@ export const GlobalPageHistoryModal = () => { const workspace = useService(Workspace); const handleOpenChange = useCallback( (open: boolean) => { + mixpanel.track('Button', { + resolve: open ? 'OpenPageHistoryModal' : 'ClosePageHistoryModal', + }); setState(prev => ({ ...prev, open, diff --git a/packages/frontend/core/src/components/affine/setting-modal/account-setting/index.tsx b/packages/frontend/core/src/components/affine/setting-modal/account-setting/index.tsx index 42de0c33c3578..1f95dcec7bcd3 100644 --- a/packages/frontend/core/src/components/affine/setting-modal/account-setting/index.tsx +++ b/packages/frontend/core/src/components/affine/setting-modal/account-setting/index.tsx @@ -33,6 +33,7 @@ import { useServerFeatures } from '../../../../hooks/affine/use-server-config'; import { useMutation } from '../../../../hooks/use-mutation'; import { useQuery } from '../../../../hooks/use-query'; import { useUserSubscription } from '../../../../hooks/use-subscription'; +import { mixpanel } from '../../../../utils'; import { validateAndReduceImage } from '../../../../utils/reduce-image'; import { Upload } from '../../../pure/file-upload'; import * as styles from './style.css'; @@ -52,6 +53,9 @@ export const UserAvatar = () => { const handleUpdateUserAvatar = useAsyncCallback( async (file: File) => { try { + mixpanel.track_forms('UpdateProfile', 'UploadAvatar', { + userId: user.id, + }); const reducedFile = await validateAndReduceImage(file); const data = await avatarTrigger({ avatar: reducedFile, // Pass the reducedFile directly to the avatarTrigger @@ -74,6 +78,9 @@ export const UserAvatar = () => { const handleRemoveUserAvatar = useCallback( async (e: MouseEvent) => { + mixpanel.track('RemoveAvatar', { + userId: user.id, + }); e.stopPropagation(); await removeAvatarTrigger(); user.update({ avatarUrl: null }); @@ -120,6 +127,9 @@ export const AvatarAndName = () => { } try { + mixpanel.track_forms('UpdateProfile', 'UpdateUsername', { + userId: user.id, + }); const data = await updateProfile({ input: { name: input }, }); @@ -197,6 +207,9 @@ const StoragePanel = () => { const setSettingModalAtom = useSetAtom(openSettingModalAtom); const onUpgrade = useCallback(() => { + mixpanel.track('Button', { + resolve: 'UpgradeStorage', + }); setSettingModalAtom({ open: true, activeTab: 'plans', diff --git a/packages/frontend/core/src/components/affine/setting-modal/general-setting/billing/index.tsx b/packages/frontend/core/src/components/affine/setting-modal/general-setting/billing/index.tsx index 64686fdb9f386..761e107a8b488 100644 --- a/packages/frontend/core/src/components/affine/setting-modal/general-setting/billing/index.tsx +++ b/packages/frontend/core/src/components/affine/setting-modal/general-setting/billing/index.tsx @@ -31,6 +31,7 @@ import { useMutation } from '../../../../../hooks/use-mutation'; import { useQuery } from '../../../../../hooks/use-query'; import type { SubscriptionMutator } from '../../../../../hooks/use-subscription'; import { useUserSubscription } from '../../../../../hooks/use-subscription'; +import { mixpanel } from '../../../../../utils'; import { SWRErrorBoundary } from '../../../../pure/swr-error-bundary'; import { CancelAction, ResumeAction } from '../plans/actions'; import * as styles from './style.css'; @@ -115,11 +116,15 @@ const SubscriptionSettings = () => { const setOpenSettingModalAtom = useSetAtom(openSettingModalAtom); const gotoPlansSetting = useCallback(() => { + mixpanel.track('Button', { + resolve: 'ChangePlan', + currentPlan: plan, + }); setOpenSettingModalAtom({ open: true, activeTab: 'plans', }); - }, [setOpenSettingModalAtom]); + }, [setOpenSettingModalAtom, plan]); const currentPlanDesc = useMemo(() => { const messageKey = getMessageKey(plan, recurring); diff --git a/packages/frontend/core/src/components/affine/setting-modal/general-setting/plans/plan-card.tsx b/packages/frontend/core/src/components/affine/setting-modal/general-setting/plans/plan-card.tsx index e917cd58a2dab..aecd730acda8f 100644 --- a/packages/frontend/core/src/components/affine/setting-modal/general-setting/plans/plan-card.tsx +++ b/packages/frontend/core/src/components/affine/setting-modal/general-setting/plans/plan-card.tsx @@ -24,6 +24,7 @@ import { openPaymentDisableAtom } from '../../../../../atoms'; import { authAtom } from '../../../../../atoms/index'; import { useCurrentLoginStatus } from '../../../../../hooks/affine/use-current-login-status'; import { useMutation } from '../../../../../hooks/use-mutation'; +import { mixpanel } from '../../../../../utils'; import { CancelAction, ResumeAction } from './actions'; import { BulledListIcon } from './icons/bulled-list'; import { ConfirmLoadingModal } from './modals'; @@ -206,6 +207,7 @@ const ActionButton = ({ const mutateAndNotify = useCallback( (sub: Parameters[0]) => { + mixpanel.track_forms('Subscription', detail.plan, sub); onSubscriptionUpdate?.(sub); onNotify?.({ detail, recurring }); }, @@ -346,6 +348,12 @@ const BookDemo = ({ plan }: { plan: SubscriptionPlan }) => { href={url} target="_blank" rel="noreferrer" + onClick={() => { + mixpanel.track('Button', { + resolve: 'BookDemo', + url, + }); + }} >