@@ -155,24 +162,8 @@ export const SettingSidebar = ({
})}
key={key}
title={title}
- onClick={() => {
- if (key === 'billing') {
- mixpanel.track('BillingViewed', {
- // page:
- segment: 'settings panel',
- module: 'settings menu',
- control: 'menu item',
- });
- } else if (key === 'plans') {
- mixpanel.track('PlansViewed', {
- // page:
- segment: 'settings panel',
- module: 'settings menu',
- control: 'menu item',
- });
- }
- onTabChange(key, null);
- }}
+ data-event-arg={key}
+ onClick={gotoTab}
data-testid={testId}
>
{icon({ className: 'icon' })}
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 8a42d8045..a97ed00ad 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,7 +21,7 @@ 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 { track } from '@affine/core/mixpanel';
import { WorkspacePermissionService } from '@affine/core/modules/permissions';
import { WorkspaceQuotaService } from '@affine/core/modules/quota';
import { WorkspaceFlavour } from '@affine/env/workspace';
@@ -146,11 +146,8 @@ export const CloudWorkspaceMembersPanel = () => {
activeTab: 'plans',
scrollAnchor: 'cloudPricingPlan',
});
- mixpanel.track('PlansViewed', {
- // page:
- segment: 'settings panel',
- module: 'workspace setting',
- control: 'invite member',
+ track.$.settingsPanel.workspace.viewPlans({
+ control: 'inviteMember',
});
}, [setSettingModalAtom]);
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 5e7b228a0..1be710270 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,7 +4,7 @@ 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 { track } from '@affine/core/mixpanel';
import { ServerConfigService } from '@affine/core/modules/cloud';
import { ShareService } from '@affine/core/modules/share-doc';
import { WorkspaceFlavour } from '@affine/env/workspace';
@@ -106,11 +106,8 @@ export const AffineSharePage = (props: ShareMenuProps) => {
await shareService.share.enableShare(
mode === 'edgeless' ? PublicPageMode.Edgeless : PublicPageMode.Page
);
- mixpanel.track('ShareCreated', {
- segment: 'sharing panel',
- module: 'public share',
- control: 'share panel',
- type: mode,
+ track.$.header.share.createShareLink({
+ mode,
});
notify.success({
title:
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 d467dc8d7..153cc2f02 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,4 +1,4 @@
-import { mixpanel } from '@affine/core/mixpanel';
+import { track } from '@affine/core/mixpanel';
import { CloseIcon, DownloadIcon } from '@blocksuite/icons/rc';
import clsx from 'clsx';
import { useCallback, useState } from 'react';
@@ -21,9 +21,7 @@ export function AppDownloadButton({
// TODO(@JimmFly): unify this type of literal value.
const handleClick = useCallback(() => {
- mixpanel.track('Button', {
- resolve: 'GoToDownloadAppPage',
- });
+ track.$.navigationPanel.bottomButtons.downloadApp();
const url = `https://affine.pro/download?channel=stable`;
open(url, '_blank');
}, []);
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 73efc8cdd..9a3bc0690 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/mixpanel';
+import { track } from '@affine/core/mixpanel';
import {
getBaseUrl,
type getCopilotHistoriesQuery,
@@ -470,10 +470,7 @@ Could you make a new website based on these notes and send back just the html fi
activeTab: 'billing',
open: true,
});
- mixpanel.track('PlansViewed', {
- segment: 'payment wall',
- category: 'payment wall ai action count',
- });
+ track.$.paywall.aiAction.viewPlans();
});
AIProvider.slots.requestLogin.on(() => {
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 60b74b0ad..ec56834b1 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/mixpanel';
+import { mixpanel, track } from '@affine/core/mixpanel';
import type { EditorHost } from '@blocksuite/block-std';
import type { BlockModel } from '@blocksuite/store';
import { lowerCase, omit } from 'lodash-es';
@@ -13,7 +13,7 @@ type AIActionEventName =
| 'AI result accepted';
type AIActionEventProperties = {
- page: 'doc-editor' | 'whiteboard-editor';
+ page: 'doc' | 'edgeless';
segment:
| 'AI action panel'
| 'right side bar'
@@ -73,9 +73,7 @@ const trackAction = ({
};
const inferPageMode = (host: EditorHost) => {
- return host.querySelector('affine-page-root')
- ? 'doc-editor'
- : 'whiteboard-editor';
+ return host.querySelector('affine-page-root') ? 'doc' : 'edgeless';
};
const defaultActionOptions = [
@@ -253,14 +251,12 @@ const toTrackedOptions = (
export function setupTracker() {
AIProvider.slots.requestUpgradePlan.on(() => {
- mixpanel.track('AI', {
- action: 'requestUpgradePlan',
- });
+ track.$.paywall.aiAction.viewPlans();
});
AIProvider.slots.requestLogin.on(() => {
- mixpanel.track('AI', {
- action: 'requestLogin',
+ track.$.$.auth.signIn({
+ control: 'aiAction',
});
});
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 8c659c228..0f030a301 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,4 +1,4 @@
-import { mixpanel } from '@affine/core/mixpanel';
+import { track } from '@affine/core/mixpanel';
import { WorkspacePropertiesAdapter } from '@affine/core/modules/properties';
import { I18n, i18nTime } from '@affine/i18n';
import type { EditorHost } from '@blocksuite/block-std';
@@ -75,12 +75,7 @@ export function createLinkedWidgetConfig(framework: FrameworkProvider) {
inlineEditor,
docId: doc.id,
});
- mixpanel.track('LinkedDocCreated', {
- control: 'linked doc',
- module: 'inline @',
- type: 'doc',
- other: 'existing doc',
- });
+ track.doc.editor.atMenu.linkDoc();
},
})),
maxDisplay: MAX_DOCS,
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 b8dadca99..ede3febe5 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,7 +7,7 @@ import {
toReactNode,
type useConfirmModal,
} from '@affine/component';
-import { mixpanel } from '@affine/core/mixpanel';
+import { track } 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';
@@ -465,30 +465,11 @@ export function patchQuickSearchService(
pageId: linkedDoc.id,
},
]);
- const isEdgeless =
- rootComponent instanceof EdgelessRootBlockComponent;
if (result.isNewDoc) {
- mixpanel.track('DocCreated', {
- control: 'linked doc',
- module: 'slash commands',
- type: 'linked doc',
- category: 'doc',
- page: isEdgeless ? 'whiteboard editor' : 'doc editor',
- });
- mixpanel.track('LinkedDocCreated', {
- control: 'new doc',
- module: 'slash commands',
- type: 'doc',
- page: isEdgeless ? 'whiteboard editor' : 'doc editor',
- });
- } else {
- mixpanel.track('LinkedDocCreated', {
- control: 'linked doc',
- module: 'slash commands',
- type: 'doc',
- page: isEdgeless ? 'whiteboard editor' : 'doc editor',
- });
+ track.doc.editor.slashMenu.createDoc({ control: 'linkDoc' });
+ track.doc.editor.slashMenu.linkDoc({ control: 'createDoc' });
}
+ track.doc.editor.slashMenu.linkDoc({ control: 'linkDoc' });
} else if ('userInput' in result) {
const embedOptions = service.getEmbedBlockOptions(
result.userInput
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 1a84e8c26..d37b8ab81 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,7 +18,7 @@ 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 { track } from '@affine/core/mixpanel';
import { WorkbenchService } from '@affine/core/modules/workbench';
import { ViewService } from '@affine/core/modules/workbench/services/view';
import { useDetailPageHeaderResponsive } from '@affine/core/pages/workspace/detail-page/use-header-responsive';
@@ -157,36 +157,23 @@ export const PageHeaderMenuButton = ({
const handleDuplicate = useCallback(() => {
duplicate(pageId);
- mixpanel.track('DocCreated', {
- segment: 'editor header',
- page: doc.mode$.value === 'page' ? 'doc editor' : 'edgeless editor',
- module: 'header menu',
- control: 'copy doc',
- type: 'doc duplicate',
- category: 'doc',
+ track.$.header.actions.createDoc({
+ control: 'duplicate',
});
- }, [doc.mode$.value, duplicate, pageId]);
+ }, [duplicate, pageId]);
const onImportFile = useAsyncCallback(async () => {
const options = await importFile();
if (options.isWorkspaceFile) {
- mixpanel.track('WorkspaceCreated', {
- segment: 'editor header',
- page: doc.mode$.value === 'page' ? 'doc editor' : 'edgeless editor',
- module: 'header menu',
- control: 'import button',
- type: 'imported workspace',
+ track.$.header.actions.createWorkspace({
+ control: 'import',
});
} else {
- mixpanel.track('DocCreated', {
- segment: 'editor header',
- page: doc.mode$.value === 'page' ? 'doc editor' : 'edgeless editor',
- module: 'header menu',
- control: 'import button',
- type: 'imported doc',
+ track.$.header.actions.createDoc({
+ control: 'import',
});
}
- }, [doc.mode$.value, importFile]);
+ }, [importFile]);
const showResponsiveMenu = hideShare;
const ResponsiveMenuItems = (
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 ed415112f..f6b88222a 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,6 +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 { track } from '@affine/core/mixpanel';
import { useI18n } from '@affine/i18n';
import {
type DocMode,
@@ -62,8 +62,8 @@ export const EditorModeSwitch = ({
}, [currentMode, isPublic, doc, pageId, t, trash]);
const onSwitchToPageMode = useCallback(() => {
- mixpanel.track('Button', {
- resolve: 'SwitchToPageMode',
+ track.$.header.actions.switchPageMode({
+ mode: 'page',
});
if (currentMode === 'page' || isPublic) {
return;
@@ -73,8 +73,8 @@ export const EditorModeSwitch = ({
}, [currentMode, isPublic, doc, t]);
const onSwitchToEdgelessMode = useCallback(() => {
- mixpanel.track('Button', {
- resolve: 'SwitchToEdgelessMode',
+ track.$.header.actions.switchPageMode({
+ mode: 'edgeless',
});
if (currentMode === 'edgeless' || isPublic) {
return;
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 cea17cebd..d2ca4d548 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/mixpanel';
+import { track } from '@affine/core/mixpanel';
import { useI18n } from '@affine/i18n';
import { EdgelessIcon, ImportIcon, PageIcon } from '@blocksuite/icons/rc';
import type { PropsWithChildren } from 'react';
@@ -70,26 +70,14 @@ export const NewPageButton = ({
const handleCreateNewPage = useCallback(() => {
createNewPage();
setOpen(false);
- mixpanel.track('DocCreated', {
- page: 'doc library',
- segment: 'all doc',
- module: 'doc list header',
- control: 'new doc button',
- type: 'doc',
- category: 'page',
- });
+ track.allDocs.header.actions.createDoc();
}, [createNewPage]);
const handleCreateNewEdgeless = useCallback(() => {
createNewEdgeless();
setOpen(false);
- mixpanel.track('DocCreated', {
- page: 'doc library',
- segment: 'all doc',
- module: 'doc list header',
- control: 'new whiteboard button',
- type: 'doc',
- category: 'whiteboard',
+ track.allDocs.header.actions.createDoc({
+ mode: 'edgeless',
});
}, [createNewEdgeless]);
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 8cd3dd901..dea28f58d 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,7 +7,7 @@ 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 { track } from '@affine/core/mixpanel';
import type { Tag } from '@affine/core/modules/tag';
import { TagService } from '@affine/core/modules/tag';
import type { Collection } from '@affine/env/filter';
@@ -49,21 +49,12 @@ export const PageListHeader = () => {
const onImportFile = useAsyncCallback(async () => {
const options = await importFile();
if (options.isWorkspaceFile) {
- mixpanel.track('WorkspaceCreated', {
- page: 'doc library',
- segment: 'all doc',
- module: 'doc list header',
- control: 'import button',
- type: 'imported workspace',
+ track.allDocs.header.actions.createWorkspace({
+ control: 'import',
});
} else {
- mixpanel.track('DocCreated', {
- page: 'doc library',
- segment: 'all doc',
- module: 'doc list header',
- control: 'import button',
- type: 'imported doc',
- // category
+ track.allDocs.header.actions.createDoc({
+ control: 'import',
});
}
}, [importFile]);
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 d07d51c91..c853c3a48 100644
--- a/packages/frontend/core/src/components/page-list/operation-cell.tsx
+++ b/packages/frontend/core/src/components/page-list/operation-cell.tsx
@@ -9,7 +9,7 @@ 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 { track } 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';
@@ -115,13 +115,8 @@ export const PageOperationCell = ({
const onDuplicate = useCallback(() => {
duplicate(page.id, false);
- mixpanel.track('DocCreated', {
- segment: 'all doc',
- module: 'doc item menu',
- control: 'copy doc',
- type: 'doc duplicate',
- category: 'doc',
- page: 'doc library',
+ track.allDocs.list.docMenu.createDoc({
+ control: 'duplicate',
});
}, [duplicate, page.id]);
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 ead2d981d..5733fe159 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,7 +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 { track } from '@affine/core/mixpanel';
import { AuthService } from '@affine/core/modules/cloud';
import { useI18n } from '@affine/i18n';
import { Logo1Icon } from '@blocksuite/icons/rc';
@@ -25,9 +25,7 @@ export const SignInItem = () => {
const t = useI18n();
const onClickSignIn = useCallback(() => {
- mixpanel.track('Button', {
- resolve: 'SignIn',
- });
+ track.$.navigationPanel.workspaceList.signIn();
setOpen(state => ({
...state,
openModal: true,
@@ -92,9 +90,7 @@ const UserWithWorkspaceListInner = ({
if (!isAuthenticated && !runtimeConfig.allowLocalWorkspace) {
return openSignInModal();
}
- mixpanel.track('Button', {
- resolve: 'NewWorkspace',
- });
+ track.$.navigationPanel.workspaceList.createWorkspace();
setOpenCreateWorkspaceModal('new');
onEventEnd?.();
}, [
@@ -104,9 +100,10 @@ const UserWithWorkspaceListInner = ({
setOpenCreateWorkspaceModal,
]);
+ track.$.navigationPanel.workspaceList.createWorkspace();
const onAddWorkspace = useCallback(() => {
- mixpanel.track('Button', {
- resolve: 'AddWorkspace',
+ track.$.navigationPanel.workspaceList.createWorkspace({
+ control: 'import',
});
setOpenCreateWorkspaceModal('add');
onEventEnd?.();
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 3b1bb22e8..95a3f1e3c 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,5 +1,5 @@
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
-import { mixpanel } from '@affine/core/mixpanel';
+import { track } from '@affine/core/mixpanel';
import { useI18n } from '@affine/i18n';
import { ImportIcon } from '@blocksuite/icons/rc';
@@ -13,22 +13,11 @@ const ImportPage = ({ docCollection }: { docCollection: DocCollection }) => {
const onImportFile = useAsyncCallback(async () => {
const options = await importFile();
- if (options.isWorkspaceFile) {
- mixpanel.track('WorkspaceCreated', {
- segment: 'navigation panel',
- module: 'doc list header',
- control: 'import button',
- type: 'imported workspace',
- });
- } else {
- mixpanel.track('DocCreated', {
- segment: 'navigation panel',
- module: 'doc list header',
- control: 'import button',
- type: 'imported doc',
- // category
- });
- }
+ track.$.navigationPanel.workspaceList[
+ options.isWorkspaceFile ? 'createWorkspace' : 'createDoc'
+ ]({
+ control: 'import',
+ });
}, [importFile]);
return (
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 5c740525c..15ddc3e6f 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,6 @@
import { openSettingModalAtom } from '@affine/core/atoms';
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
-import { mixpanel } from '@affine/core/mixpanel';
+import { track } from '@affine/core/mixpanel';
import {
ExplorerCollections,
ExplorerFavorites,
@@ -91,21 +91,14 @@ export const RootAppSidebar = (): ReactElement => {
async (e?: MouseEvent) => {
const page = pageHelper.createPage('page', false);
page.load();
- mixpanel.track('DocCreated', {
- segment: 'navigation panel',
- module: 'bottom button',
- control: 'new doc button',
- category: 'page',
- type: 'doc',
- });
+ track.$.navigationPanel.$.createDoc();
+
workbench.openDoc(page.id, {
at: e?.ctrlKey || e?.metaKey ? 'new-tab' : 'active',
});
},
[pageHelper, workbench]
);
-
- // Listen to the "New Page" action from the menu
useEffect(() => {
if (environment.isDesktop) {
return events?.applicationMenu.onNewPageAction(() => onClickNewPage());
@@ -120,12 +113,7 @@ export const RootAppSidebar = (): ReactElement => {
activeTab: 'appearance',
open: true,
});
- mixpanel.track('SettingsViewed', {
- // page:
- segment: 'navigation panel',
- module: 'general list',
- control: 'settings button',
- });
+ track.$.navigationPanel.$.openSettings();
}, [setOpenSettingModalAtom]);
const sidebarOpen = useAtomValue(appSidebarOpenAtom);
@@ -153,7 +141,7 @@ export const RootAppSidebar = (): ReactElement => {
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 fdf20e6d1..70410c79e 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/mixpanel';
+import { track } from '@affine/core/mixpanel';
import { useI18n } from '@affine/i18n';
import { AccountIcon, SignOutIcon } from '@blocksuite/icons/rc';
import { useLiveData, useService } from '@toeverything/infra';
@@ -83,12 +83,7 @@ const AccountMenu = () => {
const setOpenSignOutModalAtom = useSetAtom(openSignOutModalAtom);
const onOpenAccountSetting = useCallback(() => {
- mixpanel.track('AccountSettingsViewed', {
- // page:
- segment: 'navigation panel',
- module: 'profile and badge',
- control: 'profile and email',
- });
+ track.$.navigationPanel.profileAndBadge.openSettings({ to: 'account' });
setSettingModalAtom(prev => ({
...prev,
open: true,
diff --git a/packages/frontend/core/src/components/workspace-selector/index.tsx b/packages/frontend/core/src/components/workspace-selector/index.tsx
index 5a728efc8..939c71b0d 100644
--- a/packages/frontend/core/src/components/workspace-selector/index.tsx
+++ b/packages/frontend/core/src/components/workspace-selector/index.tsx
@@ -1,5 +1,5 @@
import { Menu } from '@affine/component';
-import { mixpanel } from '@affine/core/mixpanel';
+import { track } from '@affine/core/mixpanel';
import { useService, WorkspacesService } from '@toeverything/infra';
import { useAtom } from 'jotai';
import { useCallback, useEffect } from 'react';
@@ -16,9 +16,7 @@ export const WorkspaceSelector = () => {
setOpenUserWorkspaceList(false);
}, [setOpenUserWorkspaceList]);
const openUserWorkspaceList = useCallback(() => {
- mixpanel.track('Button', {
- resolve: 'OpenWorkspaceList',
- });
+ track.$.navigationPanel.workspaceList.open();
setOpenUserWorkspaceList(true);
}, [setOpenUserWorkspaceList]);
diff --git a/packages/frontend/core/src/components/workspace-upgrade/upgrade.tsx b/packages/frontend/core/src/components/workspace-upgrade/upgrade.tsx
index 24c36ced7..f05946fde 100644
--- a/packages/frontend/core/src/components/workspace-upgrade/upgrade.tsx
+++ b/packages/frontend/core/src/components/workspace-upgrade/upgrade.tsx
@@ -2,7 +2,7 @@ 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 { track } from '@affine/core/mixpanel';
import { WorkspaceSubPath } from '@affine/core/shared';
import { useI18n } from '@affine/i18n';
import { useLiveData, useService, WorkspaceService } from '@toeverything/infra';
@@ -26,9 +26,7 @@ export const WorkspaceUpgrade = function WorkspaceUpgrade() {
return;
}
- mixpanel.track('Button', {
- resolve: 'UpgradeWorkspace',
- });
+ track.workspace.$.$.upgradeWorkspace();
try {
const newWorkspace = await currentWorkspace.upgrade.upgrade();
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 dc35fa3e9..1f11173c1 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/mixpanel';
+import { track } from '@affine/core/mixpanel';
import { apis } from '@affine/electron-api';
import { useI18n } from '@affine/i18n';
import type { PageRootService, RootBlockModel } from '@blocksuite/blocks';
@@ -26,10 +26,8 @@ async function exportHandler({ page, type }: ExportHandlerOptions) {
if (editorRoot) {
pageService = editorRoot.spec.getService
('affine:page');
}
- mixpanel.track('ShareCreated', {
+ track.$.header.share.export({
type,
- segment: 'sharing panel',
- module: 'export share',
});
switch (type) {
case 'html':
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 0a9ed35e4..9d0b36a06 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,7 +4,7 @@ import {
PreconditionStrategy,
registerAffineCommand,
} from '@affine/core/commands';
-import { mixpanel } from '@affine/core/mixpanel';
+import { track } from '@affine/core/mixpanel';
import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/properties';
import { WorkspaceFlavour } from '@affine/env/workspace';
import { useI18n } from '@affine/i18n';
@@ -161,10 +161,8 @@ export function useRegisterBlocksuiteEditorCommands() {
label: t['com.affine.header.option.duplicate'](),
run() {
duplicate(docId);
- mixpanel.track('DocCreated', {
- control: 'cmdk',
- type: 'doc duplicate',
- category: 'doc',
+ track.$.cmdk.$.createDoc({
+ control: 'duplicate',
});
},
})
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 fd711ea12..affec8cca 100644
--- a/packages/frontend/core/src/hooks/affine/use-share-url.ts
+++ b/packages/frontend/core/src/hooks/affine/use-share-url.ts
@@ -1,5 +1,5 @@
import { notify } from '@affine/component';
-import { mixpanel } from '@affine/core/mixpanel';
+import { track } from '@affine/core/mixpanel';
import { getAffineCloudBaseUrl } from '@affine/core/modules/cloud/services/fetch';
import { useI18n } from '@affine/i18n';
import type { Disposable } from '@blocksuite/global/utils';
@@ -68,9 +68,8 @@ export const useSharingUrl = ({
.catch(err => {
console.error(err);
});
- mixpanel.track('ShareLinkCopied', {
- module: urlType === 'share' ? 'public share' : 'private share',
- type: 'link',
+ track.$.header.share.copyShareLink({
+ type: urlType === 'share' ? 'public' : 'private',
});
} else {
notify.error({
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 09bddc38d..07dde9932 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 { mixpanel } from '@affine/core/mixpanel';
+import { track } from '@affine/core/mixpanel';
import { SubscriptionPlan, SubscriptionRecurring } from '@affine/graphql';
import { nanoid } from 'nanoid';
import { useCallback, useEffect } from 'react';
@@ -129,11 +129,9 @@ export const useSubscriptionNotifyReader = () => {
upgradeNotify(link);
localStorage.removeItem(localStorageKey);
- // mixpanel
- mixpanel.track('PlanChangeSucceeded', {
- category: recurring,
- type: plan,
- control: 'new subscription',
+ track.$.$.$.checkout({
+ plan,
+ recurring,
});
} catch (err) {
console.error('Failed to parse subscription callback link', err);
diff --git a/packages/frontend/core/src/hooks/use-app-updater.ts b/packages/frontend/core/src/hooks/use-app-updater.ts
index 858a24122..89a0cf5a9 100644
--- a/packages/frontend/core/src/hooks/use-app-updater.ts
+++ b/packages/frontend/core/src/hooks/use-app-updater.ts
@@ -7,7 +7,7 @@ import { atomWithObservable, atomWithStorage } from 'jotai/utils';
import { useCallback, useState } from 'react';
import { Observable } from 'rxjs';
-import { mixpanel } from '../mixpanel';
+import { track } from '../mixpanel';
import { popupWindow } from '../utils';
import { useAsyncCallback } from './affine-async-hooks';
@@ -122,9 +122,7 @@ export const useAppUpdater = () => {
);
const quitAndInstall = useCallback(() => {
- mixpanel.track('Button', {
- resolve: 'QuitAndInstall',
- });
+ track.$.navigationPanel.bottomButtons.quitAndInstall();
if (updateReady) {
setAppQuitting(true);
apis?.updater.quitAndInstall().catch(err => {
@@ -135,9 +133,7 @@ export const useAppUpdater = () => {
}, [updateReady]);
const checkForUpdates = useCallback(async () => {
- mixpanel.track('Button', {
- resolve: 'CheckForUpdates',
- });
+ track.$.settingsPanel.about.checkUpdates();
if (checkingForUpdates) {
return;
}
@@ -154,9 +150,7 @@ export const useAppUpdater = () => {
}, [checkingForUpdates, setCheckingForUpdates]);
const downloadUpdate = useCallback(() => {
- mixpanel.track('Button', {
- resolve: 'DownloadUpdate',
- });
+ track.$.settingsPanel.about.downloadUpdate();
apis?.updater.downloadUpdate().catch(err => {
console.error('Error downloading update:', err);
});
@@ -164,8 +158,8 @@ export const useAppUpdater = () => {
const toggleAutoDownload = useCallback(
(enable: boolean) => {
- mixpanel.track('Button', {
- resolve: 'ToggleAutoDownload',
+ track.$.settingsPanel.about.changeAppSetting({
+ key: 'autoDownload',
value: enable,
});
setSetting({
@@ -177,8 +171,8 @@ export const useAppUpdater = () => {
const toggleAutoCheck = useCallback(
(enable: boolean) => {
- mixpanel.track('Button', {
- resolve: 'ToggleAutoCheck',
+ track.$.settingsPanel.about.changeAppSetting({
+ key: 'autoCheckUpdates',
value: enable,
});
setSetting({
@@ -189,17 +183,13 @@ export const useAppUpdater = () => {
);
const openChangelog = useAsyncCallback(async () => {
- mixpanel.track('Button', {
- resolve: 'OpenChangelog',
- });
+ track.$.navigationPanel.bottomButtons.openChangelog();
popupWindow(runtimeConfig.changelogUrl);
await setChangelogUnread(true);
}, [setChangelogUnread]);
const dismissChangelog = useAsyncCallback(async () => {
- mixpanel.track('Button', {
- resolve: 'DismissChangelog',
- });
+ track.$.navigationPanel.bottomButtons.dismissChangelog();
await setChangelogUnread(true);
}, [setChangelogUnread]);
diff --git a/packages/frontend/core/src/mixpanel/auto.ts b/packages/frontend/core/src/mixpanel/auto.ts
index ea6331333..24894f543 100644
--- a/packages/frontend/core/src/mixpanel/auto.ts
+++ b/packages/frontend/core/src/mixpanel/auto.ts
@@ -15,7 +15,7 @@ export function makeTracker(trackFn: TrackFn): CallableEventsChain {
get(target, prop) {
if (
typeof prop !== 'string' ||
- prop === '$$typeof' /* webpack hot load reading this prop */
+ prop === '$$typeof' /* webpack hot-reload reads this prop */
) {
return undefined;
}
@@ -55,7 +55,12 @@ export function makeTracker(trackFn: TrackFn): CallableEventsChain {
* @example
*
* ```html
- *
+ *