From ab92efcfc09b38bf38464c1864942efc1d4fdcff Mon Sep 17 00:00:00 2001 From: EYHN Date: Tue, 30 Jul 2024 13:22:16 +0000 Subject: [PATCH] feat(core): improve mixpanel (#7652) move @affine/core/utils/mixpanel -> @affine/core/mixpanel now you can debug mixpanel on browser devtool ![CleanShot 2024-07-30 at 17.32.48@2x.png](https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/g3jz87HxbjOJpXV3FPT7/083c1286-39fd-4569-b4d2-e6e84cf2e797.png) --- .../core/src/commands/affine-navigation.tsx | 2 +- .../affine/ai-onboarding/edgeless.dialog.tsx | 2 +- .../affine/ai-onboarding/general.dialog.tsx | 4 +- .../core/src/components/affine/auth/oauth.tsx | 2 +- .../src/components/affine/auth/sign-in.tsx | 6 +- .../affine/auth/user-plan-button.tsx | 2 +- .../affine/create-workspace-modal/index.tsx | 4 +- .../page-history-modal/history-modal.tsx | 2 +- .../quota-reached-modal/cloud-quota-modal.tsx | 2 +- .../account-setting/ai-usage-panel.tsx | 2 +- .../setting-modal/account-setting/index.tsx | 6 +- .../general-setting/about/index.tsx | 3 +- .../general-setting/billing/index.tsx | 5 +- .../general-setting/plans/actions.tsx | 10 +- .../plans/ai/actions/cancel.tsx | 6 +- .../plans/ai/actions/resume.tsx | 8 +- .../plans/ai/actions/subscribe.tsx | 3 +- .../general-setting/plans/plan-card.tsx | 8 +- .../setting-modal/setting-sidebar/index.tsx | 2 +- .../new-workspace-setting-detail/members.tsx | 2 +- .../share-menu/share-page.tsx | 2 +- .../app-sidebar/app-download-button/index.tsx | 2 +- .../block-suite-editor/ai/setup-provider.tsx | 2 +- .../block-suite-editor/ai/tracker.ts | 2 +- .../specs/custom/linked-widget.ts | 2 +- .../specs/custom/root-block.ts | 4 +- .../specs/custom/spec-patchers.tsx | 2 +- .../block-suite-header/menu/index.tsx | 2 +- .../block-suite-mode-switch/index.tsx | 3 +- .../page-list/components/new-page-button.tsx | 2 +- .../page-list/docs/page-list-header.tsx | 2 +- .../components/page-list/operation-cell.tsx | 2 +- .../user-with-workspace-list/index.tsx | 2 +- .../root-app-sidebar/import-page.tsx | 2 +- .../src/components/root-app-sidebar/index.tsx | 2 +- .../components/root-app-sidebar/user-info.tsx | 2 +- .../components/workspace-selector/index.tsx | 2 +- .../components/workspace-upgrade/upgrade.tsx | 2 +- .../core/src/hooks/affine/use-export-page.ts | 2 +- ...se-register-blocksuite-editor-commands.tsx | 2 +- .../core/src/hooks/affine/use-share-url.ts | 2 +- .../hooks/affine/use-subscription-notify.tsx | 4 +- .../core/src/hooks/use-app-updater.ts | 3 +- .../core/src/mixpanel/events/index.ts | 23 +++++ .../mixpanel/events/plan-change-started.ts | 16 ++++ .../{ => events}/plan-change-succeed.ts | 2 +- packages/frontend/core/src/mixpanel/index.ts | 91 ++++++++++++++++++- .../frontend/core/src/mixpanel/mixpanel.d.ts | 19 ++++ .../core/src/mixpanel/plan-change-started.ts | 15 --- .../explorer/views/nodes/doc/empty.tsx | 2 +- .../modules/telemetry/services/telemetry.ts | 16 +--- .../modules/workbench/services/workbench.ts | 2 +- .../frontend/core/src/pages/subscribe.tsx | 2 +- .../workspace/all-page/all-page-header.tsx | 2 +- packages/frontend/core/src/telemetry.tsx | 2 +- packages/frontend/core/src/utils/index.ts | 1 - packages/frontend/core/src/utils/mixpanel.ts | 42 --------- tests/kit/utils/page-logic.ts | 2 +- 58 files changed, 221 insertions(+), 149 deletions(-) create mode 100644 packages/frontend/core/src/mixpanel/events/index.ts create mode 100644 packages/frontend/core/src/mixpanel/events/plan-change-started.ts rename packages/frontend/core/src/mixpanel/{ => events}/plan-change-succeed.ts (80%) create mode 100644 packages/frontend/core/src/mixpanel/mixpanel.d.ts delete mode 100644 packages/frontend/core/src/mixpanel/plan-change-started.ts delete mode 100644 packages/frontend/core/src/utils/mixpanel.ts diff --git a/packages/frontend/core/src/commands/affine-navigation.tsx b/packages/frontend/core/src/commands/affine-navigation.tsx index 678ba342d4..106bdb8fa8 100644 --- a/packages/frontend/core/src/commands/affine-navigation.tsx +++ b/packages/frontend/core/src/commands/affine-navigation.tsx @@ -6,7 +6,7 @@ import type { createStore } from 'jotai'; import { openSettingModalAtom, openWorkspaceListModalAtom } from '../atoms'; import type { useNavigateHelper } from '../hooks/use-navigate-helper'; -import { mixpanel } from '../utils/mixpanel'; +import { mixpanel } from '../mixpanel'; import { registerAffineCommand } from './registry'; export function registerAffineNavigationCommands({ diff --git a/packages/frontend/core/src/components/affine/ai-onboarding/edgeless.dialog.tsx b/packages/frontend/core/src/components/affine/ai-onboarding/edgeless.dialog.tsx index a7da0b4040..b2a8c95fee 100644 --- a/packages/frontend/core/src/components/affine/ai-onboarding/edgeless.dialog.tsx +++ b/packages/frontend/core/src/components/affine/ai-onboarding/edgeless.dialog.tsx @@ -1,7 +1,7 @@ import { Button, FlexWrapper, notify } from '@affine/component'; import { openSettingModalAtom } from '@affine/core/atoms'; +import { mixpanel } from '@affine/core/mixpanel'; import { SubscriptionService } from '@affine/core/modules/cloud'; -import { mixpanel } from '@affine/core/utils'; import { useI18n } from '@affine/i18n'; import { AiIcon } from '@blocksuite/icons/rc'; import { diff --git a/packages/frontend/core/src/components/affine/ai-onboarding/general.dialog.tsx b/packages/frontend/core/src/components/affine/ai-onboarding/general.dialog.tsx index 8bba8cfcb4..67ee7d0655 100644 --- a/packages/frontend/core/src/components/affine/ai-onboarding/general.dialog.tsx +++ b/packages/frontend/core/src/components/affine/ai-onboarding/general.dialog.tsx @@ -1,8 +1,8 @@ import { Button, IconButton, Modal } from '@affine/component'; import { openSettingModalAtom } from '@affine/core/atoms'; import { useBlurRoot } from '@affine/core/hooks/use-blur-root'; +import { mixpanel } from '@affine/core/mixpanel'; import { AuthService, SubscriptionService } from '@affine/core/modules/cloud'; -import { mixpanel } from '@affine/core/utils'; import { Trans, useI18n } from '@affine/i18n'; import { ArrowLeftSmallIcon } from '@blocksuite/icons/rc'; import { useLiveData, useServices } from '@toeverything/infra'; @@ -117,7 +117,7 @@ export const AIOnboardingGeneral = () => { scrollAnchor: 'aiPricingPlan', }); mixpanel.track('PlansViewed', { - page: 'whiteboard-editor', + page: 'whiteboard editor', segment: 'ai onboarding', module: 'general', }); diff --git a/packages/frontend/core/src/components/affine/auth/oauth.tsx b/packages/frontend/core/src/components/affine/auth/oauth.tsx index 596b9954c6..794e3c0dd8 100644 --- a/packages/frontend/core/src/components/affine/auth/oauth.tsx +++ b/packages/frontend/core/src/components/affine/auth/oauth.tsx @@ -1,6 +1,7 @@ import { notify, Skeleton } from '@affine/component'; import { Button } from '@affine/component/ui/button'; import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks'; +import { mixpanel } from '@affine/core/mixpanel'; import { OAuthProviderType } from '@affine/graphql'; import { GithubIcon, GoogleDuotoneIcon } from '@blocksuite/icons/rc'; import { useLiveData, useService } from '@toeverything/infra'; @@ -8,7 +9,6 @@ import type { ReactElement } from 'react'; import { useState } from 'react'; import { AuthService, ServerConfigService } from '../../../modules/cloud'; -import { mixpanel } from '../../../utils'; const OAuthProviderMap: Record< OAuthProviderType, 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 0bb7a6eb60..b015393d41 100644 --- a/packages/frontend/core/src/components/affine/auth/sign-in.tsx +++ b/packages/frontend/core/src/components/affine/auth/sign-in.tsx @@ -3,6 +3,7 @@ import { AuthInput, ModalHeader } from '@affine/component/auth-components'; import { Button } from '@affine/component/ui/button'; import { authAtom } from '@affine/core/atoms'; import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks'; +import { mixpanel } from '@affine/core/mixpanel'; import { Trans, useI18n } from '@affine/i18n'; import { ArrowDownBigIcon } from '@blocksuite/icons/rc'; import { useLiveData, useService } from '@toeverything/infra'; @@ -12,7 +13,6 @@ import { useCallback, useEffect, useState } from 'react'; import { useSearchParams } from 'react-router-dom'; import { AuthService } from '../../../modules/cloud'; -import { mixpanel } from '../../../utils'; import { emailRegex } from '../../../utils/email-regex'; import type { AuthPanelProps } from './index'; import { OAuth } from './oauth'; @@ -74,7 +74,7 @@ export const SignIn: FC = ({ if (hasPassword) { setAuthState('signInWithPassword'); } else { - mixpanel.track_forms('SignIn', 'Email', { + mixpanel.track('SignIn', { email, }); await authService.sendEmailMagicLink( @@ -92,7 +92,7 @@ export const SignIn: FC = ({ challenge, searchParams.get('redirect_uri') ); - mixpanel.track_forms('SignUp', 'Email', { + mixpanel.track('SignUp', { email, }); setAuthState('afterSignUpSendEmail'); diff --git a/packages/frontend/core/src/components/affine/auth/user-plan-button.tsx b/packages/frontend/core/src/components/affine/auth/user-plan-button.tsx index b970b99d4b..a882c506af 100644 --- a/packages/frontend/core/src/components/affine/auth/user-plan-button.tsx +++ b/packages/frontend/core/src/components/affine/auth/user-plan-button.tsx @@ -1,5 +1,5 @@ import { Tooltip } from '@affine/component/ui/tooltip'; -import { mixpanel } from '@affine/core/utils'; +import { mixpanel } from '@affine/core/mixpanel'; import { SubscriptionPlan } from '@affine/graphql'; import { useI18n } from '@affine/i18n'; import { useLiveData, useServices } from '@toeverything/infra'; 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 d5572b1ae1..65a09cd82a 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 @@ -3,6 +3,7 @@ import type { ConfirmModalProps } from '@affine/component/ui/modal'; import { ConfirmModal, Modal } from '@affine/component/ui/modal'; import { authAtom } from '@affine/core/atoms'; import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks'; +import { mixpanel } from '@affine/core/mixpanel'; import { DebugLogger } from '@affine/debug'; import { apis } from '@affine/electron-api'; import { WorkspaceFlavour } from '@affine/env/workspace'; @@ -20,7 +21,6 @@ import { useCallback, useLayoutEffect, useState } from 'react'; import { buildShowcaseWorkspace } from '../../../bootstrap/first-app-data'; import { AuthService } from '../../../modules/cloud'; import { _addLocalWorkspace } from '../../../modules/workspace-engine'; -import { mixpanel } from '../../../utils'; import { CloudSvg } from '../share-page-modal/cloud-svg'; import * as styles from './index.css'; @@ -221,7 +221,7 @@ export const CreateWorkspaceModal = ({ const onConfirmName = useAsyncCallback( async (name: string, workspaceFlavour: WorkspaceFlavour) => { - mixpanel.track_forms('CreateWorkspaceModel', 'CreateWorkspace', { + mixpanel.track('CreateWorkspace', { workspaceFlavour, }); if (loading) return; 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 49cf528ec4..f2a32185ab 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 @@ -4,6 +4,7 @@ import { Button, IconButton } from '@affine/component/ui/button'; import { Modal, useConfirmModal } from '@affine/component/ui/modal'; import { openSettingModalAtom } from '@affine/core/atoms'; import { useDocCollectionPageTitle } from '@affine/core/hooks/use-block-suite-workspace-page-title'; +import { mixpanel } from '@affine/core/mixpanel'; import { WorkspacePermissionService } from '@affine/core/modules/permissions'; import { WorkspaceQuotaService } from '@affine/core/modules/quota'; import { i18nTime, Trans, useI18n } from '@affine/i18n'; @@ -32,7 +33,6 @@ import { import { encodeStateAsUpdate } from 'yjs'; import { pageHistoryModalAtom } from '../../../atoms/page-history'; -import { mixpanel } from '../../../utils'; import { BlockSuiteEditor } from '../../blocksuite/block-suite-editor'; import { StyledEditorModeSwitch } from '../../blocksuite/block-suite-mode-switch/style'; import { diff --git a/packages/frontend/core/src/components/affine/quota-reached-modal/cloud-quota-modal.tsx b/packages/frontend/core/src/components/affine/quota-reached-modal/cloud-quota-modal.tsx index 7f7a6e74ff..662bf00808 100644 --- a/packages/frontend/core/src/components/affine/quota-reached-modal/cloud-quota-modal.tsx +++ b/packages/frontend/core/src/components/affine/quota-reached-modal/cloud-quota-modal.tsx @@ -1,9 +1,9 @@ import { ConfirmModal } from '@affine/component/ui/modal'; import { openQuotaModalAtom, openSettingModalAtom } from '@affine/core/atoms'; +import { mixpanel } from '@affine/core/mixpanel'; import { UserQuotaService } from '@affine/core/modules/cloud'; import { WorkspacePermissionService } from '@affine/core/modules/permissions'; import { WorkspaceQuotaService } from '@affine/core/modules/quota'; -import { mixpanel } from '@affine/core/utils'; import { useI18n } from '@affine/i18n'; import { useLiveData, useService, WorkspaceService } from '@toeverything/infra'; import bytes from 'bytes'; diff --git a/packages/frontend/core/src/components/affine/setting-modal/account-setting/ai-usage-panel.tsx b/packages/frontend/core/src/components/affine/setting-modal/account-setting/ai-usage-panel.tsx index f53db45a41..16c1dc1bcc 100644 --- a/packages/frontend/core/src/components/affine/setting-modal/account-setting/ai-usage-panel.tsx +++ b/packages/frontend/core/src/components/affine/setting-modal/account-setting/ai-usage-panel.tsx @@ -1,12 +1,12 @@ import { Button, ErrorMessage, Skeleton } from '@affine/component'; import { SettingRow } from '@affine/component/setting-components'; import { openSettingModalAtom } from '@affine/core/atoms'; +import { mixpanel } from '@affine/core/mixpanel'; import { ServerConfigService, SubscriptionService, UserCopilotQuotaService, } from '@affine/core/modules/cloud'; -import { mixpanel } from '@affine/core/utils'; import { useI18n } from '@affine/i18n'; import { useLiveData, useService } from '@toeverything/infra'; import { cssVar } from '@toeverything/theme'; 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 d2eb0f4d23..f63aa3c057 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 @@ -6,6 +6,7 @@ import { import { Avatar } from '@affine/component/ui/avatar'; import { Button } from '@affine/component/ui/button'; import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks'; +import { mixpanel } from '@affine/core/mixpanel'; import { useI18n } from '@affine/i18n'; import { ArrowRightSmallIcon, CameraIcon } from '@blocksuite/icons/rc'; import { @@ -24,7 +25,6 @@ import { openSignOutModalAtom, } from '../../../../atoms'; import { AuthService, ServerConfigService } from '../../../../modules/cloud'; -import { mixpanel } from '../../../../utils'; import { Upload } from '../../../pure/file-upload'; import { AIUsagePanel } from './ai-usage-panel'; import { StorageProgress } from './storage-progress'; @@ -38,7 +38,7 @@ export const UserAvatar = () => { const handleUpdateUserAvatar = useAsyncCallback( async (file: File) => { try { - mixpanel.track_forms('UpdateProfile', 'UploadAvatar', { + mixpanel.track('UploadAvatar', { userId: account.id, }); await session.uploadAvatar(file); @@ -104,7 +104,7 @@ export const AvatarAndName = () => { } try { - mixpanel.track_forms('UpdateProfile', 'UpdateUsername', { + mixpanel.track('UpdateUsername', { userId: account.id, }); await session.updateLabel(input); diff --git a/packages/frontend/core/src/components/affine/setting-modal/general-setting/about/index.tsx b/packages/frontend/core/src/components/affine/setting-modal/general-setting/about/index.tsx index 096693370a..75d04af5c4 100644 --- a/packages/frontend/core/src/components/affine/setting-modal/general-setting/about/index.tsx +++ b/packages/frontend/core/src/components/affine/setting-modal/general-setting/about/index.tsx @@ -5,13 +5,14 @@ import { SettingWrapper, } from '@affine/component/setting-components'; import { useAppUpdater } from '@affine/core/hooks/use-app-updater'; +import { mixpanel } from '@affine/core/mixpanel'; import { useI18n } from '@affine/i18n'; import { ArrowRightSmallIcon, OpenInNewIcon } from '@blocksuite/icons/rc'; import { useCallback } from 'react'; import { useAppSettingHelper } from '../../../../../hooks/affine/use-app-setting-helper'; import { appIconMap, appNames } from '../../../../../pages/open-app'; -import { mixpanel, popupWindow } from '../../../../../utils'; +import { popupWindow } from '../../../../../utils'; import { relatedLinks } from './config'; import * as styles from './style.css'; import { UpdateCheckSection } from './update-check-section'; 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 179ea88bc0..8aded7e9a7 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 @@ -9,6 +9,7 @@ import { Button, IconButton } from '@affine/component/ui/button'; import { Loading } from '@affine/component/ui/loading'; import { getUpgradeQuestionnaireLink } from '@affine/core/hooks/affine/use-subscription-notify'; import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks'; +import { mixpanel } from '@affine/core/mixpanel'; import type { InvoicesQuery } from '@affine/graphql'; import { createCustomerPortalMutation, @@ -32,7 +33,7 @@ import { import { useMutation } from '../../../../../hooks/use-mutation'; import { useQuery } from '../../../../../hooks/use-query'; import { AuthService, SubscriptionService } from '../../../../../modules/cloud'; -import { mixpanel, mixpanelTrack, popupWindow } from '../../../../../utils'; +import { popupWindow } from '../../../../../utils'; import { SWRErrorBoundary } from '../../../../pure/swr-error-bundary'; import { CancelAction, ResumeAction } from '../plans/actions'; import { AICancel, AIResume, AISubscribe } from '../plans/ai/actions'; @@ -479,7 +480,7 @@ const ResumeSubscription = () => { const type = subscription.pro$.value?.plan; const category = subscription.pro$.value?.recurring; if (type && category) { - mixpanelTrack('PlanChangeStarted', { + mixpanel.track('PlanChangeStarted', { segment: 'settings panel', module: 'pricing plan list', control: 'paying', diff --git a/packages/frontend/core/src/components/affine/setting-modal/general-setting/plans/actions.tsx b/packages/frontend/core/src/components/affine/setting-modal/general-setting/plans/actions.tsx index f801ed0052..2f14c3c00d 100644 --- a/packages/frontend/core/src/components/affine/setting-modal/general-setting/plans/actions.tsx +++ b/packages/frontend/core/src/components/affine/setting-modal/general-setting/plans/actions.tsx @@ -1,7 +1,7 @@ import { getDowngradeQuestionnaireLink } from '@affine/core/hooks/affine/use-subscription-notify'; import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks'; -import type { MixpanelEvents } from '@affine/core/mixpanel'; -import { mixpanelTrack } from '@affine/core/utils'; +import { mixpanel } from '@affine/core/mixpanel'; +import type { MixpanelEvents } from '@affine/core/mixpanel/events'; import { SubscriptionPlan } from '@affine/graphql'; import { useLiveData, useService } from '@toeverything/infra'; import { nanoid } from 'nanoid'; @@ -36,7 +36,7 @@ export const CancelAction = ({ useEffect(() => { if (!open || !proSubscription) return; - mixpanelTrack('PlanChangeStarted', { + mixpanel.track('PlanChangeStarted', { segment: 'settings panel', module, control: 'cancel', @@ -58,7 +58,7 @@ export const CancelAction = ({ onOpenChange(false); const proSubscription = subscription.pro$.value; if (proSubscription) { - mixpanelTrack('PlanChangeSucceeded', { + mixpanel.track('PlanChangeSucceeded', { control: 'cancel', type: proSubscription.plan, category: proSubscription.recurring, @@ -128,7 +128,7 @@ export const ResumeAction = ({ onOpenChange(false); const proSubscription = subscription.pro$.value; if (proSubscription) { - mixpanelTrack('PlanChangeSucceeded', { + mixpanel.track('PlanChangeSucceeded', { control: 'paying', type: proSubscription.plan, category: proSubscription.recurring, diff --git a/packages/frontend/core/src/components/affine/setting-modal/general-setting/plans/ai/actions/cancel.tsx b/packages/frontend/core/src/components/affine/setting-modal/general-setting/plans/ai/actions/cancel.tsx index 34224144f6..118191bf95 100644 --- a/packages/frontend/core/src/components/affine/setting-modal/general-setting/plans/ai/actions/cancel.tsx +++ b/packages/frontend/core/src/components/affine/setting-modal/general-setting/plans/ai/actions/cancel.tsx @@ -2,9 +2,9 @@ import { Button, type ButtonProps, useConfirmModal } from '@affine/component'; import { useDowngradeNotify } from '@affine/core/components/affine/subscription-landing/notify'; import { getDowngradeQuestionnaireLink } from '@affine/core/hooks/affine/use-subscription-notify'; import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks'; -import type { MixpanelEvents } from '@affine/core/mixpanel'; +import { mixpanel } from '@affine/core/mixpanel'; +import type { MixpanelEvents } from '@affine/core/mixpanel/events'; import { AuthService, SubscriptionService } from '@affine/core/modules/cloud'; -import { mixpanel, mixpanelTrack } from '@affine/core/utils'; import { SubscriptionPlan } from '@affine/graphql'; import { useI18n } from '@affine/i18n'; import { useService } from '@toeverything/infra'; @@ -27,7 +27,7 @@ export const AICancel = ({ module, ...btnProps }: AICancelProps) => { const cancel = useAsyncCallback(async () => { const aiSubscription = subscription.ai$.value; if (aiSubscription) { - mixpanelTrack('PlanChangeStarted', { + mixpanel.track('PlanChangeStarted', { module, segment: 'settings panel', control: 'cancel', diff --git a/packages/frontend/core/src/components/affine/setting-modal/general-setting/plans/ai/actions/resume.tsx b/packages/frontend/core/src/components/affine/setting-modal/general-setting/plans/ai/actions/resume.tsx index 0edb3dcbef..12e9292037 100644 --- a/packages/frontend/core/src/components/affine/setting-modal/general-setting/plans/ai/actions/resume.tsx +++ b/packages/frontend/core/src/components/affine/setting-modal/general-setting/plans/ai/actions/resume.tsx @@ -5,9 +5,9 @@ import { useConfirmModal, } from '@affine/component'; import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks'; -import type { MixpanelEvents } from '@affine/core/mixpanel'; +import { mixpanel } from '@affine/core/mixpanel'; +import type { MixpanelEvents } from '@affine/core/mixpanel/events'; import { SubscriptionService } from '@affine/core/modules/cloud'; -import { mixpanelTrack } from '@affine/core/utils'; import { SubscriptionPlan } from '@affine/graphql'; import { useI18n } from '@affine/i18n'; import { SingleSelectSelectSolidIcon } from '@blocksuite/icons/rc'; @@ -32,7 +32,7 @@ export const AIResume = ({ module, ...btnProps }: AIResumeProps) => { const resume = useAsyncCallback(async () => { const aiSubscription = subscription.ai$.value; if (aiSubscription) { - mixpanelTrack('PlanChangeStarted', { + mixpanel.track('PlanChangeStarted', { module, segment: 'settings panel', control: 'paying', @@ -59,7 +59,7 @@ export const AIResume = ({ module, ...btnProps }: AIResumeProps) => { SubscriptionPlan.AI ); if (aiSubscription) { - mixpanelTrack('PlanChangeSucceeded', { + mixpanel.track('PlanChangeSucceeded', { category: aiSubscription.recurring, control: 'paying', type: aiSubscription.plan, diff --git a/packages/frontend/core/src/components/affine/setting-modal/general-setting/plans/ai/actions/subscribe.tsx b/packages/frontend/core/src/components/affine/setting-modal/general-setting/plans/ai/actions/subscribe.tsx index e08d3ad3a5..e00eb3eceb 100644 --- a/packages/frontend/core/src/components/affine/setting-modal/general-setting/plans/ai/actions/subscribe.tsx +++ b/packages/frontend/core/src/components/affine/setting-modal/general-setting/plans/ai/actions/subscribe.tsx @@ -1,8 +1,9 @@ import { Button, type ButtonProps, Skeleton } from '@affine/component'; import { generateSubscriptionCallbackLink } from '@affine/core/hooks/affine/use-subscription-notify'; import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks'; +import { mixpanel } from '@affine/core/mixpanel'; import { AuthService, SubscriptionService } from '@affine/core/modules/cloud'; -import { mixpanel, popupWindow } from '@affine/core/utils'; +import { popupWindow } from '@affine/core/utils'; import { SubscriptionPlan, SubscriptionRecurring } from '@affine/graphql'; import { useI18n } from '@affine/i18n'; import { useLiveData, useService } from '@toeverything/infra'; 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 b3445d0cf0..3d166b0507 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 @@ -2,8 +2,9 @@ import { Button } from '@affine/component/ui/button'; import { Tooltip } from '@affine/component/ui/tooltip'; import { generateSubscriptionCallbackLink } from '@affine/core/hooks/affine/use-subscription-notify'; import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks'; +import { mixpanel } from '@affine/core/mixpanel'; import { AuthService, SubscriptionService } from '@affine/core/modules/cloud'; -import { mixpanelTrack, popupWindow } from '@affine/core/utils'; +import { popupWindow } from '@affine/core/utils'; import type { SubscriptionRecurring } from '@affine/graphql'; import { SubscriptionPlan, SubscriptionStatus } from '@affine/graphql'; import { Trans, useI18n } from '@affine/i18n'; @@ -16,7 +17,6 @@ import type { HTMLAttributes, PropsWithChildren } from 'react'; import { useCallback, useEffect, useMemo, useState } from 'react'; import { authAtom } from '../../../../../atoms/index'; -import { mixpanel } from '../../../../../utils'; import { CancelAction, ResumeAction } from './actions'; import type { DynamicPrice, FixedPrice } from './cloud-plans'; import { ConfirmLoadingModal } from './modals'; @@ -337,7 +337,7 @@ const ChangeRecurring = ({ const subscription = useService(SubscriptionService).subscription; const onStartChange = useCallback(() => { - mixpanelTrack('PlanChangeStarted', { + mixpanel.track('PlanChangeStarted', { segment: 'settings panel', module: 'pricing plan list', control: 'paying', @@ -422,7 +422,7 @@ const ResumeButton = () => { setOpen(true); const pro = subscription.pro$.value; if (pro) { - mixpanelTrack('PlanChangeStarted', { + mixpanel.track('PlanChangeStarted', { segment: 'settings panel', module: 'pricing plan list', control: 'paying', diff --git a/packages/frontend/core/src/components/affine/setting-modal/setting-sidebar/index.tsx b/packages/frontend/core/src/components/affine/setting-modal/setting-sidebar/index.tsx index c7309bc2b7..e723166715 100644 --- a/packages/frontend/core/src/components/affine/setting-modal/setting-sidebar/index.tsx +++ b/packages/frontend/core/src/components/affine/setting-modal/setting-sidebar/index.tsx @@ -6,6 +6,7 @@ import { Avatar } from '@affine/component/ui/avatar'; import { Tooltip } from '@affine/component/ui/tooltip'; import { WorkspaceAvatar } from '@affine/component/workspace-avatar'; import { useWorkspaceInfo } from '@affine/core/hooks/use-workspace-info'; +import { mixpanel } from '@affine/core/mixpanel'; import { AuthService } from '@affine/core/modules/cloud'; import { UserFeatureService } from '@affine/core/modules/cloud/services/user-feature'; import { UNTITLED_WORKSPACE_NAME } from '@affine/env/constant'; @@ -24,7 +25,6 @@ import { useAtom } from 'jotai/react'; import { Suspense, useCallback, useEffect, useMemo } from 'react'; import { authAtom } from '../../../../atoms'; -import { mixpanel } from '../../../../utils'; import { UserPlanButton } from '../../auth/user-plan-button'; import { useGeneralSettingList } from '../general-setting'; import type { ActiveTab, WorkspaceSubTab } from '../types'; diff --git a/packages/frontend/core/src/components/affine/setting-modal/workspace-setting/new-workspace-setting-detail/members.tsx b/packages/frontend/core/src/components/affine/setting-modal/workspace-setting/new-workspace-setting-detail/members.tsx index dfaadd322c..80abe08f03 100644 --- a/packages/frontend/core/src/components/affine/setting-modal/workspace-setting/new-workspace-setting-detail/members.tsx +++ b/packages/frontend/core/src/components/affine/setting-modal/workspace-setting/new-workspace-setting-detail/members.tsx @@ -21,9 +21,9 @@ import { useMemberCount } from '@affine/core/hooks/affine/use-member-count'; import type { Member } from '@affine/core/hooks/affine/use-members'; import { useMembers } from '@affine/core/hooks/affine/use-members'; import { useRevokeMemberPermission } from '@affine/core/hooks/affine/use-revoke-member-permission'; +import { mixpanel } from '@affine/core/mixpanel'; import { WorkspacePermissionService } from '@affine/core/modules/permissions'; import { WorkspaceQuotaService } from '@affine/core/modules/quota'; -import { mixpanel } from '@affine/core/utils'; import { WorkspaceFlavour } from '@affine/env/workspace'; import { Permission } from '@affine/graphql'; import { useI18n } from '@affine/i18n'; diff --git a/packages/frontend/core/src/components/affine/share-page-modal/share-menu/share-page.tsx b/packages/frontend/core/src/components/affine/share-page-modal/share-menu/share-page.tsx index c6ad587399..44fca95086 100644 --- a/packages/frontend/core/src/components/affine/share-page-modal/share-menu/share-page.tsx +++ b/packages/frontend/core/src/components/affine/share-page-modal/share-menu/share-page.tsx @@ -4,9 +4,9 @@ import { Button } from '@affine/component/ui/button'; import { Menu, MenuItem, MenuTrigger } from '@affine/component/ui/menu'; import { useSharingUrl } from '@affine/core/hooks/affine/use-share-url'; import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks'; +import { mixpanel } from '@affine/core/mixpanel'; import { ServerConfigService } from '@affine/core/modules/cloud'; import { ShareService } from '@affine/core/modules/share-doc'; -import { mixpanel } from '@affine/core/utils'; import { WorkspaceFlavour } from '@affine/env/workspace'; import { PublicPageMode } from '@affine/graphql'; import { useI18n } from '@affine/i18n'; diff --git a/packages/frontend/core/src/components/app-sidebar/app-download-button/index.tsx b/packages/frontend/core/src/components/app-sidebar/app-download-button/index.tsx index d595ecfbd8..d467dc8d71 100644 --- a/packages/frontend/core/src/components/app-sidebar/app-download-button/index.tsx +++ b/packages/frontend/core/src/components/app-sidebar/app-download-button/index.tsx @@ -1,8 +1,8 @@ +import { mixpanel } from '@affine/core/mixpanel'; import { CloseIcon, DownloadIcon } from '@blocksuite/icons/rc'; import clsx from 'clsx'; import { useCallback, useState } from 'react'; -import { mixpanel } from '../../../utils'; import * as styles from './index.css'; // Although it is called an input, it is actually a button. diff --git a/packages/frontend/core/src/components/blocksuite/block-suite-editor/ai/setup-provider.tsx b/packages/frontend/core/src/components/blocksuite/block-suite-editor/ai/setup-provider.tsx index c551c19ab3..ecc6d702b8 100644 --- a/packages/frontend/core/src/components/blocksuite/block-suite-editor/ai/setup-provider.tsx +++ b/packages/frontend/core/src/components/blocksuite/block-suite-editor/ai/setup-provider.tsx @@ -2,7 +2,7 @@ import { notify } from '@affine/component'; import { authAtom, openSettingModalAtom } from '@affine/core/atoms'; import { AIProvider } from '@affine/core/blocksuite/presets/ai'; import { toggleGeneralAIOnboarding } from '@affine/core/components/affine/ai-onboarding/apis'; -import { mixpanel } from '@affine/core/utils'; +import { mixpanel } from '@affine/core/mixpanel'; import { getBaseUrl, type getCopilotHistoriesQuery, diff --git a/packages/frontend/core/src/components/blocksuite/block-suite-editor/ai/tracker.ts b/packages/frontend/core/src/components/blocksuite/block-suite-editor/ai/tracker.ts index cf4857b681..60b74b0adb 100644 --- a/packages/frontend/core/src/components/blocksuite/block-suite-editor/ai/tracker.ts +++ b/packages/frontend/core/src/components/blocksuite/block-suite-editor/ai/tracker.ts @@ -1,5 +1,5 @@ import { AIProvider } from '@affine/core/blocksuite/presets/ai'; -import { mixpanel } from '@affine/core/utils'; +import { mixpanel } from '@affine/core/mixpanel'; import type { EditorHost } from '@blocksuite/block-std'; import type { BlockModel } from '@blocksuite/store'; import { lowerCase, omit } from 'lodash-es'; diff --git a/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/linked-widget.ts b/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/linked-widget.ts index c4788d2a9a..57355227ec 100644 --- a/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/linked-widget.ts +++ b/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/linked-widget.ts @@ -1,5 +1,5 @@ +import { mixpanel } from '@affine/core/mixpanel'; import { WorkspacePropertiesAdapter } from '@affine/core/modules/properties'; -import { mixpanel } from '@affine/core/utils'; import { I18n, i18nTime } from '@affine/i18n'; import type { EditorHost } from '@blocksuite/block-std'; import type { AffineInlineEditor } from '@blocksuite/blocks'; diff --git a/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/root-block.ts b/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/root-block.ts index db6c068ae9..3bc8e4b449 100644 --- a/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/root-block.ts +++ b/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/root-block.ts @@ -2,7 +2,7 @@ import { AIEdgelessRootBlockSpec, AIPageRootBlockSpec, } from '@affine/core/blocksuite/presets/ai'; -import { mixpanel } from '@affine/core/utils'; +import { mixpanel } from '@affine/core/mixpanel'; import type { EdgelessRootBlockSpecType, PageRootBlockSpecType, @@ -42,7 +42,7 @@ function withAffineRootService(Service: typeof RootService) { eventName: T, props: TelemetryEventMap[T] ) => { - mixpanel.track(eventName, props); + mixpanel.track(eventName as string, props as Record); }, }; }; diff --git a/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/spec-patchers.tsx b/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/spec-patchers.tsx index 4013c24e46..f407d3cc08 100644 --- a/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/spec-patchers.tsx +++ b/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/spec-patchers.tsx @@ -7,6 +7,7 @@ import { toReactNode, type useConfirmModal, } from '@affine/component'; +import { mixpanel } from '@affine/core/mixpanel'; import { DocsSearchService } from '@affine/core/modules/docs-search'; import { resolveLinkToDoc } from '@affine/core/modules/navigation'; import type { PeekViewService } from '@affine/core/modules/peek-view'; @@ -18,7 +19,6 @@ import { QuickSearchService, RecentDocsQuickSearchSession, } from '@affine/core/modules/quicksearch'; -import { mixpanel } from '@affine/core/utils'; import { DebugLogger } from '@affine/debug'; import type { BlockSpec, WidgetComponent } from '@blocksuite/block-std'; import { diff --git a/packages/frontend/core/src/components/blocksuite/block-suite-header/menu/index.tsx b/packages/frontend/core/src/components/blocksuite/block-suite-header/menu/index.tsx index b7b633b938..8188140d1e 100644 --- a/packages/frontend/core/src/components/blocksuite/block-suite-header/menu/index.tsx +++ b/packages/frontend/core/src/components/blocksuite/block-suite-header/menu/index.tsx @@ -18,8 +18,8 @@ import { useEnableCloud } from '@affine/core/hooks/affine/use-enable-cloud'; import { useExportPage } from '@affine/core/hooks/affine/use-export-page'; import { useTrashModalHelper } from '@affine/core/hooks/affine/use-trash-modal-helper'; import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks'; +import { mixpanel } from '@affine/core/mixpanel'; import { useDetailPageHeaderResponsive } from '@affine/core/pages/workspace/detail-page/use-header-responsive'; -import { mixpanel } from '@affine/core/utils'; import { WorkspaceFlavour } from '@affine/env/workspace'; import { useI18n } from '@affine/i18n'; import { diff --git a/packages/frontend/core/src/components/blocksuite/block-suite-mode-switch/index.tsx b/packages/frontend/core/src/components/blocksuite/block-suite-mode-switch/index.tsx index 12d0536b92..eddf468e59 100644 --- a/packages/frontend/core/src/components/blocksuite/block-suite-mode-switch/index.tsx +++ b/packages/frontend/core/src/components/blocksuite/block-suite-mode-switch/index.tsx @@ -1,5 +1,6 @@ import { Tooltip } from '@affine/component/ui/tooltip'; import { useBlockSuiteDocMeta } from '@affine/core/hooks/use-block-suite-page-meta'; +import { mixpanel } from '@affine/core/mixpanel'; import { useI18n } from '@affine/i18n'; import { type DocMode, @@ -11,7 +12,7 @@ import type { CSSProperties } from 'react'; import { useCallback, useEffect } from 'react'; import type { DocCollection } from '../../../shared'; -import { mixpanel, toast } from '../../../utils'; +import { toast } from '../../../utils'; import { StyledEditorModeSwitch, StyledKeyboardItem } from './style'; import { EdgelessSwitchItem, PageSwitchItem } from './switch-items'; diff --git a/packages/frontend/core/src/components/page-list/components/new-page-button.tsx b/packages/frontend/core/src/components/page-list/components/new-page-button.tsx index 4c29f966f2..cea17cebdc 100644 --- a/packages/frontend/core/src/components/page-list/components/new-page-button.tsx +++ b/packages/frontend/core/src/components/page-list/components/new-page-button.tsx @@ -1,6 +1,6 @@ import { DropdownButton, Menu } from '@affine/component'; import { BlockCard } from '@affine/component/card/block-card'; -import { mixpanel } from '@affine/core/utils'; +import { mixpanel } from '@affine/core/mixpanel'; import { useI18n } from '@affine/i18n'; import { EdgelessIcon, ImportIcon, PageIcon } from '@blocksuite/icons/rc'; import type { PropsWithChildren } from 'react'; diff --git a/packages/frontend/core/src/components/page-list/docs/page-list-header.tsx b/packages/frontend/core/src/components/page-list/docs/page-list-header.tsx index 5b3cb3f52d..d1d83cf0f3 100644 --- a/packages/frontend/core/src/components/page-list/docs/page-list-header.tsx +++ b/packages/frontend/core/src/components/page-list/docs/page-list-header.tsx @@ -7,9 +7,9 @@ import { } from '@affine/component'; import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks'; import { useNavigateHelper } from '@affine/core/hooks/use-navigate-helper'; +import { mixpanel } from '@affine/core/mixpanel'; import type { Tag } from '@affine/core/modules/tag'; import { TagService } from '@affine/core/modules/tag'; -import { mixpanel } from '@affine/core/utils'; import type { Collection } from '@affine/env/filter'; import { useI18n } from '@affine/i18n'; import { diff --git a/packages/frontend/core/src/components/page-list/operation-cell.tsx b/packages/frontend/core/src/components/page-list/operation-cell.tsx index eb1185f081..7286c95db0 100644 --- a/packages/frontend/core/src/components/page-list/operation-cell.tsx +++ b/packages/frontend/core/src/components/page-list/operation-cell.tsx @@ -10,10 +10,10 @@ import { import { useAppSettingHelper } from '@affine/core/hooks/affine/use-app-setting-helper'; import { useBlockSuiteMetaHelper } from '@affine/core/hooks/affine/use-block-suite-meta-helper'; import { useTrashModalHelper } from '@affine/core/hooks/affine/use-trash-modal-helper'; +import { mixpanel } from '@affine/core/mixpanel'; import { FavoriteService } from '@affine/core/modules/favorite'; import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/properties'; import { WorkbenchService } from '@affine/core/modules/workbench'; -import { mixpanel } from '@affine/core/utils'; import type { Collection, DeleteCollectionInfo } from '@affine/env/filter'; import { useI18n } from '@affine/i18n'; import { diff --git a/packages/frontend/core/src/components/pure/workspace-slider-bar/user-with-workspace-list/index.tsx b/packages/frontend/core/src/components/pure/workspace-slider-bar/user-with-workspace-list/index.tsx index 1a17a1a882..ead2d981de 100644 --- a/packages/frontend/core/src/components/pure/workspace-slider-bar/user-with-workspace-list/index.tsx +++ b/packages/frontend/core/src/components/pure/workspace-slider-bar/user-with-workspace-list/index.tsx @@ -1,6 +1,7 @@ import { Loading } from '@affine/component'; import { Divider } from '@affine/component/ui/divider'; import { MenuItem } from '@affine/component/ui/menu'; +import { mixpanel } from '@affine/core/mixpanel'; import { AuthService } from '@affine/core/modules/cloud'; import { useI18n } from '@affine/i18n'; import { Logo1Icon } from '@blocksuite/icons/rc'; @@ -13,7 +14,6 @@ import { useSetAtom } from 'jotai'; import { Suspense, useCallback } from 'react'; import { authAtom, openCreateWorkspaceModalAtom } from '../../../../atoms'; -import { mixpanel } from '../../../../utils'; import { AddWorkspace } from './add-workspace'; import * as styles from './index.css'; import { UserAccountItem } from './user-account'; diff --git a/packages/frontend/core/src/components/root-app-sidebar/import-page.tsx b/packages/frontend/core/src/components/root-app-sidebar/import-page.tsx index cf7f44a2ca..1441365fb7 100644 --- a/packages/frontend/core/src/components/root-app-sidebar/import-page.tsx +++ b/packages/frontend/core/src/components/root-app-sidebar/import-page.tsx @@ -1,6 +1,6 @@ import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks'; +import { mixpanel } from '@affine/core/mixpanel'; import { TelemetryWorkspaceContextService } from '@affine/core/modules/telemetry/services/telemetry'; -import { mixpanel } from '@affine/core/utils'; import { useI18n } from '@affine/i18n'; import { ImportIcon } from '@blocksuite/icons/rc'; import { useService } from '@toeverything/infra'; diff --git a/packages/frontend/core/src/components/root-app-sidebar/index.tsx b/packages/frontend/core/src/components/root-app-sidebar/index.tsx index af450d4796..c352ea24dc 100644 --- a/packages/frontend/core/src/components/root-app-sidebar/index.tsx +++ b/packages/frontend/core/src/components/root-app-sidebar/index.tsx @@ -1,6 +1,7 @@ import { openSettingModalAtom } from '@affine/core/atoms'; import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks'; import { useNavigateHelper } from '@affine/core/hooks/use-navigate-helper'; +import { mixpanel } from '@affine/core/mixpanel'; import { ExplorerCollections, ExplorerFavorites, @@ -12,7 +13,6 @@ import { ExplorerTags } from '@affine/core/modules/explorer/views/sections/tags' import { CMDKQuickSearchService } from '@affine/core/modules/quicksearch/services/cmdk'; import { TelemetryWorkspaceContextService } from '@affine/core/modules/telemetry/services/telemetry'; import { pathGenerator } from '@affine/core/shared'; -import { mixpanel } from '@affine/core/utils'; import { apis, events } from '@affine/electron-api'; import { useI18n } from '@affine/i18n'; import { FolderIcon, SettingsIcon } from '@blocksuite/icons/rc'; diff --git a/packages/frontend/core/src/components/root-app-sidebar/user-info.tsx b/packages/frontend/core/src/components/root-app-sidebar/user-info.tsx index f5e312a60c..6b3e95b71c 100644 --- a/packages/frontend/core/src/components/root-app-sidebar/user-info.tsx +++ b/packages/frontend/core/src/components/root-app-sidebar/user-info.tsx @@ -14,7 +14,7 @@ import { openSettingModalAtom, openSignOutModalAtom, } from '@affine/core/atoms'; -import { mixpanel } from '@affine/core/utils'; +import { mixpanel } from '@affine/core/mixpanel'; import { useI18n } from '@affine/i18n'; import { AccountIcon, SignOutIcon } from '@blocksuite/icons/rc'; import { useLiveData, useService } from '@toeverything/infra'; diff --git a/packages/frontend/core/src/components/workspace-selector/index.tsx b/packages/frontend/core/src/components/workspace-selector/index.tsx index 156407dfe0..5a728efc8e 100644 --- a/packages/frontend/core/src/components/workspace-selector/index.tsx +++ b/packages/frontend/core/src/components/workspace-selector/index.tsx @@ -1,10 +1,10 @@ import { Menu } from '@affine/component'; +import { mixpanel } from '@affine/core/mixpanel'; import { useService, WorkspacesService } from '@toeverything/infra'; import { useAtom } from 'jotai'; import { useCallback, useEffect } from 'react'; import { openWorkspaceListModalAtom } from '../../atoms'; -import { mixpanel } from '../../utils'; import { UserWithWorkspaceList } from '../pure/workspace-slider-bar/user-with-workspace-list'; import { WorkspaceCard } from '../pure/workspace-slider-bar/workspace-card'; diff --git a/packages/frontend/core/src/components/workspace-upgrade/upgrade.tsx b/packages/frontend/core/src/components/workspace-upgrade/upgrade.tsx index 684ec2660c..c77075d244 100644 --- a/packages/frontend/core/src/components/workspace-upgrade/upgrade.tsx +++ b/packages/frontend/core/src/components/workspace-upgrade/upgrade.tsx @@ -2,12 +2,12 @@ import { Button } from '@affine/component/ui/button'; import { AffineShapeIcon } from '@affine/core/components/page-list'; // TODO(@eyhn): import from page-list temporarily, need to defined common svg icon/images management. import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks'; import { useNavigateHelper } from '@affine/core/hooks/use-navigate-helper'; +import { mixpanel } from '@affine/core/mixpanel'; import { WorkspaceSubPath } from '@affine/core/shared'; import { useI18n } from '@affine/i18n'; import { useLiveData, useService, WorkspaceService } from '@toeverything/infra'; import { useState } from 'react'; -import { mixpanel } from '../../utils'; import * as styles from './upgrade.css'; import { ArrowCircleIcon, HeartBreakIcon } from './upgrade-icon'; diff --git a/packages/frontend/core/src/hooks/affine/use-export-page.ts b/packages/frontend/core/src/hooks/affine/use-export-page.ts index 7ccf21634f..dc35fa3e9c 100644 --- a/packages/frontend/core/src/hooks/affine/use-export-page.ts +++ b/packages/frontend/core/src/hooks/affine/use-export-page.ts @@ -3,7 +3,7 @@ import { pushGlobalLoadingEventAtom, resolveGlobalLoadingEventAtom, } from '@affine/component/global-loading'; -import { mixpanel } from '@affine/core/utils'; +import { mixpanel } from '@affine/core/mixpanel'; import { apis } from '@affine/electron-api'; import { useI18n } from '@affine/i18n'; import type { PageRootService, RootBlockModel } from '@blocksuite/blocks'; diff --git a/packages/frontend/core/src/hooks/affine/use-register-blocksuite-editor-commands.tsx b/packages/frontend/core/src/hooks/affine/use-register-blocksuite-editor-commands.tsx index da2ca067c3..5f1db7d042 100644 --- a/packages/frontend/core/src/hooks/affine/use-register-blocksuite-editor-commands.tsx +++ b/packages/frontend/core/src/hooks/affine/use-register-blocksuite-editor-commands.tsx @@ -4,9 +4,9 @@ import { PreconditionStrategy, registerAffineCommand, } from '@affine/core/commands'; +import { mixpanel } from '@affine/core/mixpanel'; import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/properties'; import { TelemetryWorkspaceContextService } from '@affine/core/modules/telemetry/services/telemetry'; -import { mixpanel } from '@affine/core/utils'; import { WorkspaceFlavour } from '@affine/env/workspace'; import { useI18n } from '@affine/i18n'; import { EdgelessIcon, HistoryIcon, PageIcon } from '@blocksuite/icons/rc'; diff --git a/packages/frontend/core/src/hooks/affine/use-share-url.ts b/packages/frontend/core/src/hooks/affine/use-share-url.ts index b65e093f3b..fd711ea12a 100644 --- a/packages/frontend/core/src/hooks/affine/use-share-url.ts +++ b/packages/frontend/core/src/hooks/affine/use-share-url.ts @@ -1,6 +1,6 @@ import { notify } from '@affine/component'; +import { mixpanel } from '@affine/core/mixpanel'; import { getAffineCloudBaseUrl } from '@affine/core/modules/cloud/services/fetch'; -import { mixpanel } from '@affine/core/utils'; import { useI18n } from '@affine/i18n'; import type { Disposable } from '@blocksuite/global/utils'; import { useCallback, useEffect, useMemo, useState } from 'react'; diff --git a/packages/frontend/core/src/hooks/affine/use-subscription-notify.tsx b/packages/frontend/core/src/hooks/affine/use-subscription-notify.tsx index f9d06c26b1..09bddc38df 100644 --- a/packages/frontend/core/src/hooks/affine/use-subscription-notify.tsx +++ b/packages/frontend/core/src/hooks/affine/use-subscription-notify.tsx @@ -1,5 +1,5 @@ import { useUpgradeNotify } from '@affine/core/components/affine/subscription-landing/notify'; -import { mixpanelTrack } from '@affine/core/utils'; +import { mixpanel } from '@affine/core/mixpanel'; import { SubscriptionPlan, SubscriptionRecurring } from '@affine/graphql'; import { nanoid } from 'nanoid'; import { useCallback, useEffect } from 'react'; @@ -130,7 +130,7 @@ export const useSubscriptionNotifyReader = () => { localStorage.removeItem(localStorageKey); // mixpanel - mixpanelTrack('PlanChangeSucceeded', { + mixpanel.track('PlanChangeSucceeded', { category: recurring, type: plan, control: 'new subscription', diff --git a/packages/frontend/core/src/hooks/use-app-updater.ts b/packages/frontend/core/src/hooks/use-app-updater.ts index 011464115b..858a241223 100644 --- a/packages/frontend/core/src/hooks/use-app-updater.ts +++ b/packages/frontend/core/src/hooks/use-app-updater.ts @@ -7,7 +7,8 @@ import { atomWithObservable, atomWithStorage } from 'jotai/utils'; import { useCallback, useState } from 'react'; import { Observable } from 'rxjs'; -import { mixpanel, popupWindow } from '../utils'; +import { mixpanel } from '../mixpanel'; +import { popupWindow } from '../utils'; import { useAsyncCallback } from './affine-async-hooks'; function rpcToObservable< diff --git a/packages/frontend/core/src/mixpanel/events/index.ts b/packages/frontend/core/src/mixpanel/events/index.ts new file mode 100644 index 0000000000..41a748d09c --- /dev/null +++ b/packages/frontend/core/src/mixpanel/events/index.ts @@ -0,0 +1,23 @@ +import type { PlanChangeStartedEvent } from './plan-change-started'; +import type { PlanChangeSucceededEvent } from './plan-change-succeed'; + +export interface MixpanelEvents { + PlanChangeStarted: PlanChangeStartedEvent; + PlanChangeSucceeded: PlanChangeSucceededEvent; + OAuth: { + provider: string; + }; +} + +export interface GeneralMixpanelEvent { + // location + page?: string | null; + segment?: string | null; + module?: string | null; + control?: string | null; + + // entity + type?: string | null; + category?: string | null; + id?: string | null; +} diff --git a/packages/frontend/core/src/mixpanel/events/plan-change-started.ts b/packages/frontend/core/src/mixpanel/events/plan-change-started.ts new file mode 100644 index 0000000000..cc2e3aec81 --- /dev/null +++ b/packages/frontend/core/src/mixpanel/events/plan-change-started.ts @@ -0,0 +1,16 @@ +import type { SubscriptionPlan, SubscriptionRecurring } from '@affine/graphql'; + +/** + * Before subscription plan changed + */ +export interface PlanChangeStartedEvent { + segment?: 'settings panel'; + module?: 'pricing plan list' | 'billing subscription list'; + control?: + | 'new subscription' // no subscription before + | 'cancel' + | 'paying' // resume: subscribed before + | 'plan cancel action'; + type?: SubscriptionPlan; + category?: SubscriptionRecurring; +} diff --git a/packages/frontend/core/src/mixpanel/plan-change-succeed.ts b/packages/frontend/core/src/mixpanel/events/plan-change-succeed.ts similarity index 80% rename from packages/frontend/core/src/mixpanel/plan-change-succeed.ts rename to packages/frontend/core/src/mixpanel/events/plan-change-succeed.ts index 4487f77d75..3d96022434 100644 --- a/packages/frontend/core/src/mixpanel/plan-change-succeed.ts +++ b/packages/frontend/core/src/mixpanel/events/plan-change-succeed.ts @@ -5,5 +5,5 @@ import type { PlanChangeStartedEvent } from './plan-change-started'; */ export type PlanChangeSucceededEvent = Pick< PlanChangeStartedEvent, - 'control' | 'type' | 'category' + 'control' | 'type' | 'category' | 'segment' >; diff --git a/packages/frontend/core/src/mixpanel/index.ts b/packages/frontend/core/src/mixpanel/index.ts index 07b53a423f..d2bc0f3876 100644 --- a/packages/frontend/core/src/mixpanel/index.ts +++ b/packages/frontend/core/src/mixpanel/index.ts @@ -1,7 +1,88 @@ -import type { PlanChangeStartedEvent } from './plan-change-started'; -import type { PlanChangeSucceededEvent } from './plan-change-succeed'; +import { DebugLogger } from '@affine/debug'; +import type { OverridedMixpanel } from 'mixpanel-browser'; +import mixpanelBrowser from 'mixpanel-browser'; -export interface MixpanelEvents { - PlanChangeStarted: PlanChangeStartedEvent; - PlanChangeSucceeded: PlanChangeSucceededEvent; +import type { GeneralMixpanelEvent, MixpanelEvents } from './events'; + +const logger = new DebugLogger('mixpanel'); + +function createMixpanel() { + let mixpanel; + if (process.env.MIXPANEL_TOKEN) { + mixpanelBrowser.init(process.env.MIXPANEL_TOKEN || '', { + track_pageview: true, + persistence: 'localStorage', + api_host: 'https://telemetry.affine.run', + }); + mixpanel = mixpanelBrowser; + } else { + mixpanel = new Proxy( + function () {} as unknown as OverridedMixpanel, + createProxyHandler() + ); + } + + const wrapped = { + reset() { + mixpanel.reset(); + mixpanel.register({ + appVersion: runtimeConfig.appVersion, + environment: runtimeConfig.appBuildType, + editorVersion: runtimeConfig.editorVersion, + isSelfHosted: Boolean(runtimeConfig.isSelfHosted), + isDesktop: environment.isDesktop, + }); + }, + track< + T extends string, + P extends (T extends keyof MixpanelEvents + ? MixpanelEvents[T] + : Record) & + GeneralMixpanelEvent, + >(event_name: T, properties?: P) { + logger.debug('track', event_name, properties); + mixpanel.track(event_name, properties); + }, + opt_out_tracking() { + mixpanel.opt_out_tracking(); + }, + opt_in_tracking() { + mixpanel.opt_in_tracking(); + }, + has_opted_in_tracking() { + mixpanel.has_opted_in_tracking(); + }, + has_opted_out_tracking() { + mixpanel.has_opted_out_tracking(); + }, + identify(unique_id?: string) { + mixpanel.identify(unique_id); + }, + get people() { + return mixpanel.people; + }, + track_pageview(properties?: { location?: string }) { + logger.debug('track_pageview', properties); + mixpanel.track_pageview(properties); + }, + }; + + wrapped.reset(); + + return wrapped; +} + +export const mixpanel = createMixpanel(); + +function createProxyHandler() { + const handler = { + get: () => { + return new Proxy( + function () {} as unknown as OverridedMixpanel, + createProxyHandler() + ); + }, + apply: () => {}, + } as ProxyHandler; + return handler; } diff --git a/packages/frontend/core/src/mixpanel/mixpanel.d.ts b/packages/frontend/core/src/mixpanel/mixpanel.d.ts new file mode 100644 index 0000000000..0903c12454 --- /dev/null +++ b/packages/frontend/core/src/mixpanel/mixpanel.d.ts @@ -0,0 +1,19 @@ +// eslint-disable-next-line @typescript-eslint/no-unused-vars, unused-imports/no-unused-imports +import * as mixpanel from 'mixpanel-browser'; + +import type { GeneralMixpanelEvent, MixpanelEvents } from './events'; + +declare module 'mixpanel-browser' { + export interface OverridedMixpanel { + track< + T extends string, + P extends (T extends keyof MixpanelEvents + ? MixpanelEvents[T] + : Record) & + GeneralMixpanelEvent, + >( + event_name: T, + properties?: P + ): void; + } +} diff --git a/packages/frontend/core/src/mixpanel/plan-change-started.ts b/packages/frontend/core/src/mixpanel/plan-change-started.ts deleted file mode 100644 index 697c937a1e..0000000000 --- a/packages/frontend/core/src/mixpanel/plan-change-started.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { SubscriptionPlan, SubscriptionRecurring } from '@affine/graphql'; - -/** - * Before subscription plan changed - */ -export interface PlanChangeStartedEvent { - segment: 'settings panel'; - module: 'pricing plan list' | 'billing subscription list'; - control: - | 'new subscription' // no subscription before - | 'cancel' - | 'paying'; // resume: subscribed before - type: SubscriptionPlan; - category: SubscriptionRecurring; -} diff --git a/packages/frontend/core/src/modules/explorer/views/nodes/doc/empty.tsx b/packages/frontend/core/src/modules/explorer/views/nodes/doc/empty.tsx index 914d3d8211..4882004756 100644 --- a/packages/frontend/core/src/modules/explorer/views/nodes/doc/empty.tsx +++ b/packages/frontend/core/src/modules/explorer/views/nodes/doc/empty.tsx @@ -9,7 +9,7 @@ export const Empty = ({ }: { onDrop: (data: DropTargetDropEvent) => void; }) => { - const { dropTargetRef } = useDropTarget( + const { dropTargetRef } = useDropTarget( () => ({ onDrop, }), diff --git a/packages/frontend/core/src/modules/telemetry/services/telemetry.ts b/packages/frontend/core/src/modules/telemetry/services/telemetry.ts index 3496cd05a4..1fca0c7440 100644 --- a/packages/frontend/core/src/modules/telemetry/services/telemetry.ts +++ b/packages/frontend/core/src/modules/telemetry/services/telemetry.ts @@ -1,4 +1,4 @@ -import { mixpanel } from '@affine/core/utils'; +import { mixpanel } from '@affine/core/mixpanel'; import type { QuotaQuery } from '@affine/graphql'; import type { WorkspaceScope } from '@toeverything/infra'; import { @@ -31,20 +31,6 @@ export class TelemetryService extends Service { } onApplicationStart() { - if (process.env.MIXPANEL_TOKEN) { - mixpanel.init(process.env.MIXPANEL_TOKEN || '', { - track_pageview: true, - persistence: 'localStorage', - api_host: 'https://telemetry.affine.run', - }); - mixpanel.register({ - appVersion: runtimeConfig.appVersion, - environment: runtimeConfig.appBuildType, - editorVersion: runtimeConfig.editorVersion, - isSelfHosted: Boolean(runtimeConfig.isSelfHosted), - isDesktop: environment.isDesktop, - }); - } const account = this.auth.session.account$.value; this.updateIdentity(account); } diff --git a/packages/frontend/core/src/modules/workbench/services/workbench.ts b/packages/frontend/core/src/modules/workbench/services/workbench.ts index d867237984..dad8ba3f68 100644 --- a/packages/frontend/core/src/modules/workbench/services/workbench.ts +++ b/packages/frontend/core/src/modules/workbench/services/workbench.ts @@ -1,4 +1,4 @@ -import { mixpanel } from '@affine/core/utils'; +import { mixpanel } from '@affine/core/mixpanel'; import { createEvent, Service } from '@toeverything/infra'; import { combineLatest, distinctUntilChanged, map, skip } from 'rxjs'; diff --git a/packages/frontend/core/src/pages/subscribe.tsx b/packages/frontend/core/src/pages/subscribe.tsx index 9ee125a41d..41dd662056 100644 --- a/packages/frontend/core/src/pages/subscribe.tsx +++ b/packages/frontend/core/src/pages/subscribe.tsx @@ -8,8 +8,8 @@ import { EMPTY, mergeMap, switchMap } from 'rxjs'; import { generateSubscriptionCallbackLink } from '../hooks/affine/use-subscription-notify'; import { RouteLogic, useNavigateHelper } from '../hooks/use-navigate-helper'; +import { mixpanel } from '../mixpanel'; import { AuthService, SubscriptionService } from '../modules/cloud'; -import { mixpanel } from '../utils'; import { container } from './subscribe.css'; export const Component = () => { diff --git a/packages/frontend/core/src/pages/workspace/all-page/all-page-header.tsx b/packages/frontend/core/src/pages/workspace/all-page/all-page-header.tsx index e7ebdc0a2b..0dcc3e776b 100644 --- a/packages/frontend/core/src/pages/workspace/all-page/all-page-header.tsx +++ b/packages/frontend/core/src/pages/workspace/all-page/all-page-header.tsx @@ -7,7 +7,7 @@ import { import { Header } from '@affine/core/components/pure/header'; import { WorkspaceModeFilterTab } from '@affine/core/components/pure/workspace-mode-filter-tab'; import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks'; -import { mixpanel } from '@affine/core/utils'; +import { mixpanel } from '@affine/core/mixpanel'; import type { Filter } from '@affine/env/filter'; import { PlusIcon } from '@blocksuite/icons/rc'; import { useService, WorkspaceService } from '@toeverything/infra'; diff --git a/packages/frontend/core/src/telemetry.tsx b/packages/frontend/core/src/telemetry.tsx index c949920001..aeceddbb2e 100644 --- a/packages/frontend/core/src/telemetry.tsx +++ b/packages/frontend/core/src/telemetry.tsx @@ -2,7 +2,7 @@ import { appSettingAtom } from '@toeverything/infra'; import { useAtomValue } from 'jotai/react'; import { useLayoutEffect } from 'react'; -import { mixpanel } from './utils/mixpanel'; +import { mixpanel } from './mixpanel'; export function Telemetry() { const settings = useAtomValue(appSettingAtom); diff --git a/packages/frontend/core/src/utils/index.ts b/packages/frontend/core/src/utils/index.ts index 7505a714a2..eaf45a6fa2 100644 --- a/packages/frontend/core/src/utils/index.ts +++ b/packages/frontend/core/src/utils/index.ts @@ -1,6 +1,5 @@ export * from './create-emotion-cache'; export * from './fractional-indexing'; -export * from './mixpanel'; export * from './popup'; export * from './string2color'; export * from './toast'; diff --git a/packages/frontend/core/src/utils/mixpanel.ts b/packages/frontend/core/src/utils/mixpanel.ts deleted file mode 100644 index 7e0bf980e7..0000000000 --- a/packages/frontend/core/src/utils/mixpanel.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { DebugLogger } from '@affine/debug'; -import type { OverridedMixpanel } from 'mixpanel-browser'; -import mixpanelBrowser from 'mixpanel-browser'; - -import type { MixpanelEvents } from '../mixpanel'; - -const logger = new DebugLogger('affine:mixpanel'); - -export const mixpanel = process.env.MIXPANEL_TOKEN - ? mixpanelBrowser - : new Proxy( - function () {} as unknown as OverridedMixpanel, - createProxyHandler() - ); - -function createProxyHandler(property?: string | symbol) { - const handler = { - get: (_target, childProperty) => { - const path = property - ? String(property) + '.' + String(childProperty) - : String(childProperty); - return new Proxy( - function () {} as unknown as OverridedMixpanel, - createProxyHandler(path) - ); - }, - apply: (_target, _thisArg, args) => { - logger.debug( - `mixpanel.${property ? String(property) : 'mixpanel'}`, - ...args - ); - }, - } as ProxyHandler; - return handler; -} - -export function mixpanelTrack( - event: T, - properties?: MixpanelEvents[T] -) { - return mixpanel.track(event, properties); -} diff --git a/tests/kit/utils/page-logic.ts b/tests/kit/utils/page-logic.ts index d32cf90117..6ff38f9fbe 100644 --- a/tests/kit/utils/page-logic.ts +++ b/tests/kit/utils/page-logic.ts @@ -10,7 +10,7 @@ export async function waitForEditorLoad(page: Page) { export async function waitForAllPagesLoad(page: Page) { // if filters tag is rendered, we believe all_pages is ready await page.waitForSelector('[data-testid="create-first-filter"]', { - timeout: 1000, + timeout: 20000, }); }