From 0165abab3e10c88e824b32a7f221ad5b63bb3210 Mon Sep 17 00:00:00 2001 From: Lakhan Baheti <94619783+1akhanBaheti@users.noreply.github.com> Date: Mon, 5 Feb 2024 13:19:07 +0530 Subject: [PATCH] chore: posthog events improved (#3554) * chore: events naming convention changed * chore: track element added for project related events * chore: track element added for cycle related events * chore: track element added for module related events * chore: issue related events updated * refactor: event tracker store * refactor: event-tracker store * fix: posthog changes --------- Co-authored-by: sriram veeraghanta --- .../actions/project-actions.tsx | 9 +- .../command-palette/command-modal.tsx | 8 +- .../command-palette/command-palette.tsx | 7 +- web/components/cycles/cycles-board-card.tsx | 9 +- web/components/cycles/cycles-list-item.tsx | 9 +- web/components/cycles/delete-modal.tsx | 16 +- web/components/cycles/modal.tsx | 17 +- web/components/cycles/sidebar.tsx | 6 +- .../dashboard/project-empty-state.tsx | 11 +- .../dashboard/widgets/recent-projects.tsx | 4 +- web/components/headers/cycle-issues.tsx | 5 +- web/components/headers/cycles.tsx | 6 +- web/components/headers/module-issues.tsx | 5 +- web/components/headers/modules-list.tsx | 8 +- web/components/headers/project-issues.tsx | 15 +- .../headers/project-view-issues.tsx | 3 +- web/components/headers/projects.tsx | 10 +- web/components/inbox/inbox-issue-actions.tsx | 36 ++-- .../inbox/modals/create-issue-modal.tsx | 35 ++-- .../integration/jira/give-details.tsx | 10 +- web/components/issues/attachment/root.tsx | 33 +++- .../issues/issue-detail/inbox/root.tsx | 36 +++- web/components/issues/issue-detail/root.tsx | 116 ++++++++++++- .../calendar/quick-add-issue-form.tsx | 16 +- .../issue-layouts/empty-states/cycle.tsx | 6 +- .../empty-states/global-view.tsx | 8 +- .../issue-layouts/empty-states/module.tsx | 6 +- .../empty-states/project-issues.tsx | 10 +- .../empty-states/project-view.tsx | 10 +- .../gantt/quick-add-issue-form.tsx | 16 +- .../issue-layouts/kanban/base-kanban-root.tsx | 8 +- .../issues/issue-layouts/kanban/block.tsx | 5 +- .../kanban/headers/group-by-card.tsx | 26 ++- .../kanban/quick-add-issue-form.tsx | 16 +- .../issues/issue-layouts/list/block.tsx | 7 +- .../issues/issue-layouts/list/blocks-list.tsx | 2 +- .../list/headers/group-by-card.tsx | 23 ++- .../list/quick-add-issue-form.tsx | 18 +- .../properties/all-properties.tsx | 98 +++++++++-- .../quick-action-dropdowns/all-issue.tsx | 6 + .../quick-action-dropdowns/archived-issue.tsx | 14 +- .../quick-action-dropdowns/cycle-issue.tsx | 9 + .../quick-action-dropdowns/module-issue.tsx | 9 + .../quick-action-dropdowns/project-issue.tsx | 9 +- .../roots/all-issue-layout-root.tsx | 13 +- .../spreadsheet/columns/assignee-column.tsx | 13 +- .../spreadsheet/columns/due-date-column.tsx | 14 +- .../spreadsheet/columns/estimate-column.tsx | 6 +- .../spreadsheet/columns/label-column.tsx | 6 +- .../spreadsheet/columns/priority-column.tsx | 4 +- .../spreadsheet/columns/start-date-column.tsx | 14 +- .../spreadsheet/columns/state-column.tsx | 4 +- .../issue-layouts/spreadsheet/issue-row.tsx | 18 +- .../spreadsheet/quick-add-issue-form.tsx | 21 ++- .../issues/issue-modal/draft-issue-layout.tsx | 22 ++- web/components/issues/issue-modal/modal.tsx | 72 ++++---- web/components/issues/peek-overview/root.tsx | 113 ++++++++++++- web/components/issues/sub-issues/root.tsx | 66 +++++++- .../modules/delete-module-modal.tsx | 16 +- web/components/modules/modal.tsx | 29 ++-- web/components/modules/module-card-item.tsx | 5 +- web/components/modules/module-list-item.tsx | 5 +- web/components/modules/modules-list-view.tsx | 8 +- web/components/modules/sidebar.tsx | 11 +- web/components/onboarding/invitations.tsx | 11 +- web/components/onboarding/tour/root.tsx | 10 +- .../page-views/workspace-dashboard.tsx | 15 +- web/components/project/card-list.tsx | 10 +- .../project/create-project-modal.tsx | 31 ++-- .../project/delete-project-modal.tsx | 34 ++-- web/components/project/form.tsx | 34 ++-- .../project/leave-project-modal.tsx | 10 +- web/components/project/member-list.tsx | 6 +- .../project/send-project-invitation-modal.tsx | 14 +- .../project/settings/features-list.tsx | 8 +- web/components/project/sidebar-list-item.tsx | 45 ++--- web/components/project/sidebar-list.tsx | 7 +- .../states/create-update-state-inline.tsx | 14 +- web/components/states/delete-state-modal.tsx | 10 +- .../project-setting-state-list-item.tsx | 6 +- .../states/project-setting-state-list.tsx | 6 +- .../workspace/create-workspace-form.tsx | 12 +- .../workspace/delete-workspace-modal.tsx | 10 +- .../workspace/settings/workspace-details.tsx | 10 +- web/components/workspace/sidebar-dropdown.tsx | 31 ++-- .../workspace/sidebar-quick-action.tsx | 9 +- web/constants/event-tracker.ts | 105 ++++++++++++ web/constants/spreadsheet.ts | 6 +- web/hooks/store/index.ts | 1 + web/hooks/store/use-event-tracker.ts | 11 ++ web/layouts/auth-layout/project-wrapper.tsx | 7 +- web/lib/app-provider.tsx | 6 +- ...sthog-wrapper.tsx => posthog-provider.tsx} | 12 +- web/lib/redirect.ts | 16 -- web/pages/[workspaceSlug]/analytics.tsx | 6 +- .../projects/[projectId]/cycles/index.tsx | 4 +- .../[workspaceSlug]/settings/members.tsx | 10 +- web/pages/invitations/index.tsx | 8 +- web/pages/onboarding/index.tsx | 8 +- web/store/application/event-tracker.store.ts | 79 --------- web/store/application/index.ts | 5 +- web/store/event-tracker.store.ts | 155 ++++++++++++++++++ web/store/root.store.ts | 3 + 103 files changed, 1385 insertions(+), 596 deletions(-) create mode 100644 web/constants/event-tracker.ts create mode 100644 web/hooks/store/use-event-tracker.ts rename web/lib/{wrappers/posthog-wrapper.tsx => posthog-provider.tsx} (82%) delete mode 100644 web/lib/redirect.ts delete mode 100644 web/store/application/event-tracker.store.ts create mode 100644 web/store/event-tracker.store.ts diff --git a/web/components/command-palette/actions/project-actions.tsx b/web/components/command-palette/actions/project-actions.tsx index 44b5e6111f..bdd08a0d83 100644 --- a/web/components/command-palette/actions/project-actions.tsx +++ b/web/components/command-palette/actions/project-actions.tsx @@ -1,7 +1,7 @@ import { Command } from "cmdk"; import { ContrastIcon, FileText } from "lucide-react"; // hooks -import { useApplication } from "hooks/store"; +import { useApplication, useEventTracker } from "hooks/store"; // ui import { DiceIcon, PhotoFilterIcon } from "@plane/ui"; @@ -14,8 +14,8 @@ export const CommandPaletteProjectActions: React.FC = (props) => { const { commandPalette: { toggleCreateCycleModal, toggleCreateModuleModal, toggleCreatePageModal, toggleCreateViewModal }, - eventTracker: { setTrackElement }, } = useApplication(); + const { setTrackElement } = useEventTracker(); return ( <> @@ -23,7 +23,7 @@ export const CommandPaletteProjectActions: React.FC = (props) => { { closePalette(); - setTrackElement("COMMAND_PALETTE"); + setTrackElement("Command palette"); toggleCreateCycleModal(true); }} className="focus:outline-none" @@ -39,6 +39,7 @@ export const CommandPaletteProjectActions: React.FC = (props) => { { closePalette(); + setTrackElement("Command palette"); toggleCreateModuleModal(true); }} className="focus:outline-none" @@ -54,6 +55,7 @@ export const CommandPaletteProjectActions: React.FC = (props) => { { closePalette(); + setTrackElement("Command palette"); toggleCreateViewModal(true); }} className="focus:outline-none" @@ -69,6 +71,7 @@ export const CommandPaletteProjectActions: React.FC = (props) => { { closePalette(); + setTrackElement("Command palette"); toggleCreatePageModal(true); }} className="focus:outline-none" diff --git a/web/components/command-palette/command-modal.tsx b/web/components/command-palette/command-modal.tsx index 3428278253..dbf349f9d7 100644 --- a/web/components/command-palette/command-modal.tsx +++ b/web/components/command-palette/command-modal.tsx @@ -6,7 +6,7 @@ import { Dialog, Transition } from "@headlessui/react"; import { observer } from "mobx-react-lite"; import { FolderPlus, Search, Settings } from "lucide-react"; // hooks -import { useApplication, useProject } from "hooks/store"; +import { useApplication, useEventTracker, useProject } from "hooks/store"; // services import { WorkspaceService } from "services/workspace.service"; import { IssueService } from "services/issue"; @@ -64,8 +64,8 @@ export const CommandModal: React.FC = observer(() => { toggleCreateIssueModal, toggleCreateProjectModal, }, - eventTracker: { setTrackElement }, } = useApplication(); + const { setTrackElement } = useEventTracker(); // router const router = useRouter(); @@ -278,7 +278,7 @@ export const CommandModal: React.FC = observer(() => { { closePalette(); - setTrackElement("COMMAND_PALETTE"); + setTrackElement("Command Palette"); toggleCreateIssueModal(true); }} className="focus:bg-custom-background-80" @@ -296,7 +296,7 @@ export const CommandModal: React.FC = observer(() => { { closePalette(); - setTrackElement("COMMAND_PALETTE"); + setTrackElement("Command palette"); toggleCreateProjectModal(true); }} className="focus:outline-none" diff --git a/web/components/command-palette/command-palette.tsx b/web/components/command-palette/command-palette.tsx index 213c35f8ee..e6349e0b4a 100644 --- a/web/components/command-palette/command-palette.tsx +++ b/web/components/command-palette/command-palette.tsx @@ -3,7 +3,7 @@ import { useRouter } from "next/router"; import useSWR from "swr"; import { observer } from "mobx-react-lite"; // hooks -import { useApplication, useIssues, useUser } from "hooks/store"; +import { useApplication, useEventTracker, useIssues, useUser } from "hooks/store"; import useToast from "hooks/use-toast"; // components import { CommandModal, ShortcutsModal } from "components/command-palette"; @@ -32,8 +32,8 @@ export const CommandPalette: FC = observer(() => { const { commandPalette, theme: { toggleSidebar }, - eventTracker: { setTrackElement }, } = useApplication(); + const { setTrackElement } = useEventTracker(); const { currentUser } = useUser(); const { issues: { removeIssue }, @@ -118,11 +118,10 @@ export const CommandPalette: FC = observer(() => { toggleSidebar(); } } else if (!isAnyModalOpen) { + setTrackElement("Shortcut key"); if (keyPressed === "c") { - setTrackElement("SHORTCUT_KEY"); toggleCreateIssueModal(true); } else if (keyPressed === "p") { - setTrackElement("SHORTCUT_KEY"); toggleCreateProjectModal(true); } else if (keyPressed === "h") { toggleShortcutModal(true); diff --git a/web/components/cycles/cycles-board-card.tsx b/web/components/cycles/cycles-board-card.tsx index d2279aeb4e..8da2be9ece 100644 --- a/web/components/cycles/cycles-board-card.tsx +++ b/web/components/cycles/cycles-board-card.tsx @@ -2,7 +2,7 @@ import { FC, MouseEvent, useState } from "react"; import { useRouter } from "next/router"; import Link from "next/link"; // hooks -import { useApplication, useCycle, useUser } from "hooks/store"; +import { useEventTracker, useCycle, useUser } from "hooks/store"; import useToast from "hooks/use-toast"; // components import { CycleCreateUpdateModal, CycleDeleteModal } from "components/cycles"; @@ -33,9 +33,7 @@ export const CyclesBoardCard: FC = (props) => { // router const router = useRouter(); // store - const { - eventTracker: { setTrackElement }, - } = useApplication(); + const { setTrackElement } = useEventTracker(); const { membership: { currentProjectRole }, } = useUser(); @@ -117,14 +115,15 @@ export const CyclesBoardCard: FC = (props) => { const handleEditCycle = (e: MouseEvent) => { e.preventDefault(); e.stopPropagation(); + setTrackElement("Cycles page board layout"); setUpdateModal(true); }; const handleDeleteCycle = (e: MouseEvent) => { e.preventDefault(); e.stopPropagation(); + setTrackElement("Cycles page board layout"); setDeleteModal(true); - setTrackElement("CYCLE_PAGE_BOARD_LAYOUT"); }; const openCycleOverview = (e: MouseEvent) => { diff --git a/web/components/cycles/cycles-list-item.tsx b/web/components/cycles/cycles-list-item.tsx index e34f4b30b2..86de8d0c0c 100644 --- a/web/components/cycles/cycles-list-item.tsx +++ b/web/components/cycles/cycles-list-item.tsx @@ -2,7 +2,7 @@ import { FC, MouseEvent, useState } from "react"; import Link from "next/link"; import { useRouter } from "next/router"; // hooks -import { useApplication, useCycle, useUser } from "hooks/store"; +import { useEventTracker, useCycle, useUser } from "hooks/store"; import useToast from "hooks/use-toast"; // components import { CycleCreateUpdateModal, CycleDeleteModal } from "components/cycles"; @@ -37,9 +37,7 @@ export const CyclesListItem: FC = (props) => { // router const router = useRouter(); // store hooks - const { - eventTracker: { setTrackElement }, - } = useApplication(); + const { setTrackElement } = useEventTracker(); const { membership: { currentProjectRole }, } = useUser(); @@ -90,14 +88,15 @@ export const CyclesListItem: FC = (props) => { const handleEditCycle = (e: MouseEvent) => { e.preventDefault(); e.stopPropagation(); + setTrackElement("Cycles page list layout"); setUpdateModal(true); }; const handleDeleteCycle = (e: MouseEvent) => { e.preventDefault(); e.stopPropagation(); + setTrackElement("Cycles page list layout"); setDeleteModal(true); - setTrackElement("CYCLE_PAGE_LIST_LAYOUT"); }; const openCycleOverview = (e: MouseEvent) => { diff --git a/web/components/cycles/delete-modal.tsx b/web/components/cycles/delete-modal.tsx index 44da175b49..32e067833e 100644 --- a/web/components/cycles/delete-modal.tsx +++ b/web/components/cycles/delete-modal.tsx @@ -4,7 +4,7 @@ import { Dialog, Transition } from "@headlessui/react"; import { observer } from "mobx-react-lite"; import { AlertTriangle } from "lucide-react"; // hooks -import { useApplication, useCycle } from "hooks/store"; +import { useEventTracker, useCycle } from "hooks/store"; import useToast from "hooks/use-toast"; // components import { Button } from "@plane/ui"; @@ -27,9 +27,7 @@ export const CycleDeleteModal: React.FC = observer((props) => { const router = useRouter(); const { cycleId, peekCycle } = router.query; // store hooks - const { - eventTracker: { postHogEventTracker }, - } = useApplication(); + const { captureCycleEvent } = useEventTracker(); const { deleteCycle } = useCycle(); // toast alert const { setToastAlert } = useToast(); @@ -46,13 +44,15 @@ export const CycleDeleteModal: React.FC = observer((props) => { title: "Success!", message: "Cycle deleted successfully.", }); - postHogEventTracker("CYCLE_DELETE", { - state: "SUCCESS", + captureCycleEvent({ + eventName: "Cycle deleted", + payload: { ...cycle, state: "SUCCESS" }, }); }) .catch(() => { - postHogEventTracker("CYCLE_DELETE", { - state: "FAILED", + captureCycleEvent({ + eventName: "Cycle deleted", + payload: { ...cycle, state: "FAILED" }, }); }); diff --git a/web/components/cycles/modal.tsx b/web/components/cycles/modal.tsx index 8144feef7e..7e17e55f1e 100644 --- a/web/components/cycles/modal.tsx +++ b/web/components/cycles/modal.tsx @@ -3,7 +3,7 @@ import { Dialog, Transition } from "@headlessui/react"; // services import { CycleService } from "services/cycle.service"; // hooks -import { useApplication, useCycle, useProject } from "hooks/store"; +import { useEventTracker, useCycle, useProject } from "hooks/store"; import useToast from "hooks/use-toast"; import useLocalStorage from "hooks/use-local-storage"; // components @@ -27,9 +27,7 @@ export const CycleCreateUpdateModal: React.FC = (props) => { // states const [activeProject, setActiveProject] = useState(null); // store hooks - const { - eventTracker: { postHogEventTracker }, - } = useApplication(); + const { captureCycleEvent } = useEventTracker(); const { workspaceProjectIds } = useProject(); const { createCycle, updateCycleDetails } = useCycle(); // toast alert @@ -48,9 +46,9 @@ export const CycleCreateUpdateModal: React.FC = (props) => { title: "Success!", message: "Cycle created successfully.", }); - postHogEventTracker("CYCLE_CREATE", { - ...res, - state: "SUCCESS", + captureCycleEvent({ + eventName: "Cycle created", + payload: { ...res, state: "SUCCESS" }, }); }) .catch((err) => { @@ -59,8 +57,9 @@ export const CycleCreateUpdateModal: React.FC = (props) => { title: "Error!", message: err.detail ?? "Error in creating cycle. Please try again.", }); - postHogEventTracker("CYCLE_CREATE", { - state: "FAILED", + captureCycleEvent({ + eventName: "Cycle created", + payload: { ...payload, state: "FAILED" }, }); }); }; diff --git a/web/components/cycles/sidebar.tsx b/web/components/cycles/sidebar.tsx index 5fa1d24593..c61679304e 100644 --- a/web/components/cycles/sidebar.tsx +++ b/web/components/cycles/sidebar.tsx @@ -6,7 +6,7 @@ import { Disclosure, Popover, Transition } from "@headlessui/react"; // services import { CycleService } from "services/cycle.service"; // hooks -import { useApplication, useCycle, useMember, useUser } from "hooks/store"; +import { useEventTracker, useCycle, useUser, useMember } from "hooks/store"; import useToast from "hooks/use-toast"; // components import { SidebarProgressStats } from "components/core"; @@ -66,9 +66,7 @@ export const CycleDetailsSidebar: React.FC = observer((props) => { const router = useRouter(); const { workspaceSlug, projectId, peekCycle } = router.query; // store hooks - const { - eventTracker: { setTrackElement }, - } = useApplication(); + const { setTrackElement } = useEventTracker(); const { membership: { currentProjectRole }, } = useUser(); diff --git a/web/components/dashboard/project-empty-state.tsx b/web/components/dashboard/project-empty-state.tsx index c0ac90f34e..bb7f82f341 100644 --- a/web/components/dashboard/project-empty-state.tsx +++ b/web/components/dashboard/project-empty-state.tsx @@ -1,7 +1,7 @@ import Image from "next/image"; import { observer } from "mobx-react-lite"; // hooks -import { useApplication, useUser } from "hooks/store"; +import { useApplication, useEventTracker, useUser } from "hooks/store"; // ui import { Button } from "@plane/ui"; // assets @@ -14,6 +14,7 @@ export const DashboardProjectEmptyState = observer(() => { const { commandPalette: { toggleCreateProjectModal }, } = useApplication(); + const { setTrackElement } = useEventTracker(); const { membership: { currentWorkspaceRole }, } = useUser(); @@ -31,7 +32,13 @@ export const DashboardProjectEmptyState = observer(() => { Project empty state {canCreateProject && (
-
diff --git a/web/components/dashboard/widgets/recent-projects.tsx b/web/components/dashboard/widgets/recent-projects.tsx index aae8ff54b4..eb7a5e4e55 100644 --- a/web/components/dashboard/widgets/recent-projects.tsx +++ b/web/components/dashboard/widgets/recent-projects.tsx @@ -3,7 +3,7 @@ import Link from "next/link"; import { observer } from "mobx-react-lite"; import { Plus } from "lucide-react"; // hooks -import { useApplication, useDashboard, useProject, useUser } from "hooks/store"; +import { useApplication, useEventTracker, useDashboard, useProject, useUser } from "hooks/store"; // components import { WidgetLoader, WidgetProps } from "components/dashboard/widgets"; // ui @@ -72,6 +72,7 @@ export const RecentProjectsWidget: React.FC = observer((props) => { const { commandPalette: { toggleCreateProjectModal }, } = useApplication(); + const { setTrackElement } = useEventTracker(); const { membership: { currentWorkspaceRole }, } = useUser(); @@ -105,6 +106,7 @@ export const RecentProjectsWidget: React.FC = observer((props) => { onClick={(e) => { e.preventDefault(); e.stopPropagation(); + setTrackElement("Sidebar"); toggleCreateProjectModal(true); }} > diff --git a/web/components/headers/cycle-issues.tsx b/web/components/headers/cycle-issues.tsx index 8e2ceab100..7cfc492f4f 100644 --- a/web/components/headers/cycle-issues.tsx +++ b/web/components/headers/cycle-issues.tsx @@ -5,6 +5,7 @@ import Link from "next/link"; // hooks import { useApplication, + useEventTracker, useCycle, useLabel, useMember, @@ -70,8 +71,8 @@ export const CycleIssuesHeader: React.FC = observer(() => { const { currentProjectCycleIds, getCycleById } = useCycle(); const { commandPalette: { toggleCreateIssueModal }, - eventTracker: { setTrackElement }, } = useApplication(); + const { setTrackElement } = useEventTracker(); const { membership: { currentProjectRole }, } = useUser(); @@ -238,7 +239,7 @@ export const CycleIssuesHeader: React.FC = observer(() => { diff --git a/web/components/headers/project-issues.tsx b/web/components/headers/project-issues.tsx index 29ecb16c7f..769d6c945f 100644 --- a/web/components/headers/project-issues.tsx +++ b/web/components/headers/project-issues.tsx @@ -4,7 +4,16 @@ import { useRouter } from "next/router"; import { observer } from "mobx-react-lite"; import { ArrowLeft, Briefcase, Circle, ExternalLink, Plus } from "lucide-react"; // hooks -import { useApplication, useLabel, useProject, useProjectState, useUser, useInbox, useMember } from "hooks/store"; +import { + useApplication, + useEventTracker, + useLabel, + useProject, + useProjectState, + useUser, + useInbox, + useMember, +} from "hooks/store"; // components import { DisplayFiltersSelection, FiltersDropdown, FilterSelection, LayoutSelection } from "components/issues"; import { ProjectAnalyticsModal } from "components/analytics"; @@ -36,8 +45,8 @@ export const ProjectIssuesHeader: React.FC = observer(() => { } = useIssues(EIssuesStoreType.PROJECT); const { commandPalette: { toggleCreateIssueModal }, - eventTracker: { setTrackElement }, } = useApplication(); + const { setTrackElement } = useEventTracker(); const { membership: { currentProjectRole }, } = useUser(); @@ -221,7 +230,7 @@ export const ProjectIssuesHeader: React.FC = observer(() => { {isEditingAllowed && ( - setModuleDeleteModal(true)}> + { + setTrackElement("Module peek-overview"); + setModuleDeleteModal(true); + }} + > Delete module diff --git a/web/components/onboarding/invitations.tsx b/web/components/onboarding/invitations.tsx index c9ec19cc8a..3315ff0357 100644 --- a/web/components/onboarding/invitations.tsx +++ b/web/components/onboarding/invitations.tsx @@ -1,7 +1,7 @@ import React, { useState } from "react"; import useSWR, { mutate } from "swr"; // hooks -import { useApplication, useUser, useWorkspace } from "hooks/store"; +import { useEventTracker, useUser, useWorkspace } from "hooks/store"; // components import { Button } from "@plane/ui"; // helpers @@ -15,6 +15,7 @@ import { ROLE } from "constants/workspace"; import { IWorkspaceMemberInvitation } from "@plane/types"; // icons import { CheckCircle2, Search } from "lucide-react"; +import {} from "hooks/store/use-event-tracker"; type Props = { handleNextStep: () => void; @@ -28,9 +29,7 @@ export const Invitations: React.FC = (props) => { const [isJoiningWorkspaces, setIsJoiningWorkspaces] = useState(false); const [invitationsRespond, setInvitationsRespond] = useState([]); // store hooks - const { - eventTracker: { postHogEventTracker }, - } = useApplication(); + const { captureEvent } = useEventTracker(); const { currentUser, updateCurrentUser } = useUser(); const { workspaces, fetchWorkspaces } = useWorkspace(); @@ -63,7 +62,7 @@ export const Invitations: React.FC = (props) => { await workspaceService .joinWorkspaces({ invitations: invitationsRespond }) .then(async (res) => { - postHogEventTracker("MEMBER_ACCEPTED", { ...res, state: "SUCCESS", accepted_from: "App" }); + captureEvent("Member accepted", { ...res, state: "SUCCESS", accepted_from: "App" }); await fetchWorkspaces(); await mutate(USER_WORKSPACES); await updateLastWorkspace(); @@ -72,7 +71,7 @@ export const Invitations: React.FC = (props) => { }) .catch((error) => { console.error(error); - postHogEventTracker("MEMBER_ACCEPTED", { state: "FAILED", accepted_from: "App" }); + captureEvent("Member accepted", { state: "FAILED", accepted_from: "App" }); }) .finally(() => setIsJoiningWorkspaces(false)); }; diff --git a/web/components/onboarding/tour/root.tsx b/web/components/onboarding/tour/root.tsx index 362c03ed5b..6e1de15dd5 100644 --- a/web/components/onboarding/tour/root.tsx +++ b/web/components/onboarding/tour/root.tsx @@ -3,7 +3,7 @@ import Image from "next/image"; import { observer } from "mobx-react-lite"; import { X } from "lucide-react"; // hooks -import { useApplication, useUser } from "hooks/store"; +import { useApplication, useEventTracker, useUser } from "hooks/store"; // components import { TourSidebar } from "components/onboarding"; // ui @@ -78,10 +78,8 @@ export const TourRoot: React.FC = observer((props) => { // states const [step, setStep] = useState("welcome"); // store hooks - const { - commandPalette: commandPaletteStore, - eventTracker: { setTrackElement }, - } = useApplication(); + const { commandPalette: commandPaletteStore } = useApplication(); + const { setTrackElement } = useEventTracker(); const { currentUser } = useUser(); const currentStepIndex = TOUR_STEPS.findIndex((tourStep) => tourStep.key === step); @@ -159,7 +157,7 @@ export const TourRoot: React.FC = observer((props) => { variant="primary" onClick={() => { onComplete(); - setTrackElement("ONBOARDING_TOUR"); + setTrackElement("Onboarding tour"); commandPaletteStore.toggleCreateProjectModal(true); }} > diff --git a/web/components/page-views/workspace-dashboard.tsx b/web/components/page-views/workspace-dashboard.tsx index 3ae0b9e62a..dc9c4de612 100644 --- a/web/components/page-views/workspace-dashboard.tsx +++ b/web/components/page-views/workspace-dashboard.tsx @@ -2,7 +2,7 @@ import { useEffect } from "react"; import { useTheme } from "next-themes"; import { observer } from "mobx-react-lite"; // hooks -import { useApplication, useDashboard, useProject, useUser } from "hooks/store"; +import { useApplication, useEventTracker, useDashboard, useProject, useUser } from "hooks/store"; // components import { TourRoot } from "components/onboarding"; import { UserGreetingsView } from "components/user"; @@ -18,9 +18,9 @@ export const WorkspaceDashboardView = observer(() => { // theme const { resolvedTheme } = useTheme(); // store hooks + const { captureEvent, setTrackElement } = useEventTracker(); const { commandPalette: { toggleCreateProjectModal }, - eventTracker: { postHogEventTracker }, router: { workspaceSlug }, } = useApplication(); const { @@ -37,7 +37,7 @@ export const WorkspaceDashboardView = observer(() => { const handleTourCompleted = () => { updateTourCompleted() .then(() => { - postHogEventTracker("USER_TOUR_COMPLETE", { + captureEvent("User tour complete", { user_id: currentUser?.id, email: currentUser?.email, state: "SUCCESS", @@ -62,7 +62,7 @@ export const WorkspaceDashboardView = observer(() => { {homeDashboardId && joinedProjectIds ? ( <> {joinedProjectIds.length > 0 ? ( -
+
{currentUser && } {currentUser && !currentUser.is_tour_completed && ( @@ -81,7 +81,10 @@ export const WorkspaceDashboardView = observer(() => { progress." primaryButton={{ text: "Build your first project", - onClick: () => toggleCreateProjectModal(true), + onClick: () => { + setTrackElement("Dashboard"); + toggleCreateProjectModal(true); + }, }} comicBox={{ title: "Everything starts with a project in Plane", @@ -93,7 +96,7 @@ export const WorkspaceDashboardView = observer(() => { )} ) : ( -
+
)} diff --git a/web/components/project/card-list.tsx b/web/components/project/card-list.tsx index 76e67e1b70..e7601ce350 100644 --- a/web/components/project/card-list.tsx +++ b/web/components/project/card-list.tsx @@ -1,7 +1,7 @@ import { observer } from "mobx-react-lite"; import { useTheme } from "next-themes"; // hooks -import { useApplication, useProject, useUser } from "hooks/store"; +import { useApplication, useEventTracker, useProject, useUser } from "hooks/store"; // components import { ProjectCard } from "components/project"; import { Loader } from "@plane/ui"; @@ -13,10 +13,8 @@ export const ProjectCardList = observer(() => { // theme const { resolvedTheme } = useTheme(); // store hooks - const { - commandPalette: commandPaletteStore, - eventTracker: { setTrackElement }, - } = useApplication(); + const { commandPalette: commandPaletteStore } = useApplication(); + const { setTrackElement } = useEventTracker(); const { membership: { currentWorkspaceRole }, currentUser, @@ -66,7 +64,7 @@ export const ProjectCardList = observer(() => { primaryButton={{ text: "Start your first project", onClick: () => { - setTrackElement("PROJECTS_EMPTY_STATE"); + setTrackElement("Project empty state"); commandPaletteStore.toggleCreateProjectModal(true); }, }} diff --git a/web/components/project/create-project-modal.tsx b/web/components/project/create-project-modal.tsx index 1e6aa136ab..377ef06c1d 100644 --- a/web/components/project/create-project-modal.tsx +++ b/web/components/project/create-project-modal.tsx @@ -4,7 +4,7 @@ import { Dialog, Transition } from "@headlessui/react"; import { observer } from "mobx-react-lite"; import { X } from "lucide-react"; // hooks -import { useApplication, useProject, useUser, useWorkspace } from "hooks/store"; +import { useEventTracker, useProject, useUser, useWorkspace } from "hooks/store"; import useToast from "hooks/use-toast"; // ui import { Button, CustomSelect, Input, TextArea } from "@plane/ui"; @@ -61,9 +61,7 @@ export interface ICreateProjectForm { export const CreateProjectModal: FC = observer((props) => { const { isOpen, onClose, setToFavorite = false, workspaceSlug } = props; // store - const { - eventTracker: { postHogEventTracker }, - } = useApplication(); + const { captureProjectEvent } = useEventTracker(); const { membership: { currentWorkspaceRole }, } = useUser(); @@ -135,10 +133,14 @@ export const CreateProjectModal: FC = observer((props) => { ...res, state: "SUCCESS", }; - postHogEventTracker("PROJECT_CREATED", newPayload, { - isGrouping: true, - groupType: "Workspace_metrics", - groupId: res.workspace, + captureProjectEvent({ + eventName: "Project created", + payload: newPayload, + group: { + isGrouping: true, + groupType: "Workspace_metrics", + groupId: res.workspace, + }, }); setToastAlert({ type: "success", @@ -157,17 +159,18 @@ export const CreateProjectModal: FC = observer((props) => { title: "Error!", message: err.data[key], }); - postHogEventTracker( - "PROJECT_CREATED", - { + captureProjectEvent({ + eventName: "Project created", + payload: { + ...payload, state: "FAILED", }, - { + group: { isGrouping: true, groupType: "Workspace_metrics", groupId: currentWorkspace?.id!, - } - ); + }, + }); }); }); }; diff --git a/web/components/project/delete-project-modal.tsx b/web/components/project/delete-project-modal.tsx index e2b0bc5f0d..7e04a6ebd0 100644 --- a/web/components/project/delete-project-modal.tsx +++ b/web/components/project/delete-project-modal.tsx @@ -4,7 +4,7 @@ import { Controller, useForm } from "react-hook-form"; import { Dialog, Transition } from "@headlessui/react"; import { AlertTriangle } from "lucide-react"; // hooks -import { useApplication, useProject, useWorkspace } from "hooks/store"; +import { useEventTracker, useProject, useWorkspace } from "hooks/store"; import useToast from "hooks/use-toast"; // ui import { Button, Input } from "@plane/ui"; @@ -25,9 +25,7 @@ const defaultValues = { export const DeleteProjectModal: React.FC = (props) => { const { isOpen, project, onClose } = props; // store hooks - const { - eventTracker: { postHogEventTracker }, - } = useApplication(); + const { captureProjectEvent } = useEventTracker(); const { currentWorkspace } = useWorkspace(); const { deleteProject } = useProject(); // router @@ -63,17 +61,15 @@ export const DeleteProjectModal: React.FC = (props) => { if (projectId && projectId.toString() === project.id) router.push(`/${workspaceSlug}/projects`); handleClose(); - postHogEventTracker( - "PROJECT_DELETED", - { - state: "SUCCESS", - }, - { + captureProjectEvent({ + eventName: "Project deleted", + payload: { ...project, state: "SUCCESS", element: "Project general settings" }, + group: { isGrouping: true, groupType: "Workspace_metrics", groupId: currentWorkspace?.id!, - } - ); + }, + }); setToastAlert({ type: "success", title: "Success!", @@ -81,17 +77,15 @@ export const DeleteProjectModal: React.FC = (props) => { }); }) .catch(() => { - postHogEventTracker( - "PROJECT_DELETED", - { - state: "FAILED", - }, - { + captureProjectEvent({ + eventName: "Project deleted", + payload: { ...project, state: "FAILED", element: "Project general settings" }, + group: { isGrouping: true, groupType: "Workspace_metrics", groupId: currentWorkspace?.id!, - } - ); + }, + }); setToastAlert({ type: "error", title: "Error!", diff --git a/web/components/project/form.tsx b/web/components/project/form.tsx index 5be7033a4c..f5efa7bc8e 100644 --- a/web/components/project/form.tsx +++ b/web/components/project/form.tsx @@ -1,7 +1,7 @@ import { FC, useEffect, useState } from "react"; import { Controller, useForm } from "react-hook-form"; // hooks -import { useApplication, useProject, useWorkspace } from "hooks/store"; +import { useEventTracker, useProject, useWorkspace } from "hooks/store"; import useToast from "hooks/use-toast"; // components import EmojiIconPicker from "components/emoji-icon-picker"; @@ -32,9 +32,7 @@ export const ProjectDetailsForm: FC = (props) => { // states const [isLoading, setIsLoading] = useState(false); // store hooks - const { - eventTracker: { postHogEventTracker }, - } = useApplication(); + const { captureProjectEvent } = useEventTracker(); const { currentWorkspace } = useWorkspace(); const { updateProject } = useProject(); // toast alert @@ -79,15 +77,15 @@ export const ProjectDetailsForm: FC = (props) => { return updateProject(workspaceSlug.toString(), project.id, payload) .then((res) => { - postHogEventTracker( - "PROJECT_UPDATED", - { ...res, state: "SUCCESS" }, - { + captureProjectEvent({ + eventName: "Project updated", + payload: { ...res, state: "SUCCESS", element: "Project general settings" }, + group: { isGrouping: true, groupType: "Workspace_metrics", groupId: res.workspace, - } - ); + }, + }); setToastAlert({ type: "success", title: "Success!", @@ -95,17 +93,15 @@ export const ProjectDetailsForm: FC = (props) => { }); }) .catch((error) => { - postHogEventTracker( - "PROJECT_UPDATED", - { - state: "FAILED", - }, - { + captureProjectEvent({ + eventName: "Project updated", + payload: { ...payload, state: "FAILED", element: "Project general settings" }, + group: { isGrouping: true, groupType: "Workspace_metrics", - groupId: currentWorkspace?.id!, - } - ); + groupId: currentWorkspace?.id, + }, + }); setToastAlert({ type: "error", title: "Error!", diff --git a/web/components/project/leave-project-modal.tsx b/web/components/project/leave-project-modal.tsx index 96fc8df595..941bbbaa6a 100644 --- a/web/components/project/leave-project-modal.tsx +++ b/web/components/project/leave-project-modal.tsx @@ -5,7 +5,7 @@ import { Dialog, Transition } from "@headlessui/react"; import { AlertTriangleIcon } from "lucide-react"; import { observer } from "mobx-react-lite"; // hooks -import { useApplication, useUser } from "hooks/store"; +import { useEventTracker, useUser } from "hooks/store"; import useToast from "hooks/use-toast"; // ui import { Button, Input } from "@plane/ui"; @@ -34,9 +34,7 @@ export const LeaveProjectModal: FC = observer((props) => { const router = useRouter(); const { workspaceSlug } = router.query; // store hooks - const { - eventTracker: { postHogEventTracker }, - } = useApplication(); + const { captureEvent } = useEventTracker(); const { membership: { leaveProject }, } = useUser(); @@ -65,7 +63,7 @@ export const LeaveProjectModal: FC = observer((props) => { .then(() => { handleClose(); router.push(`/${workspaceSlug}/projects`); - postHogEventTracker("PROJECT_MEMBER_LEAVE", { + captureEvent("Project member leave", { state: "SUCCESS", }); }) @@ -75,7 +73,7 @@ export const LeaveProjectModal: FC = observer((props) => { title: "Error!", message: "Something went wrong please try again later.", }); - postHogEventTracker("PROJECT_MEMBER_LEAVE", { + captureEvent("Project member leave", { state: "FAILED", }); }); diff --git a/web/components/project/member-list.tsx b/web/components/project/member-list.tsx index 899348dd21..fa8008c8f2 100644 --- a/web/components/project/member-list.tsx +++ b/web/components/project/member-list.tsx @@ -2,7 +2,7 @@ import { useState } from "react"; import { observer } from "mobx-react-lite"; import { Search } from "lucide-react"; // hooks -import { useApplication, useMember } from "hooks/store"; +import { useEventTracker, useMember } from "hooks/store"; // components import { ProjectMemberListItem, SendProjectInvitationModal } from "components/project"; // ui @@ -13,9 +13,7 @@ export const ProjectMemberList: React.FC = observer(() => { const [inviteModal, setInviteModal] = useState(false); const [searchQuery, setSearchQuery] = useState(""); // store hooks - const { - eventTracker: { setTrackElement }, - } = useApplication(); + const { setTrackElement } = useEventTracker(); const { project: { projectMemberIds, getProjectMemberDetails }, } = useMember(); diff --git a/web/components/project/send-project-invitation-modal.tsx b/web/components/project/send-project-invitation-modal.tsx index b165a40ae4..39fb5c9741 100644 --- a/web/components/project/send-project-invitation-modal.tsx +++ b/web/components/project/send-project-invitation-modal.tsx @@ -5,7 +5,7 @@ import { useForm, Controller, useFieldArray } from "react-hook-form"; import { Dialog, Transition } from "@headlessui/react"; import { ChevronDown, Plus, X } from "lucide-react"; // hooks -import { useApplication, useMember, useUser, useWorkspace } from "hooks/store"; +import { useEventTracker, useMember, useUser, useWorkspace } from "hooks/store"; import useToast from "hooks/use-toast"; // ui import { Avatar, Button, CustomSelect, CustomSearchSelect } from "@plane/ui"; @@ -45,9 +45,7 @@ export const SendProjectInvitationModal: React.FC = observer((props) => { // toast alert const { setToastAlert } = useToast(); // store hooks - const { - eventTracker: { postHogEventTracker }, - } = useApplication(); + const { captureEvent } = useEventTracker(); const { membership: { currentProjectRole }, } = useUser(); @@ -89,8 +87,8 @@ export const SendProjectInvitationModal: React.FC = observer((props) => { type: "success", message: "Members added successfully.", }); - postHogEventTracker( - "MEMBER_ADDED", + captureEvent( + "Member added", { ...res, state: "SUCCESS", @@ -104,8 +102,8 @@ export const SendProjectInvitationModal: React.FC = observer((props) => { }) .catch((error) => { console.error(error); - postHogEventTracker( - "MEMBER_ADDED", + captureEvent( + "Member added", { state: "FAILED", }, diff --git a/web/components/project/settings/features-list.tsx b/web/components/project/settings/features-list.tsx index ed45792f24..34aec4db61 100644 --- a/web/components/project/settings/features-list.tsx +++ b/web/components/project/settings/features-list.tsx @@ -4,7 +4,7 @@ import { observer } from "mobx-react-lite"; import { ContrastIcon, FileText, Inbox, Layers } from "lucide-react"; import { DiceIcon, ToggleSwitch } from "@plane/ui"; // hooks -import { useApplication, useProject, useUser, useWorkspace } from "hooks/store"; +import { useEventTracker, useProject, useUser, useWorkspace } from "hooks/store"; import useToast from "hooks/use-toast"; // types import { IProject } from "@plane/types"; @@ -51,9 +51,7 @@ export const ProjectFeaturesList: FC = observer(() => { const router = useRouter(); const { workspaceSlug, projectId } = router.query; // store hooks - const { - eventTracker: { setTrackElement, postHogEventTracker }, - } = useApplication(); + const { setTrackElement, captureEvent } = useEventTracker(); const { currentUser, membership: { currentProjectRole }, @@ -94,7 +92,7 @@ export const ProjectFeaturesList: FC = observer(() => { value={Boolean(currentProjectDetails?.[feature.property as keyof IProject])} onChange={() => { setTrackElement("PROJECT_SETTINGS_FEATURES_PAGE"); - postHogEventTracker(`TOGGLE_${feature.title.toUpperCase()}`, { + captureEvent(`Toggle ${feature.title.toLowerCase()}`, { workspace_id: currentWorkspace?.id, workspace_slug: currentWorkspace?.slug, project_id: currentProjectDetails?.id, diff --git a/web/components/project/sidebar-list-item.tsx b/web/components/project/sidebar-list-item.tsx index 8e4188d811..d9cd81d5f6 100644 --- a/web/components/project/sidebar-list-item.tsx +++ b/web/components/project/sidebar-list-item.tsx @@ -18,7 +18,7 @@ import { MoreHorizontal, } from "lucide-react"; // hooks -import { useApplication, useProject } from "hooks/store"; +import { useApplication,useEventTracker, useProject } from "hooks/store"; import useOutsideClickDetector from "hooks/use-outside-click-detector"; import useToast from "hooks/use-toast"; // helpers @@ -73,10 +73,8 @@ export const ProjectSidebarListItem: React.FC = observer((props) => { // eslint-disable-next-line @typescript-eslint/no-unused-vars const { projectId, provided, snapshot, handleCopyText, shortContextMenu = false } = props; // store hooks - const { - theme: themeStore, - eventTracker: { setTrackElement }, - } = useApplication(); + const { theme: themeStore } = useApplication(); + const { setTrackElement } = useEventTracker(); const { addProjectToFavorites, removeProjectFromFavorites, getProjectById } = useProject(); // states const [leaveProjectModalOpen, setLeaveProjectModal] = useState(false); @@ -149,8 +147,9 @@ export const ProjectSidebarListItem: React.FC = observer((props) => { {({ open }) => ( <>
{provided && ( = observer((props) => { >