Compare commits

...

5 Commits

Author SHA1 Message Date
srinivaspendem
00b3c25c0f Merge branch 'develop' of https://github.com/makeplane/plane into fix/posthog-fixes 2023-09-19 13:12:38 +05:30
srinivaspendem
a798707112 Posthog initial integration 2023-09-19 13:12:21 +05:30
sriram veeraghanta
5b3d28d9aa yarn lock update 2023-09-15 11:40:45 +05:30
sriram veeraghanta
4303658ddb adding capture function for tacking events in posthog 2023-09-14 23:02:49 +05:30
sriram veeraghanta
df62c97579 fix: posthog integration fixes 2023-09-14 21:38:00 +05:30
26 changed files with 678 additions and 173 deletions

View File

@ -28,7 +28,8 @@
"SLACK_CLIENT_SECRET",
"JITSU_TRACKER_ACCESS_KEY",
"JITSU_TRACKER_HOST",
"UNSPLASH_ACCESS_KEY"
"UNSPLASH_ACCESS_KEY",
"NODE_ENV"
],
"pipeline": {
"build": {

View File

@ -26,110 +26,121 @@ type Props = {
export type TPeekOverviewModes = "side" | "modal" | "full";
export const IssuePeekOverview: React.FC<Props> = observer(
({ handleMutation, projectId, readOnly, workspaceSlug }) => {
const [isSidePeekOpen, setIsSidePeekOpen] = useState(false);
const [isModalPeekOpen, setIsModalPeekOpen] = useState(false);
const [peekOverviewMode, setPeekOverviewMode] = useState<TPeekOverviewModes>("side");
const [deleteIssueModal, setDeleteIssueModal] = useState(false);
export const IssuePeekOverview: React.FC<Props> = observer((props) => {
const { handleMutation, projectId, readOnly, workspaceSlug } = props;
// states
const [isSidePeekOpen, setIsSidePeekOpen] = useState(false);
const [isModalPeekOpen, setIsModalPeekOpen] = useState(false);
const [peekOverviewMode, setPeekOverviewMode] = useState<TPeekOverviewModes>("side");
const [deleteIssueModal, setDeleteIssueModal] = useState(false);
const router = useRouter();
const { peekIssue } = router.query;
const router = useRouter();
const { peekIssue } = router.query;
const { issues: issuesStore } = useMobxStore();
const { deleteIssue, getIssueById, issues, updateIssue } = issuesStore;
const { issues: issuesStore } = useMobxStore();
const { deleteIssue, getIssueById, issues, updateIssue } = issuesStore;
const issue = issues[peekIssue?.toString() ?? ""];
const issue = issues[peekIssue?.toString() ?? ""];
const { user } = useUser();
const { user } = useUser();
const handleClose = () => {
const { query } = router;
delete query.peekIssue;
const handleClose = () => {
const { query } = router;
delete query.peekIssue;
router.push({
pathname: router.pathname,
query: { ...query },
});
};
router.push({
pathname: router.pathname,
query: { ...query },
});
};
const handleUpdateIssue = async (formData: Partial<IIssue>) => {
if (!issue || !user) return;
const handleUpdateIssue = async (formData: Partial<IIssue>) => {
if (!issue || !user) return;
await updateIssue(workspaceSlug, projectId, issue.id, formData, user);
mutate(PROJECT_ISSUES_ACTIVITY(issue.id));
handleMutation();
};
await updateIssue(workspaceSlug, projectId, issue.id, formData, user);
mutate(PROJECT_ISSUES_ACTIVITY(issue.id));
handleMutation();
};
const handleDeleteIssue = async () => {
if (!issue || !user) return;
const handleDeleteIssue = async () => {
if (!issue || !user) return;
await deleteIssue(workspaceSlug, projectId, issue.id, user);
handleMutation();
handleClose();
};
await deleteIssue(workspaceSlug, projectId, issue.id, user);
handleMutation();
useEffect(() => {
if (!peekIssue) return;
handleClose();
};
getIssueById(workspaceSlug, projectId, peekIssue.toString());
}, [getIssueById, peekIssue, projectId, workspaceSlug]);
useEffect(() => {
if (!peekIssue) return;
getIssueById(workspaceSlug, projectId, peekIssue.toString());
}, [getIssueById, peekIssue, projectId, workspaceSlug]);
useEffect(() => {
if (peekIssue) {
if (peekOverviewMode === "side") {
setIsSidePeekOpen(true);
setIsModalPeekOpen(false);
} else {
setIsModalPeekOpen(true);
setIsSidePeekOpen(false);
}
} else {
setIsSidePeekOpen(false);
useEffect(() => {
if (peekIssue) {
if (peekOverviewMode === "side") {
setIsSidePeekOpen(true);
setIsModalPeekOpen(false);
} else {
setIsModalPeekOpen(true);
setIsSidePeekOpen(false);
}
}, [peekIssue, peekOverviewMode]);
} else {
setIsSidePeekOpen(false);
setIsModalPeekOpen(false);
}
}, [peekIssue, peekOverviewMode]);
return (
<>
<DeleteIssueModal
isOpen={deleteIssueModal}
handleClose={() => setDeleteIssueModal(false)}
data={issue ? { ...issue } : null}
onSubmit={handleDeleteIssue}
user={user}
/>
<Transition.Root appear show={isSidePeekOpen} as={React.Fragment}>
<Dialog as="div" className="relative z-20" onClose={handleClose}>
<div className="fixed inset-0 z-20 h-full w-full overflow-y-auto">
<Transition.Child
as={React.Fragment}
enter="transition-transform duration-300"
enterFrom="translate-x-full"
enterTo="translate-x-0"
leave="transition-transform duration-200"
leaveFrom="translate-x-0"
leaveTo="translate-x-full"
>
<Dialog.Panel className="fixed z-20 bg-custom-background-100 top-0 right-0 h-full w-1/2 shadow-custom-shadow-md">
<SidePeekView
handleClose={handleClose}
handleDeleteIssue={() => setDeleteIssueModal(true)}
handleUpdateIssue={handleUpdateIssue}
issue={issue}
mode={peekOverviewMode}
readOnly={readOnly}
setMode={(mode) => setPeekOverviewMode(mode)}
workspaceSlug={workspaceSlug}
/>
</Dialog.Panel>
</Transition.Child>
</div>
</Dialog>
</Transition.Root>
<Transition.Root appear show={isModalPeekOpen} as={React.Fragment}>
<Dialog as="div" className="relative z-20" onClose={handleClose}>
return (
<>
<DeleteIssueModal
isOpen={deleteIssueModal}
handleClose={() => setDeleteIssueModal(false)}
data={issue ? { ...issue } : null}
onSubmit={handleDeleteIssue}
user={user}
/>
<Transition.Root appear show={isSidePeekOpen} as={React.Fragment}>
<Dialog as="div" className="relative z-20" onClose={handleClose}>
<div className="fixed inset-0 z-20 h-full w-full overflow-y-auto">
<Transition.Child
as={React.Fragment}
enter="transition-transform duration-300"
enterFrom="translate-x-full"
enterTo="translate-x-0"
leave="transition-transform duration-200"
leaveFrom="translate-x-0"
leaveTo="translate-x-full"
>
<Dialog.Panel className="fixed z-20 bg-custom-background-100 top-0 right-0 h-full w-1/2 shadow-custom-shadow-md">
<SidePeekView
handleClose={handleClose}
handleDeleteIssue={() => setDeleteIssueModal(true)}
handleUpdateIssue={handleUpdateIssue}
issue={issue}
mode={peekOverviewMode}
readOnly={readOnly}
setMode={(mode) => setPeekOverviewMode(mode)}
workspaceSlug={workspaceSlug}
/>
</Dialog.Panel>
</Transition.Child>
</div>
</Dialog>
</Transition.Root>
<Transition.Root appear show={isModalPeekOpen} as={React.Fragment}>
<Dialog as="div" className="relative z-20" onClose={handleClose}>
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-custom-backdrop bg-opacity-50 transition-opacity" />
</Transition.Child>
<div className="fixed inset-0 z-20 h-full w-full overflow-y-auto">
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
@ -139,55 +150,42 @@ export const IssuePeekOverview: React.FC<Props> = observer(
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-custom-backdrop bg-opacity-50 transition-opacity" />
<Dialog.Panel>
<div
className={`fixed z-20 bg-custom-background-100 top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 rounded-lg shadow-custom-shadow-xl transition-all duration-300 ${
peekOverviewMode === "modal" ? "h-[70%] w-3/5" : "h-[95%] w-[95%]"
}`}
>
{peekOverviewMode === "modal" && (
<SidePeekView
handleClose={handleClose}
handleDeleteIssue={() => setDeleteIssueModal(true)}
handleUpdateIssue={handleUpdateIssue}
issue={issue}
mode={peekOverviewMode}
readOnly={readOnly}
setMode={(mode) => setPeekOverviewMode(mode)}
workspaceSlug={workspaceSlug}
/>
)}
{peekOverviewMode === "full" && (
<FullScreenPeekView
handleClose={handleClose}
handleDeleteIssue={() => setDeleteIssueModal(true)}
handleUpdateIssue={handleUpdateIssue}
issue={issue}
mode={peekOverviewMode}
readOnly={readOnly}
setMode={(mode) => setPeekOverviewMode(mode)}
workspaceSlug={workspaceSlug}
/>
)}
</div>
</Dialog.Panel>
</Transition.Child>
<div className="fixed inset-0 z-20 h-full w-full overflow-y-auto">
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Dialog.Panel>
<div
className={`fixed z-20 bg-custom-background-100 top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 rounded-lg shadow-custom-shadow-xl transition-all duration-300 ${
peekOverviewMode === "modal" ? "h-[70%] w-3/5" : "h-[95%] w-[95%]"
}`}
>
{peekOverviewMode === "modal" && (
<SidePeekView
handleClose={handleClose}
handleDeleteIssue={() => setDeleteIssueModal(true)}
handleUpdateIssue={handleUpdateIssue}
issue={issue}
mode={peekOverviewMode}
readOnly={readOnly}
setMode={(mode) => setPeekOverviewMode(mode)}
workspaceSlug={workspaceSlug}
/>
)}
{peekOverviewMode === "full" && (
<FullScreenPeekView
handleClose={handleClose}
handleDeleteIssue={() => setDeleteIssueModal(true)}
handleUpdateIssue={handleUpdateIssue}
issue={issue}
mode={peekOverviewMode}
readOnly={readOnly}
setMode={(mode) => setPeekOverviewMode(mode)}
workspaceSlug={workspaceSlug}
/>
)}
</div>
</Dialog.Panel>
</Transition.Child>
</div>
</Dialog>
</Transition.Root>
</>
);
}
);
</div>
</Dialog>
</Transition.Root>
</>
);
});

View File

@ -0,0 +1,118 @@
// Workspace Events
export const CREATE_WORKSPACE = "CREATE_WORKSPACE";
export const UPDATE_WORKSPACE = "UPDATE_WORKSPACE";
export const DELETE_WORKSPACE = "DELETE_WORKSPACE";
// Workspace invite related
export const WORKSPACE_USER_INVITE = "WORKSPACE_USER_INVITE";
export const WORKSPACE_USER_INVITE_ACCEPT = "WORKSPACE_USER_INVITE_ACCEPT";
export const WORKSPACE_USER_BULK_INVITE_ACCEPT = "WORKSPACE_USER_BULK_INVITE_ACCEPT";
// Project Events
export const CREATE_PROJECT = "CREATE_PROJECT";
export const UPDATE_PROJECT = "UPDATE_PROJECT";
export const DELETE_PROJECT = "DELETE_PROJECT";
export const PROJECT_MEMBER_INVITE = "PROJECT_MEMBER_INVITE";
// Issue Events
export const ISSUE_CREATE = "ISSUE_CREATE";
export const ISSUE_UPDATE = "ISSUE_UPDATE";
export const ISSUE_DELETE = "ISSUE_DELETE";
// Cycle Events
export const CYCLE_CREATE = "CYCLE_CREATE";
export const CYCLE_UPDATE = "CYCLE_UPDATE";
export const CYCLE_DELETE = "CYCLE_DELETE";
// State Events
export const STATE_CREATE = "STATE_CREATE";
export const STATE_UPDATE = "STATE_UPDATE";
export const STATE_DELETE = "STATE_DELETE";
// Module Events
export const MODULE_CREATE = "MODULE_CREATE";
export const MODULE_UPDATE = "MODULE_UPDATE";
export const MODULE_DELETE = "MODULE_DELETE";
// Pages Events
export const PAGE_CREATE = "PAGE_CREATE";
export const PAGE_UPDATE = "PAGE_UPDATE";
export const PAGE_DELETE = "PAGE_DELETE";
// View Events
export const VIEW_CREATE = "VIEW_CREATE";
export const VIEW_UPDATE = "VIEW_UPDATE";
export const VIEW_DELETE = "VIEW_DELETE";
// Issue Comment Events
export const ISSUE_COMMENT_CREATE = "ISSUE_COMMENT_CREATE";
export const ISSUE_COMMENT_UPDATE = "ISSUE_COMMENT_UPDATE";
export const ISSUE_COMMENT_DELETE = "ISSUE_COMMENT_DELETE";
// Miscellaneous Events
export const TOGGLE_CYCLE_ON = "TOGGLE_CYCLE_ON";
export const TOGGLE_CYCLE_OFF = "TOGGLE_CYCLE_OFF";
export const TOGGLE_MODULE_ON = "TOGGLE_MODULE_ON";
export const TOGGLE_MODULE_OFF = "TOGGLE_MODULE_OFF";
export const TOGGLE_VIEW_ON = "TOGGLE_VIEW_ON";
export const TOGGLE_VIEW_OFF = "TOGGLE_VIEW_OFF";
export const TOGGLE_PAGES_ON = "TOGGLE_PAGES_ON";
export const TOGGLE_PAGES_OFF = "TOGGLE_PAGES_OFF";
export const TOGGLE_STATE_ON = "TOGGLE_STATE_ON";
export const TOGGLE_STATE_OFF = "TOGGLE_STATE_OFF";
export const TOGGLE_INBOX_ON = "TOGGLE_INBOX_ON";
export const TOGGLE_INBOX_OFF = "TOGGLE_INBOX_OFF";
// Integration Events
export const ADD_WORKSPACE_INTEGRATION = "ADD_WORKSPACE_INTEGRATION";
export const REMOVE_WORKSPACE_INTEGRATION = "REMOVE_WORKSPACE_INTEGRATION";
// GitHub Sync Events
export const GITHUB_REPO_SYNC = "GITHUB_REPO_SYNC";
// Page Blocks Events
export const PAGE_BLOCK_CREATE = "PAGE_BLOCK_CREATE";
export const PAGE_BLOCK_UPDATE = "PAGE_BLOCK_UPDATE";
export const PAGE_BLOCK_DELETE = "PAGE_BLOCK_DELETE";
export const PAGE_BLOCK_CONVERTED_TO_ISSUE = "PAGE_BLOCK_CONVERTED_TO_ISSUE";
// Issue Label Events
export const ISSUE_LABEL_CREATE = "ISSUE_LABEL_CREATE";
export const ISSUE_LABEL_UPDATE = "ISSUE_LABEL_UPDATE";
export const ISSUE_LABEL_DELETE = "ISSUE_LABEL_DELETE";
// GPT Events
export const ASK_GPT = "ASK_GPT";
export const USE_GPT_RESPONSE_IN_ISSUE = "USE_GPT_RESPONSE_IN_ISSUE";
export const USE_GPT_RESPONSE_IN_PAGE_BLOCK = "USE_GPT_RESPONSE_IN_PAGE_BLOCK";
// Issue Estimate Events
export const ESTIMATE_CREATE = "ESTIMATE_CREATE";
export const ESTIMATE_UPDATE = "ESTIMATE_UPDATE";
export const ESTIMATE_DELETE = "ESTIMATE_DELETE";
// Inbox Events
export const INBOX_CREATE = "INBOX_CREATE";
export const INBOX_UPDATE = "INBOX_UPDATE";
export const INBOX_DELETE = "INBOX_DELETE";
export const INBOX_ISSUE_CREATE = "INBOX_ISSUE_CREATE";
export const INBOX_ISSUE_UPDATE = "INBOX_ISSUE_UPDATE";
export const INBOX_ISSUE_DELETE = "INBOX_ISSUE_DELETE";
export const INBOX_ISSUE_DUPLICATED = "INBOX_ISSUE_DUPLICATED";
export const INBOX_ISSUE_ACCEPTED = "INBOX_ISSUE_ACCEPTED";
export const INBOX_ISSUE_SNOOZED = "INBOX_ISSUE_SNOOZED";
export const INBOX_ISSUE_REJECTED = "INBOX_ISSUE_REJECTED";
// Importer Events
export const GITHUB_IMPORTER_CREATE = "GITHUB_IMPORTER_CREATE";
export const GITHUB_IMPORTER_DELETE = "GITHUB_IMPORTER_DELETE";
export const JIRA_IMPORTER_CREATE = "JIRA_IMPORTER_CREATE";
export const JIRA_IMPORTER_DELETE = "JIRA_IMPORTER_DELETE";
// Exporter Events
export const CSV_EXPORTER_CREATE = "CSV_EXPORTER_CREATE";
// Analytics Events
export const WORKSPACE_SCOPE_AND_DEMAND_ANALYTICS = "WORKSPACE_SCOPE_AND_DEMAND_ANALYTICS";
export const WORKSPACE_CUSTOM_ANALYTICS = "WORKSPACE_CUSTOM_ANALYTICS";
export const WORKSPACE_ANALYTICS_EXPORT = "WORKSPACE_ANALYTICS_EXPORT";
// Project Analytics
export const PROJECT_SCOPE_AND_DEMAND_ANALYTICS = "PROJECT_SCOPE_AND_DEMAND_ANALYTICS";
export const PROJECT_CUSTOM_ANALYTICS = "PROJECT_CUSTOM_ANALYTICS";
export const PROJECT_ANALYTICS_EXPORT = "PROJECT_ANALYTICS_EXPORT";
// Cycle Custom
export const CYCLE_SCOPE_AND_DEMAND_ANALYTICS = "CYCLE_SCOPE_AND_DEMAND_ANALYTICS";
export const CYCLE_CUSTOM_ANALYTICS = "CYCLE_CUSTOM_ANALYTICS";
export const CYCLE_ANALYTICS_EXPORT = "CYCLE_ANALYTICS_EXPORT";
// Module Custom
export const MODULE_SCOPE_AND_DEMAND_ANALYTICS = "MODULE_SCOPE_AND_DEMAND_ANALYTICS";
export const MODULE_CUSTOM_ANALYTICS = "MODULE_CUSTOM_ANALYTICS";
export const MODULE_ANALYTICS_EXPORT = "MODULE_ANALYTICS_EXPORT";
// Reaction Events
export const ISSUE_REACTION_CREATE = "ISSUE_REACTION_CREATE";
export const ISSUE_COMMENT_REACTION_CREATE = "ISSUE_COMMENT_REACTION_CREATE";
export const ISSUE_REACTION_DELETE = "ISSUE_REACTION_DELETE";
export const ISSUE_COMMENT_REACTION_DELETE = "ISSUE_COMMENT_REACTION_DELETE";
// Leave Project/Workspace
export const PROJECT_MEMBER_LEAVE = "PROJECT_MEMBER_LEAVE";
export const WORKSPACE_MEMBER_LEAVE = "WORKSPACE_MEMBER_LEAVE";

View File

@ -6,7 +6,7 @@ import userService from "services/user.service";
// constants
import { CURRENT_USER } from "constants/fetch-keys";
// types
import type { ICurrentUserResponse, IUser } from "types";
import type { ICurrentUserResponse } from "types";
export default function useUser({ redirectTo = "", redirectIfFound = false, options = {} } = {}) {
const router = useRouter();

84
web/lib/app-providers.tsx Normal file
View File

@ -0,0 +1,84 @@
import { useEffect } from "react";
import dynamic from "next/dynamic";
import Router, { useRouter } from "next/router";
import { ThemeProvider } from "next-themes";
import NProgress from "nprogress";
import posthog from "posthog-js";
import { PostHogProvider } from "posthog-js/react";
// mobx store provider
import { MobxStoreProvider } from "lib/mobx/store-provider";
import MobxStoreInit from "lib/mobx/store-init";
// constants
import { THEMES } from "constants/themes";
// contexts
import { ToastContextProvider } from "contexts/toast.context";
import useUser from "hooks/use-user";
const CrispWithNoSSR = dynamic(() => import("constants/crisp"), { ssr: false });
// nprogress
NProgress.configure({ showSpinner: false });
Router.events.on("routeChangeStart", NProgress.start);
Router.events.on("routeChangeError", NProgress.done);
Router.events.on("routeChangeComplete", NProgress.done);
// Check that PostHog is client-side (used to handle Next.js SSR)
if (typeof window !== "undefined") {
posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY || "", {
api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST || "https://app.posthog.com",
// Enable debug mode in development
loaded: (posthog) => {
if (process.env.NODE_ENV === "development") posthog.debug();
},
autocapture: false,
capture_pageview: false, // Disable automatic pageview capture, as we capture manually
});
}
const AppProviders = (props: any) => {
const router = useRouter();
const { user } = useUser();
useEffect(() => {
if (user) {
// Identify sends an event, so you want may want to limit how often you call it
posthog?.identify(user.email, {
email: user.email,
first_name: user.first_name,
last_name: user.last_name,
id: user.id,
});
}
}, [user?.id]);
const RemainingProviders = (
<MobxStoreProvider {...props.pageProps}>
<ThemeProvider themes={THEMES} defaultTheme="system">
<ToastContextProvider>
<CrispWithNoSSR />
<MobxStoreInit />
{props.children}
</ToastContextProvider>
</ThemeProvider>
</MobxStoreProvider>
);
useEffect(() => {
// Track page views
const handleRouteChange = () => {
posthog?.capture("$pageview");
};
router.events.on("routeChangeComplete", handleRouteChange);
return () => {
router.events.off("routeChangeComplete", handleRouteChange);
};
}, []);
if (process.env.NEXT_PUBLIC_POSTHOG_KEY && process.env.NEXT_PUBLIC_POSTHOG_HOST) {
return <PostHogProvider client={posthog}>{RemainingProviders}</PostHogProvider>;
}
return <>{RemainingProviders}</>;
};
export default AppProviders;

View File

@ -64,6 +64,7 @@
"next-pwa": "^5.6.0",
"next-themes": "^0.2.1",
"nprogress": "^0.2.0",
"posthog-js": "^1.78.4",
"react": "18.2.0",
"react-beautiful-dnd": "^13.1.1",
"react-color": "^2.19.3",

View File

@ -28,6 +28,22 @@ import type { NextPage } from "next";
import { PROJECTS_LIST, PROJECT_DETAILS } from "constants/fetch-keys";
// helper
import { truncateText } from "helpers/string.helper";
//Posthog
import PosthogService from "services/posthog.service";
import {
TOGGLE_CYCLE_ON,
TOGGLE_CYCLE_OFF,
TOGGLE_MODULE_ON,
TOGGLE_MODULE_OFF,
TOGGLE_VIEW_ON,
TOGGLE_VIEW_OFF,
TOGGLE_PAGES_ON,
TOGGLE_PAGES_OFF,
TOGGLE_INBOX_ON,
TOGGLE_INBOX_OFF,
} from "constants/posthog-events";
const posthogService = new PosthogService();
const featuresList = [
{
@ -87,6 +103,23 @@ const getEventType = (feature: string, toggle: boolean): MiscellaneousEventType
}
};
const getPosthogEventType = (feature: string, toggle: boolean): MiscellaneousEventType => {
switch (feature) {
case "Cycles":
return toggle ? TOGGLE_CYCLE_ON : TOGGLE_CYCLE_OFF;
case "Modules":
return toggle ? TOGGLE_MODULE_ON : TOGGLE_MODULE_OFF;
case "Views":
return toggle ? TOGGLE_VIEW_ON : TOGGLE_VIEW_OFF;
case "Pages":
return toggle ? TOGGLE_PAGES_ON : TOGGLE_PAGES_OFF;
case "Inbox":
return toggle ? TOGGLE_INBOX_ON : TOGGLE_INBOX_OFF;
default:
throw new Error("Invalid feature");
}
};
const FeaturesSettings: NextPage = () => {
const router = useRouter();
const { workspaceSlug, projectId } = router.query;
@ -195,6 +228,20 @@ const FeaturesSettings: NextPage = () => {
),
user
);
posthogService.capture(
getPosthogEventType(
feature.title,
!projectDetails?.[feature.property as keyof IProject]
),
{
workspaceId: (projectDetails?.workspace as any)?.id,
workspaceSlug,
projectId,
projectIdentifier: projectDetails?.identifier,
projectName: projectDetails?.name,
},
user
);
handleSubmit({
[feature.property]: !projectDetails?.[feature.property as keyof IProject],
});

View File

@ -1,33 +1,16 @@
import Head from "next/head";
import dynamic from "next/dynamic";
import Router from "next/router";
import { ThemeProvider } from "next-themes";
import NProgress from "nprogress";
// styles
import "styles/globals.css";
import "styles/editor.css";
import "styles/command-pallette.css";
import "styles/nprogress.css";
import "styles/react-datepicker.css";
// contexts
import { ToastContextProvider } from "contexts/toast.context";
// types
import type { AppProps } from "next/app";
// constants
import { THEMES } from "constants/themes";
// constants
import { SITE_TITLE } from "constants/seo-variables";
// mobx store provider
import { MobxStoreProvider } from "lib/mobx/store-provider";
import MobxStoreInit from "lib/mobx/store-init";
const CrispWithNoSSR = dynamic(() => import("constants/crisp"), { ssr: false });
// nprogress
NProgress.configure({ showSpinner: false });
Router.events.on("routeChangeStart", NProgress.start);
Router.events.on("routeChangeError", NProgress.done);
Router.events.on("routeChangeComplete", NProgress.done);
//lib
import AppProviders from "lib/app-providers";
function MyApp({ Component, pageProps }: AppProps) {
return (
@ -35,15 +18,9 @@ function MyApp({ Component, pageProps }: AppProps) {
<Head>
<title>{SITE_TITLE}</title>
</Head>
<MobxStoreProvider {...pageProps}>
<ThemeProvider themes={THEMES} defaultTheme="system">
<ToastContextProvider>
<CrispWithNoSSR />
<MobxStoreInit />
<Component {...pageProps} />
</ToastContextProvider>
</ThemeProvider>
</MobxStoreProvider>
<AppProviders pageProps={pageProps}>
<Component {...pageProps} />
</AppProviders>
</>
);
}

View File

@ -4,6 +4,10 @@ import trackEventServices from "services/track-event.service";
import { ICurrentUserResponse, IGptResponse } from "types";
// helpers
import { API_BASE_URL } from "helpers/common.helper";
import PosthogService from "./posthog.service";
import { ASK_GPT } from "constants/posthog-events";
const posthogService = new PosthogService();
class AiServices extends APIService {
constructor() {
@ -19,6 +23,7 @@ class AiServices extends APIService {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/ai-assistant/`, data)
.then((response) => {
trackEventServices.trackAskGptEvent(response?.data, "ASK_GPT", user);
posthogService.capture(ASK_GPT, response?.data, user);
return response?.data;
})
.catch((error) => {

View File

@ -4,6 +4,10 @@ import trackEventServices from "services/track-event.service";
// types
import type { CycleDateCheckData, ICurrentUserResponse, ICycle, IIssue } from "types";
import { API_BASE_URL } from "helpers/common.helper";
import PosthogService from "./posthog.service";
import { CYCLE_CREATE, CYCLE_UPDATE, CYCLE_DELETE } from "constants/posthog-events";
const posthogService = new PosthogService();
class ProjectCycleServices extends APIService {
constructor() {
@ -19,6 +23,8 @@ class ProjectCycleServices extends APIService {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/`, data)
.then((response) => {
trackEventServices.trackCycleEvent(response?.data, "CYCLE_CREATE", user);
posthogService.capture(CYCLE_CREATE, response.data, user);
return response?.data;
})
.catch((error) => {
@ -97,6 +103,7 @@ class ProjectCycleServices extends APIService {
)
.then((response) => {
trackEventServices.trackCycleEvent(response?.data, "CYCLE_UPDATE", user);
posthogService.capture(CYCLE_UPDATE, response?.data, user);
return response?.data;
})
.catch((error) => {
@ -117,6 +124,7 @@ class ProjectCycleServices extends APIService {
)
.then((response) => {
trackEventServices.trackCycleEvent(response?.data, "CYCLE_UPDATE", user);
posthogService.capture(CYCLE_UPDATE, response?.data, user);
return response?.data;
})
.catch((error) => {
@ -133,6 +141,7 @@ class ProjectCycleServices extends APIService {
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/`)
.then((response) => {
trackEventServices.trackCycleEvent(response?.data, "CYCLE_DELETE", user);
posthogService.capture(CYCLE_DELETE, { workspaceSlug, projectId, cycleId }, user);
return response?.data;
})
.catch((error) => {

View File

@ -4,7 +4,10 @@ import APIService from "services/api.service";
import type { ICurrentUserResponse, IEstimate, IEstimateFormData } from "types";
import trackEventServices from "services/track-event.service";
import { API_BASE_URL } from "helpers/common.helper";
import PosthogService from "./posthog.service";
import { ESTIMATE_CREATE, ESTIMATE_UPDATE, ESTIMATE_DELETE } from "constants/posthog-events";
const posthogService = new PosthogService();
class ProjectEstimateServices extends APIService {
constructor() {
super(API_BASE_URL);
@ -19,6 +22,7 @@ class ProjectEstimateServices extends APIService {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/estimates/`, data)
.then((response) => {
trackEventServices.trackIssueEstimateEvent(response?.data, "ESTIMATE_CREATE", user);
posthogService.capture(ESTIMATE_CREATE, response?.data, user);
return response?.data;
})
.catch((error) => {
@ -39,6 +43,7 @@ class ProjectEstimateServices extends APIService {
)
.then((response) => {
trackEventServices.trackIssueEstimateEvent(response?.data, "ESTIMATE_UPDATE", user);
posthogService.capture(ESTIMATE_UPDATE, response?.data, user);
return response?.data;
})
.catch((error) => {
@ -79,6 +84,7 @@ class ProjectEstimateServices extends APIService {
)
.then((response) => {
trackEventServices.trackIssueEstimateEvent(response?.data, "ESTIMATE_DELETE", user);
posthogService.capture(ESTIMATE_DELETE, { workspaceSlug, projectId, estimateId }, user);
return response?.data;
})
.catch((error) => {

View File

@ -10,6 +10,14 @@ import type {
ICurrentUserResponse,
IInboxQueryParams,
} from "types";
import PosthogService from "./posthog.service";
import {
INBOX_ISSUE_CREATE,
INBOX_ISSUE_UPDATE,
INBOX_ISSUE_DELETE,
} from "constants/posthog-events";
const posthogService = new PosthogService();
class InboxServices extends APIService {
constructor() {
@ -91,6 +99,11 @@ class InboxServices extends APIService {
)
.then((response) => {
trackEventServices.trackInboxEvent(response?.data, "INBOX_ISSUE_DELETE", user);
posthogService.capture(
INBOX_ISSUE_DELETE,
{ workspaceSlug, projectId, inboxId, inboxIssueId },
user
);
return response?.data;
})
.catch((error) => {
@ -141,6 +154,7 @@ class InboxServices extends APIService {
)
.then((response) => {
trackEventServices.trackInboxEvent(response?.data, "INBOX_ISSUE_UPDATE", user);
posthogService.capture(INBOX_ISSUE_UPDATE, response?.data, user);
return response?.data;
})
.catch((error) => {
@ -161,6 +175,7 @@ class InboxServices extends APIService {
)
.then((response) => {
trackEventServices.trackInboxEvent(response?.data, "INBOX_ISSUE_CREATE", user);
posthogService.capture(INBOX_ISSUE_CREATE, response?.data, user);
return response?.data;
})
.catch((error) => {

View File

@ -2,7 +2,10 @@ import APIService from "services/api.service";
import trackEventServices from "services/track-event.service";
import { ICurrentUserResponse } from "types";
import { API_BASE_URL } from "helpers/common.helper";
import PosthogService from "../posthog.service";
import { CSV_EXPORTER_CREATE } from "constants/posthog-events";
const posthogService = new PosthogService();
class CSVIntegrationService extends APIService {
constructor() {
super(API_BASE_URL);
@ -25,6 +28,7 @@ class CSVIntegrationService extends APIService {
"CSV_EXPORTER_CREATE",
user
);
posthogService.capture(CSV_EXPORTER_CREATE, { workspaceSlug, data }, user);
return response?.data;
})
.catch((error) => {

View File

@ -3,6 +3,10 @@ import trackEventServices from "services/track-event.service";
import { API_BASE_URL } from "helpers/common.helper";
import { ICurrentUserResponse, IGithubRepoInfo, IGithubServiceImportFormData } from "types";
import PosthogService from "../posthog.service";
import { GITHUB_IMPORTER_CREATE } from "constants/posthog-events";
const posthogService = new PosthogService();
const integrationServiceType: string = "github";
class GithubIntegrationService extends APIService {
@ -44,6 +48,8 @@ class GithubIntegrationService extends APIService {
)
.then((response) => {
trackEventServices.trackImporterEvent(response?.data, "GITHUB_IMPORTER_CREATE", user);
posthogService.capture(GITHUB_IMPORTER_CREATE, response?.data, user);
return response?.data;
})
.catch((error) => {

View File

@ -3,6 +3,10 @@ import trackEventServices from "services/track-event.service";
import { API_BASE_URL } from "helpers/common.helper";
// types
import { IJiraMetadata, IJiraResponse, IJiraImporterForm, ICurrentUserResponse } from "types";
import PosthogService from "../posthog.service";
import { JIRA_IMPORTER_CREATE } from "constants/posthog-events";
const posthogService = new PosthogService();
class JiraImportedService extends APIService {
constructor() {
@ -27,6 +31,7 @@ class JiraImportedService extends APIService {
return this.post(`/api/workspaces/${workspaceSlug}/projects/importers/jira/`, data)
.then((response) => {
trackEventServices.trackImporterEvent(response?.data, "JIRA_IMPORTER_CREATE", user);
posthogService.capture(JIRA_IMPORTER_CREATE, response?.data, user);
return response?.data;
})
.catch((error) => {

View File

@ -11,6 +11,20 @@ import type {
ISubIssueResponse,
} from "types";
import { API_BASE_URL } from "helpers/common.helper";
import PosthogService from "./posthog.service";
import {
ISSUE_CREATE,
ISSUE_UPDATE,
ISSUE_DELETE,
ISSUE_COMMENT_CREATE,
ISSUE_COMMENT_UPDATE,
ISSUE_COMMENT_DELETE,
ISSUE_LABEL_CREATE,
ISSUE_LABEL_UPDATE,
ISSUE_LABEL_DELETE,
} from "constants/posthog-events";
const posthogService = new PosthogService();
class ProjectIssuesServices extends APIService {
constructor() {
@ -26,6 +40,7 @@ class ProjectIssuesServices extends APIService {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/`, data)
.then((response) => {
trackEventServices.trackIssueEvent(response.data, "ISSUE_CREATE", user);
posthogService.capture(ISSUE_CREATE, response.data, user);
return response?.data;
})
.catch((error) => {
@ -230,6 +245,7 @@ class ProjectIssuesServices extends APIService {
)
.then((response) => {
trackEventServices.trackIssueCommentEvent(response.data, "ISSUE_COMMENT_CREATE", user);
posthogService.capture(ISSUE_COMMENT_CREATE, response.data, user);
return response?.data;
})
.catch((error) => {
@ -251,6 +267,7 @@ class ProjectIssuesServices extends APIService {
)
.then((response) => {
trackEventServices.trackIssueCommentEvent(response.data, "ISSUE_COMMENT_UPDATE", user);
posthogService.capture(ISSUE_COMMENT_UPDATE, response.data, user);
return response?.data;
})
.catch((error) => {
@ -277,6 +294,15 @@ class ProjectIssuesServices extends APIService {
"ISSUE_COMMENT_DELETE",
user
);
posthogService.capture(
ISSUE_COMMENT_DELETE,
{
issueId,
commentId,
},
user
);
return response?.data;
})
.catch((error) => {
@ -322,6 +348,21 @@ class ProjectIssuesServices extends APIService {
"ISSUE_LABEL_CREATE",
user
);
posthogService.capture(
ISSUE_LABEL_CREATE,
{
workSpaceId: response?.data?.workspace_detail?.id,
workSpaceName: response?.data?.workspace_detail?.name,
workspaceSlug,
projectId,
projectIdentifier: response?.data?.project_detail?.identifier,
projectName: response?.data?.project_detail?.name,
labelId: response?.data?.id,
color: response?.data?.color,
},
user
);
return response?.data;
})
.catch((error) => {
@ -355,6 +396,21 @@ class ProjectIssuesServices extends APIService {
"ISSUE_LABEL_UPDATE",
user
);
posthogService.capture(
ISSUE_LABEL_UPDATE,
{
workSpaceId: response?.data?.workspace_detail?.id,
workSpaceName: response?.data?.workspace_detail?.name,
workspaceSlug,
projectId,
projectIdentifier: response?.data?.project_detail?.identifier,
projectName: response?.data?.project_detail?.name,
labelId: response?.data?.id,
color: response?.data?.color,
},
user
);
return response?.data;
})
.catch((error) => {
@ -380,6 +436,14 @@ class ProjectIssuesServices extends APIService {
"ISSUE_LABEL_DELETE",
user
);
posthogService.capture(
ISSUE_LABEL_DELETE,
{
workspaceSlug,
projectId,
},
user
);
return response?.data;
})
.catch((error) => {
@ -400,6 +464,7 @@ class ProjectIssuesServices extends APIService {
)
.then((response) => {
trackEventServices.trackIssueEvent(response.data, "ISSUE_UPDATE", user);
posthogService.capture(ISSUE_UPDATE, response.data, user);
return response?.data;
})
.catch((error) => {
@ -416,6 +481,7 @@ class ProjectIssuesServices extends APIService {
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issuesId}/`)
.then((response) => {
trackEventServices.trackIssueEvent({ issuesId }, "ISSUE_DELETE", user);
posthogService.capture(ISSUE_DELETE, response.data, user);
return response?.data;
})
.catch((error) => {

View File

@ -4,6 +4,10 @@ import trackEventServices from "./track-event.service";
// types
import type { IModule, IIssue, ICurrentUserResponse } from "types";
import { API_BASE_URL } from "helpers/common.helper";
import PosthogService from "./posthog.service";
import { MODULE_CREATE, MODULE_UPDATE, MODULE_DELETE } from "constants/posthog-events";
const posthogService = new PosthogService();
class ProjectIssuesServices extends APIService {
constructor() {
@ -27,6 +31,7 @@ class ProjectIssuesServices extends APIService {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/`, data)
.then((response) => {
trackEventServices.trackModuleEvent(response?.data, "MODULE_CREATE", user);
posthogService.capture(MODULE_CREATE, response?.data, user);
return response?.data;
})
.catch((error) => {
@ -47,6 +52,7 @@ class ProjectIssuesServices extends APIService {
)
.then((response) => {
trackEventServices.trackModuleEvent(response?.data, "MODULE_UPDATE", user);
posthogService.capture(MODULE_UPDATE, response?.data, user);
return response?.data;
})
.catch((error) => {
@ -79,6 +85,8 @@ class ProjectIssuesServices extends APIService {
)
.then((response) => {
trackEventServices.trackModuleEvent(response?.data, "MODULE_UPDATE", user);
posthogService.capture(MODULE_UPDATE, response?.data, user);
return response?.data;
})
.catch((error) => {
@ -97,6 +105,7 @@ class ProjectIssuesServices extends APIService {
)
.then((response) => {
trackEventServices.trackModuleEvent(response?.data, "MODULE_DELETE", user);
posthogService.capture(MODULE_DELETE, { workspaceSlug, projectId, moduleId }, user);
return response?.data;
})
.catch((error) => {

View File

@ -4,6 +4,18 @@ import APIService from "services/api.service";
import trackEventServices from "services/track-event.service";
// types
import { IPage, IPageBlock, RecentPagesResponse, IIssue, ICurrentUserResponse } from "types";
import PosthogService from "./posthog.service";
import {
PAGE_CREATE,
PAGE_UPDATE,
PAGE_DELETE,
PAGE_BLOCK_CREATE,
PAGE_BLOCK_UPDATE,
PAGE_BLOCK_DELETE,
PAGE_BLOCK_CONVERTED_TO_ISSUE,
} from "constants/posthog-events";
const posthogService = new PosthogService();
class PageServices extends APIService {
constructor() {
@ -19,6 +31,7 @@ class PageServices extends APIService {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/`, data)
.then((response) => {
trackEventServices.trackPageEvent(response?.data, "PAGE_CREATE", user);
posthogService.capture(PAGE_CREATE, response?.data, user);
return response?.data;
})
.catch((error) => {
@ -39,6 +52,7 @@ class PageServices extends APIService {
)
.then((response) => {
trackEventServices.trackPageEvent(response?.data, "PAGE_UPDATE", user);
posthogService.capture(PAGE_UPDATE, response?.data, user);
return response?.data;
})
.catch((error) => {
@ -55,6 +69,7 @@ class PageServices extends APIService {
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/`)
.then((response) => {
trackEventServices.trackPageEvent(response?.data, "PAGE_DELETE", user);
posthogService.capture(PAGE_DELETE, { workspaceSlug, projectId, pageId }, user);
return response?.data;
})
.catch((error) => {
@ -138,6 +153,7 @@ class PageServices extends APIService {
)
.then((response) => {
trackEventServices.trackPageBlockEvent(response?.data, "PAGE_BLOCK_CREATE", user);
posthogService.capture(PAGE_BLOCK_CREATE, response?.data, user);
return response?.data;
})
.catch((error) => {
@ -174,6 +190,7 @@ class PageServices extends APIService {
)
.then((response) => {
trackEventServices.trackPageBlockEvent(response?.data, "PAGE_BLOCK_UPDATE", user);
posthogService.capture(PAGE_BLOCK_UPDATE, response?.data, user);
return response?.data;
})
.catch((error) => {
@ -193,6 +210,11 @@ class PageServices extends APIService {
)
.then((response) => {
trackEventServices.trackPageBlockEvent(response?.data, "PAGE_BLOCK_DELETE", user);
posthogService.capture(
PAGE_BLOCK_DELETE,
{ workspaceSlug, projectId, pageId, pageBlockId },
user
);
return response?.data;
})
.catch((error) => {
@ -230,6 +252,7 @@ class PageServices extends APIService {
"PAGE_BLOCK_CONVERTED_TO_ISSUE",
user
);
posthogService.capture(PAGE_BLOCK_CONVERTED_TO_ISSUE, response?.data, user);
return response?.data;
})
.catch((error) => {

View File

@ -0,0 +1,27 @@
import APIService from "./api.service";
class PosthogService extends APIService {
constructor() {
super("");
}
capture(event: string, data: any = {}, user: any = {}) {
this.request({
method: "post",
url: `${process.env.NEXT_PUBLIC_POSTHOG_HOST || ""}/capture/`,
headers: {
"Content-Type": "application/json",
},
data: {
api_key: process.env.NEXT_PUBLIC_POSTHOG_KEY,
properties: {
user,
...data,
},
distinct_id: user?.email,
event,
},
});
}
}
export default PosthogService;

View File

@ -15,6 +15,16 @@ import type {
IProjectViewProps,
TProjectIssuesSearchParams,
} from "types";
import PosthogService from "./posthog.service";
import {
CREATE_PROJECT,
UPDATE_PROJECT,
DELETE_PROJECT,
PROJECT_MEMBER_INVITE,
PROJECT_MEMBER_LEAVE,
} from "constants/posthog-events";
const posthogService = new PosthogService();
export class ProjectServices extends APIService {
constructor() {
@ -29,6 +39,7 @@ export class ProjectServices extends APIService {
return this.post(`/api/workspaces/${workspaceSlug}/projects/`, data)
.then((response) => {
trackEventServices.trackProjectEvent(response.data, "CREATE_PROJECT", user);
posthogService.capture(CREATE_PROJECT, response.data, user);
return response?.data;
})
.catch((error) => {
@ -80,6 +91,7 @@ export class ProjectServices extends APIService {
return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/`, data)
.then((response) => {
trackEventServices.trackProjectEvent(response.data, "UPDATE_PROJECT", user);
posthogService.capture(UPDATE_PROJECT, response.data, user);
return response?.data;
})
.catch((error) => {
@ -95,6 +107,7 @@ export class ProjectServices extends APIService {
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/`)
.then((response) => {
trackEventServices.trackProjectEvent({ projectId }, "DELETE_PROJECT", user);
posthogService.capture(DELETE_PROJECT, response.data, user);
return response?.data;
})
.catch((error) => {
@ -121,6 +134,17 @@ export class ProjectServices extends APIService {
"PROJECT_MEMBER_INVITE",
user
);
posthogService.capture(
PROJECT_MEMBER_INVITE,
{
workspaceId: response?.data?.workspace?.id,
workspaceSlug,
projectId,
projectName: response?.data?.project?.name,
memberEmail: response?.data?.member?.email,
},
user
);
return response?.data;
})
.catch((error) => {
@ -152,6 +176,16 @@ export class ProjectServices extends APIService {
},
user
);
posthogService.capture(
PROJECT_MEMBER_LEAVE,
{
workspaceSlug,
projectId,
...response?.data,
},
user
);
return response?.data;
})
.catch((error) => {

View File

@ -10,6 +10,15 @@ import type {
IssueReactionForm,
IssueCommentReactionForm,
} from "types";
import PosthogService from "./posthog.service";
import {
ISSUE_REACTION_CREATE,
ISSUE_COMMENT_REACTION_CREATE,
ISSUE_REACTION_DELETE,
ISSUE_COMMENT_REACTION_DELETE,
} from "constants/posthog-events";
const posthogService = new PosthogService();
class ReactionService extends APIService {
constructor() {
@ -29,6 +38,8 @@ class ReactionService extends APIService {
)
.then((response) => {
trackEventServices.trackReactionEvent(response?.data, "ISSUE_REACTION_CREATE", user);
posthogService.capture(ISSUE_REACTION_CREATE, response?.data, user);
return response?.data;
})
.catch((error) => {
@ -62,6 +73,8 @@ class ReactionService extends APIService {
)
.then((response) => {
trackEventServices.trackReactionEvent(response?.data, "ISSUE_REACTION_DELETE", user);
posthogService.capture(ISSUE_REACTION_DELETE, { workspaceSlug, projectId, issueId, reaction }, user);
return response?.data;
})
.catch((error) => {
@ -86,6 +99,7 @@ class ReactionService extends APIService {
"ISSUE_COMMENT_REACTION_CREATE",
user
);
posthogService.capture(ISSUE_COMMENT_REACTION_CREATE, response?.data, user);
return response?.data;
})
.catch((error) => {
@ -123,6 +137,12 @@ class ReactionService extends APIService {
"ISSUE_COMMENT_REACTION_DELETE",
user
);
posthogService.capture(
ISSUE_COMMENT_REACTION_DELETE,
{ workspaceSlug, projectId, commentId, reaction },
user
);
return response?.data;
})
.catch((error) => {

View File

@ -5,6 +5,10 @@ import trackEventServices from "services/track-event.service";
import { API_BASE_URL } from "helpers/common.helper";
// types
import type { ICurrentUserResponse, IState, IStateResponse } from "types";
import PosthogService from "./posthog.service";
import { STATE_CREATE, STATE_UPDATE, STATE_DELETE } from "constants/posthog-events";
const posthogService = new PosthogService();
class ProjectStateServices extends APIService {
constructor() {
@ -20,6 +24,7 @@ class ProjectStateServices extends APIService {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/states/`, data)
.then((response) => {
trackEventServices.trackStateEvent(response?.data, "STATE_CREATE", user);
posthogService.capture(STATE_CREATE, response.data, user);
return response?.data;
})
.catch((error) => {
@ -65,6 +70,7 @@ class ProjectStateServices extends APIService {
)
.then((response) => {
trackEventServices.trackStateEvent(response?.data, "STATE_UPDATE", user);
posthogService.capture(STATE_UPDATE, response?.data, user);
return response?.data;
})
.catch((error) => {
@ -85,6 +91,7 @@ class ProjectStateServices extends APIService {
)
.then((response) => {
trackEventServices.trackStateEvent(response?.data, "STATE_UPDATE", user);
posthogService.capture(STATE_UPDATE, response?.data, user);
return response?.data;
})
.catch((error) => {
@ -101,6 +108,7 @@ class ProjectStateServices extends APIService {
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/states/${stateId}/`)
.then((response) => {
trackEventServices.trackStateEvent(response?.data, "STATE_DELETE", user);
posthogService.capture(STATE_DELETE, { workspaceSlug, projectId, stateId }, user);
return response?.data;
})
.catch((error) => {

View File

@ -5,6 +5,10 @@ import { IView } from "types/views";
import { ICurrentUserResponse } from "types";
// helpers
import { API_BASE_URL } from "helpers/common.helper";
import PosthogService from "./posthog.service";
import { VIEW_CREATE, VIEW_UPDATE, VIEW_DELETE } from "constants/posthog-events";
const posthogService = new PosthogService();
class ViewServices extends APIService {
constructor() {
@ -20,6 +24,7 @@ class ViewServices extends APIService {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/views/`, data)
.then((response) => {
trackEventServices.trackViewEvent(response?.data, "VIEW_CREATE", user);
posthogService.capture(VIEW_CREATE, response?.data, user);
return response?.data;
})
.catch((error) => {
@ -37,6 +42,8 @@ class ViewServices extends APIService {
return this.put(`/api/workspaces/${workspaceSlug}/projects/${projectId}/views/${viewId}/`, data)
.then((response) => {
trackEventServices.trackViewEvent(response?.data, "VIEW_UPDATE", user);
posthogService.capture(VIEW_UPDATE, response?.data, user);
return response?.data;
})
.catch((error) => {
@ -57,6 +64,8 @@ class ViewServices extends APIService {
)
.then((response) => {
trackEventServices.trackViewEvent(response?.data, "VIEW_UPDATE", user);
posthogService.capture(VIEW_UPDATE, response?.data, user);
return response?.data;
})
.catch((error) => {
@ -73,6 +82,8 @@ class ViewServices extends APIService {
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/views/${viewId}/`)
.then((response) => {
trackEventServices.trackViewEvent(response?.data, "VIEW_DELETE", user);
posthogService.capture(VIEW_DELETE, { workspaceSlug, projectId, viewId }, user);
return response?.data;
})
.catch((error) => {

View File

@ -15,6 +15,18 @@ import {
IWorkspaceBulkInviteFormData,
IWorkspaceViewProps,
} from "types";
import PosthogService from "./posthog.service";
import {
CREATE_WORKSPACE,
UPDATE_WORKSPACE,
DELETE_WORKSPACE,
WORKSPACE_USER_INVITE,
WORKSPACE_USER_INVITE_ACCEPT,
WORKSPACE_USER_BULK_INVITE_ACCEPT,
WORKSPACE_MEMBER_LEAVE,
} from "constants/posthog-events";
const posthogService = new PosthogService();
class WorkspaceService extends APIService {
constructor() {
@ -44,6 +56,7 @@ class WorkspaceService extends APIService {
return this.post("/api/workspaces/", data)
.then((response) => {
trackEventServices.trackWorkspaceEvent(response.data, "CREATE_WORKSPACE", user);
posthogService.capture(CREATE_WORKSPACE, response.data, user);
return response?.data;
})
.catch((error) => {
@ -59,6 +72,7 @@ class WorkspaceService extends APIService {
return this.patch(`/api/workspaces/${workspaceSlug}/`, data)
.then((response) => {
trackEventServices.trackWorkspaceEvent(response.data, "UPDATE_WORKSPACE", user);
posthogService.capture(UPDATE_WORKSPACE, response.data, user);
return response?.data;
})
.catch((error) => {
@ -73,6 +87,7 @@ class WorkspaceService extends APIService {
return this.delete(`/api/workspaces/${workspaceSlug}/`)
.then((response) => {
trackEventServices.trackWorkspaceEvent({ workspaceSlug }, "DELETE_WORKSPACE", user);
posthogService.capture(DELETE_WORKSPACE, { workspaceSlug }, user);
return response?.data;
})
.catch((error) => {
@ -88,6 +103,7 @@ class WorkspaceService extends APIService {
return this.post(`/api/workspaces/${workspaceSlug}/invite/`, data)
.then((response) => {
trackEventServices.trackWorkspaceEvent(response.data, "WORKSPACE_USER_INVITE", user);
posthogService.capture(WORKSPACE_USER_INVITE, response.data, user);
return response?.data;
})
.catch((error) => {
@ -110,6 +126,7 @@ class WorkspaceService extends APIService {
)
.then((response) => {
trackEventServices.trackWorkspaceEvent(response.data, "WORKSPACE_USER_INVITE_ACCEPT", user);
posthogService.capture(WORKSPACE_USER_INVITE_ACCEPT, response.data, user);
return response?.data;
})
.catch((error) => {
@ -190,7 +207,10 @@ class WorkspaceService extends APIService {
async deleteWorkspaceMember(workspaceSlug: string, memberId: string): Promise<any> {
return this.delete(`/api/workspaces/${workspaceSlug}/members/${memberId}/`)
.then((response) => response?.data)
.then((response) => {
posthogService.capture(WORKSPACE_MEMBER_LEAVE, { workspaceSlug, memberId });
return response?.data;
})
.catch((error) => {
throw error?.response?.data;
});

View File

@ -1,4 +1,3 @@
// mobx
import { action, observable, runInAction, makeAutoObservable } from "mobx";
// services
import issueService from "services/issues.service";

View File

@ -4465,6 +4465,11 @@ fault@^2.0.0:
dependencies:
format "^0.2.0"
fflate@^0.4.1:
version "0.4.8"
resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.4.8.tgz#f90b82aefbd8ac174213abb338bd7ef848f0f5ae"
integrity sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==
file-entry-cache@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027"
@ -6487,6 +6492,13 @@ postcss@^8.4.23, postcss@^8.4.29:
picocolors "^1.0.0"
source-map-js "^1.0.2"
posthog-js@^1.78.4:
version "1.78.4"
resolved "https://registry.yarnpkg.com/posthog-js/-/posthog-js-1.78.4.tgz#082d976e84770fa3c7b16c3005ee4bcb4692119a"
integrity sha512-+ao0/qoP8fUErrF6Y2Yugilkh4ooh8MX6n6ckYsn3yV610YrpXGR165fbq8X1ukimV4YmkWbMHOACtkOuZ/+8w==
dependencies:
fflate "^0.4.1"
prebuild-install@^7.1.1:
version "7.1.1"
resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-7.1.1.tgz#de97d5b34a70a0c81334fd24641f2a1702352e45"
@ -6644,7 +6656,7 @@ prosemirror-model@^1.0.0, prosemirror-model@^1.16.0, prosemirror-model@^1.18.1,
prosemirror-model@^1.19.0:
version "1.19.3"
resolved "https://registry.yarnpkg.com/prosemirror-model/-/prosemirror-model-1.19.3.tgz#f0d55285487fefd962d0ac695f716f4ec6705006"
resolved "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.19.3.tgz#f0d55285487fefd962d0ac695f716f4ec6705006"
integrity sha512-tgSnwN7BS7/UM0sSARcW+IQryx2vODKX4MI7xpqY2X+iaepJdKBPc7I4aACIsDV/LTaTjt12Z56MhDr9LsyuZQ==
dependencies:
orderedmap "^2.0.0"