fix: posthog integration fixes

This commit is contained in:
sriram veeraghanta 2023-09-14 21:38:00 +05:30
parent 759a604cb8
commit df62c97579
8 changed files with 222 additions and 44 deletions

View File

@ -1,10 +1,6 @@
import React, { useEffect, useState, useCallback } from "react"; import React, { useEffect, useState, useCallback } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { mutate } from "swr"; import { mutate } from "swr";
// headless ui
import { Dialog, Transition } from "@headlessui/react"; import { Dialog, Transition } from "@headlessui/react";
// services // services
import modulesService from "services/modules.service"; import modulesService from "services/modules.service";
@ -38,6 +34,8 @@ import {
} from "constants/fetch-keys"; } from "constants/fetch-keys";
// constants // constants
import { INBOX_ISSUE_SOURCE } from "constants/inbox"; import { INBOX_ISSUE_SOURCE } from "constants/inbox";
import { usePostHog } from "posthog-js/react";
import { ISSUE_CREATE } from "constants/posthog-events";
export interface IssuesModalProps { export interface IssuesModalProps {
data?: IIssue | null; data?: IIssue | null;
@ -71,6 +69,7 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = ({
fieldsToShow = ["all"], fieldsToShow = ["all"],
onSubmit, onSubmit,
}) => { }) => {
const posthog = usePostHog();
// states // states
const [createMore, setCreateMore] = useState(false); const [createMore, setCreateMore] = useState(false);
const [activeProject, setActiveProject] = useState<string | null>(null); const [activeProject, setActiveProject] = useState<string | null>(null);
@ -242,6 +241,7 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = ({
await issuesService await issuesService
.createIssues(workspaceSlug as string, activeProject ?? "", payload, user) .createIssues(workspaceSlug as string, activeProject ?? "", payload, user)
.then(async (res) => { .then(async (res) => {
posthog?.capture(ISSUE_CREATE);
mutate(PROJECT_ISSUES_LIST_WITH_PARAMS(activeProject ?? "", params)); mutate(PROJECT_ISSUES_LIST_WITH_PARAMS(activeProject ?? "", params));
if (payload.cycle && payload.cycle !== "") await addIssueToCycle(res.id, payload.cycle); if (payload.cycle && payload.cycle !== "") await addIssueToCycle(res.id, payload.cycle);
if (payload.module && payload.module !== "") if (payload.module && payload.module !== "")

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

@ -1,15 +1,17 @@
import { useEffect } from "react"; import { useEffect } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { usePostHog } from "posthog-js/react";
import useSWR from "swr"; import useSWR from "swr";
// services // services
import userService from "services/user.service"; import userService from "services/user.service";
// constants // constants
import { CURRENT_USER } from "constants/fetch-keys"; import { CURRENT_USER } from "constants/fetch-keys";
// types // types
import type { ICurrentUserResponse, IUser } from "types"; import type { ICurrentUserResponse } from "types";
export default function useUser({ redirectTo = "", redirectIfFound = false, options = {} } = {}) { export default function useUser({ redirectTo = "", redirectIfFound = false, options = {} } = {}) {
const router = useRouter(); const router = useRouter();
const posthog = usePostHog();
// API to fetch user information // API to fetch user information
const { data, isLoading, error, mutate } = useSWR<ICurrentUserResponse>( const { data, isLoading, error, mutate } = useSWR<ICurrentUserResponse>(
CURRENT_USER, CURRENT_USER,

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-pwa": "^5.6.0",
"next-themes": "^0.2.1", "next-themes": "^0.2.1",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
"posthog-js": "^1.78.4",
"react": "18.2.0", "react": "18.2.0",
"react-beautiful-dnd": "^13.1.1", "react-beautiful-dnd": "^13.1.1",
"react-color": "^2.19.3", "react-color": "^2.19.3",

View File

@ -1,33 +1,16 @@
import Head from "next/head"; 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 // styles
import "styles/globals.css"; import "styles/globals.css";
import "styles/editor.css"; import "styles/editor.css";
import "styles/command-pallette.css"; import "styles/command-pallette.css";
import "styles/nprogress.css"; import "styles/nprogress.css";
import "styles/react-datepicker.css"; import "styles/react-datepicker.css";
// contexts
import { ToastContextProvider } from "contexts/toast.context";
// types // types
import type { AppProps } from "next/app"; import type { AppProps } from "next/app";
// constants // constants
import { THEMES } from "constants/themes";
// constants
import { SITE_TITLE } from "constants/seo-variables"; import { SITE_TITLE } from "constants/seo-variables";
// mobx store provider //lib
import { MobxStoreProvider } from "lib/mobx/store-provider"; import AppProviders from "lib/app-providers";
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);
function MyApp({ Component, pageProps }: AppProps) { function MyApp({ Component, pageProps }: AppProps) {
return ( return (
@ -35,15 +18,9 @@ function MyApp({ Component, pageProps }: AppProps) {
<Head> <Head>
<title>{SITE_TITLE}</title> <title>{SITE_TITLE}</title>
</Head> </Head>
<MobxStoreProvider {...pageProps}> <AppProviders pageProps={pageProps}>
<ThemeProvider themes={THEMES} defaultTheme="system"> <Component {...pageProps} />
<ToastContextProvider> </AppProviders>
<CrispWithNoSSR />
<MobxStoreInit />
<Component {...pageProps} />
</ToastContextProvider>
</ThemeProvider>
</MobxStoreProvider>
</> </>
); );
} }

View File

@ -32,10 +32,6 @@ class MyDocument extends Document {
<link rel="icon" type="image/png" sizes="16x16" href="/favicon/favicon-16x16.png" /> <link rel="icon" type="image/png" sizes="16x16" href="/favicon/favicon-16x16.png" />
<link rel="manifest" href="/site.webmanifest.json" /> <link rel="manifest" href="/site.webmanifest.json" />
<link rel="shortcut icon" href="/favicon/favicon.ico" /> <link rel="shortcut icon" href="/favicon/favicon.ico" />
</Head>
<body>
<Main />
<NextScript />
{process.env.NEXT_PUBLIC_PLAUSIBLE_DOMAIN && ( {process.env.NEXT_PUBLIC_PLAUSIBLE_DOMAIN && (
<script <script
defer defer
@ -49,15 +45,13 @@ class MyDocument extends Document {
c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)}; c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)};
t=l.createElement(r);t.async=1;t.src="https://www.clarity.ms/tag/"+i; t=l.createElement(r);t.async=1;t.src="https://www.clarity.ms/tag/"+i;
y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y); y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y);
})(window, document, "clarity", "script", "${process.env.NEXT_PUBLIC_SESSION_RECORDER_KEY}");`} })(window, document, "clarity", "script", "${process.env.NEXT_PUBLIC_SESSION_RECORDER_KEY}");`}
</Script>
)}
{process.env.NEXT_PUBLIC_POSTHOG_KEY && process.env.NEXT_PUBLIC_POSTHOG_HOST && (
<Script id="posthog-tracking">
{`!function(t,e){var o,n,p,r;e.__SV||(window.posthog=e,e._i=[],e.init=function(i,s,a){function g(t,e){var o=e.split(".");2==o.length&&(t=t[o[0]],e=o[1]),t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}}(p=t.createElement("script")).type="text/javascript",p.async=!0,p.src=s.api_host+"/static/array.js",(r=t.getElementsByTagName("script")[0]).parentNode.insertBefore(p,r);var u=e;for(void 0!==a?u=e[a]=[]:a="posthog",u.people=u.people||[],u.toString=function(t){var e="posthog";return"posthog"!==a&&(e+="."+a),t||(e+=" (stub)"),e},u.people.toString=function(){return u.toString(1)+".people (stub)"},o="capture identify alias people.set people.set_once set_config register register_once unregister opt_out_capturing has_opted_out_capturing opt_in_capturing reset isFeatureEnabled onFeatureFlags getFeatureFlag getFeatureFlagPayload reloadFeatureFlags group updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures getActiveMatchingSurveys getSurveys".split(" "),n=0;n<o.length;n++)g(u,o[n]);e._i.push([i,s,a])},e.__SV=1)}(document,window.posthog||[]);
posthog.init('${process.env.NEXT_PUBLIC_POSTHOG_KEY}',{api_host:'${process.env.NEXT_PUBLIC_POSTHOG_HOST}'})`}
</Script> </Script>
)} )}
</Head>
<body>
<Main />
<NextScript />
</body> </body>
</Html> </Html>
); );

View File

@ -1,5 +1,7 @@
// mobx // mobx
import { ISSUE_CREATE } from "constants/posthog-events";
import { action, observable, runInAction, makeAutoObservable } from "mobx"; import { action, observable, runInAction, makeAutoObservable } from "mobx";
import { usePostHog } from "posthog-js/react";
// services // services
import issueService from "services/issues.service"; import issueService from "services/issues.service";
// types // types