adding capture function for tacking events in posthog

This commit is contained in:
sriram veeraghanta 2023-09-14 23:02:49 +05:30
parent df62c97579
commit 4303658ddb
6 changed files with 170 additions and 148 deletions

View File

@ -34,7 +34,6 @@ 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"; import { ISSUE_CREATE } from "constants/posthog-events";
export interface IssuesModalProps { export interface IssuesModalProps {
@ -69,7 +68,6 @@ 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);
@ -241,7 +239,6 @@ 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

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

View File

@ -1,6 +1,5 @@
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";
@ -11,7 +10,6 @@ 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,

View File

@ -11,6 +11,10 @@ import type {
ISubIssueResponse, ISubIssueResponse,
} from "types"; } from "types";
import { API_BASE_URL } from "helpers/common.helper"; import { API_BASE_URL } from "helpers/common.helper";
import PosthogService from "./posthog.service";
import { ISSUE_CREATE } from "constants/posthog-events";
const posthogService = new PosthogService();
class ProjectIssuesServices extends APIService { class ProjectIssuesServices extends APIService {
constructor() { constructor() {
@ -26,6 +30,7 @@ class ProjectIssuesServices extends APIService {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/`, data) return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/`, data)
.then((response) => { .then((response) => {
trackEventServices.trackIssueEvent(response.data, "ISSUE_CREATE", user); trackEventServices.trackIssueEvent(response.data, "ISSUE_CREATE", user);
posthogService.capture(ISSUE_CREATE, response.data, user);
return response?.data; return response?.data;
}) })
.catch((error) => { .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

@ -1,7 +1,4 @@
// 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