chore: added sign-up/in, onboarding, dashboard, all-issues related events (#3595)
* chore: added event constants * chore: added workspace events * chore: added workspace group for events * chore: member invitation event added * chore: added project pages related events. * fix: member integer role to string * chore: added sign-up & sign-in events * chore: added global-view related events * chore: added notification related events * chore: project, cycle property change added * chore: cycle favourite, and change-properties added * chore: module davorite, and sidebar property changes added * fix: build errors * chore: all events defined in constants
This commit is contained in:
parent
8d730e6680
commit
4f72ebded9
80 changed files with 1276 additions and 507 deletions
|
|
@ -11,11 +11,13 @@ import { WorkspaceService } from "services/workspace.service";
|
|||
// constants
|
||||
import { USER_WORKSPACES, USER_WORKSPACE_INVITATIONS } from "constants/fetch-keys";
|
||||
import { ROLE } from "constants/workspace";
|
||||
import { MEMBER_ACCEPTED } from "constants/event-tracker";
|
||||
// types
|
||||
import { IWorkspaceMemberInvitation } from "@plane/types";
|
||||
// icons
|
||||
import { CheckCircle2, Search } from "lucide-react";
|
||||
import {} from "hooks/store/use-event-tracker";
|
||||
import { getUserRole } from "helpers/user.helper";
|
||||
|
||||
type Props = {
|
||||
handleNextStep: () => void;
|
||||
|
|
@ -58,11 +60,19 @@ export const Invitations: React.FC<Props> = (props) => {
|
|||
if (invitationsRespond.length <= 0) return;
|
||||
|
||||
setIsJoiningWorkspaces(true);
|
||||
const invitation = invitations?.find((invitation) => invitation.id === invitationsRespond[0]);
|
||||
|
||||
await workspaceService
|
||||
.joinWorkspaces({ invitations: invitationsRespond })
|
||||
.then(async (res) => {
|
||||
captureEvent("Member accepted", { ...res, state: "SUCCESS", accepted_from: "App" });
|
||||
.then(async () => {
|
||||
captureEvent(MEMBER_ACCEPTED, {
|
||||
member_id: invitation?.id,
|
||||
role: getUserRole(invitation?.role!),
|
||||
project_id: undefined,
|
||||
accepted_from: "App",
|
||||
state: "SUCCESS",
|
||||
element: "Workspace invitations page",
|
||||
});
|
||||
await fetchWorkspaces();
|
||||
await mutate(USER_WORKSPACES);
|
||||
await updateLastWorkspace();
|
||||
|
|
@ -71,7 +81,14 @@ export const Invitations: React.FC<Props> = (props) => {
|
|||
})
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
captureEvent("Member accepted", { state: "FAILED", accepted_from: "App" });
|
||||
captureEvent(MEMBER_ACCEPTED, {
|
||||
member_id: invitation?.id,
|
||||
role: getUserRole(invitation?.role!),
|
||||
project_id: undefined,
|
||||
accepted_from: "App",
|
||||
state: "FAILED",
|
||||
element: "Workspace invitations page",
|
||||
});
|
||||
})
|
||||
.finally(() => setIsJoiningWorkspaces(false));
|
||||
};
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import { Check, ChevronDown, Plus, XCircle } from "lucide-react";
|
|||
import { WorkspaceService } from "services/workspace.service";
|
||||
// hooks
|
||||
import useToast from "hooks/use-toast";
|
||||
import { useEventTracker } from "hooks/store";
|
||||
// ui
|
||||
import { Button, Input } from "@plane/ui";
|
||||
// components
|
||||
|
|
@ -28,6 +29,9 @@ import useDynamicDropdownPosition from "hooks/use-dynamic-dropdown";
|
|||
import { IUser, IWorkspace, TOnboardingSteps } from "@plane/types";
|
||||
// constants
|
||||
import { EUserWorkspaceRoles, ROLE } from "constants/workspace";
|
||||
import { MEMBER_INVITED } from "constants/event-tracker";
|
||||
// helpers
|
||||
import { getUserRole } from "helpers/user.helper";
|
||||
// assets
|
||||
import user1 from "public/users/user-1.png";
|
||||
import user2 from "public/users/user-2.png";
|
||||
|
|
@ -267,6 +271,8 @@ export const InviteMembers: React.FC<Props> = (props) => {
|
|||
|
||||
const { setToastAlert } = useToast();
|
||||
const { resolvedTheme } = useTheme();
|
||||
// store hooks
|
||||
const { captureEvent } = useEventTracker();
|
||||
|
||||
const {
|
||||
control,
|
||||
|
|
@ -305,6 +311,17 @@ export const InviteMembers: React.FC<Props> = (props) => {
|
|||
})),
|
||||
})
|
||||
.then(async () => {
|
||||
captureEvent(MEMBER_INVITED, {
|
||||
emails: [
|
||||
...payload.emails.map((email) => ({
|
||||
email: email.email,
|
||||
role: getUserRole(email.role),
|
||||
})),
|
||||
],
|
||||
project_id: undefined,
|
||||
state: "SUCCESS",
|
||||
element: "Onboarding",
|
||||
});
|
||||
setToastAlert({
|
||||
type: "success",
|
||||
title: "Success!",
|
||||
|
|
@ -313,13 +330,18 @@ export const InviteMembers: React.FC<Props> = (props) => {
|
|||
|
||||
await nextStep();
|
||||
})
|
||||
.catch((err) =>
|
||||
.catch((err) => {
|
||||
captureEvent(MEMBER_INVITED, {
|
||||
project_id: undefined,
|
||||
state: "FAILED",
|
||||
element: "Onboarding",
|
||||
});
|
||||
setToastAlert({
|
||||
type: "error",
|
||||
title: "Error!",
|
||||
message: err?.error,
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const appendField = () => {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@ import CyclesTour from "public/onboarding/cycles.webp";
|
|||
import ModulesTour from "public/onboarding/modules.webp";
|
||||
import ViewsTour from "public/onboarding/views.webp";
|
||||
import PagesTour from "public/onboarding/pages.webp";
|
||||
// constants
|
||||
import { PRODUCT_TOUR_SKIPPED, PRODUCT_TOUR_STARTED } from "constants/event-tracker";
|
||||
|
||||
type Props = {
|
||||
onComplete: () => void;
|
||||
|
|
@ -79,7 +81,7 @@ export const TourRoot: React.FC<Props> = observer((props) => {
|
|||
const [step, setStep] = useState<TTourSteps>("welcome");
|
||||
// store hooks
|
||||
const { commandPalette: commandPaletteStore } = useApplication();
|
||||
const { setTrackElement } = useEventTracker();
|
||||
const { setTrackElement, captureEvent } = useEventTracker();
|
||||
const { currentUser } = useUser();
|
||||
|
||||
const currentStepIndex = TOUR_STEPS.findIndex((tourStep) => tourStep.key === step);
|
||||
|
|
@ -103,13 +105,22 @@ export const TourRoot: React.FC<Props> = observer((props) => {
|
|||
</p>
|
||||
<div className="flex h-full items-end">
|
||||
<div className="mt-8 flex items-center gap-6">
|
||||
<Button variant="primary" onClick={() => setStep("issues")}>
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={() => {
|
||||
captureEvent(PRODUCT_TOUR_STARTED);
|
||||
setStep("issues");
|
||||
}}
|
||||
>
|
||||
Take a Product Tour
|
||||
</Button>
|
||||
<button
|
||||
type="button"
|
||||
className="bg-transparent text-xs font-medium text-custom-primary-100 outline-custom-text-100"
|
||||
onClick={onComplete}
|
||||
onClick={() => {
|
||||
captureEvent(PRODUCT_TOUR_SKIPPED);
|
||||
onComplete();
|
||||
}}
|
||||
>
|
||||
No thanks, I will explore it myself
|
||||
</button>
|
||||
|
|
@ -156,8 +167,8 @@ export const TourRoot: React.FC<Props> = observer((props) => {
|
|||
<Button
|
||||
variant="primary"
|
||||
onClick={() => {
|
||||
setTrackElement("Product tour");
|
||||
onComplete();
|
||||
setTrackElement("Onboarding tour");
|
||||
commandPaletteStore.toggleCreateProjectModal(true);
|
||||
}}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { Controller, useForm } from "react-hook-form";
|
|||
import { observer } from "mobx-react-lite";
|
||||
import { Camera, User2 } from "lucide-react";
|
||||
// hooks
|
||||
import { useUser, useWorkspace } from "hooks/store";
|
||||
import { useEventTracker, useUser, useWorkspace } from "hooks/store";
|
||||
// components
|
||||
import { Button, Input } from "@plane/ui";
|
||||
import { OnboardingSidebar, OnboardingStepIndicator } from "components/onboarding";
|
||||
|
|
@ -15,6 +15,7 @@ import { IUser } from "@plane/types";
|
|||
import { FileService } from "services/file.service";
|
||||
// assets
|
||||
import IssuesSvg from "public/onboarding/onboarding-issues.webp";
|
||||
import { USER_DETAILS } from "constants/event-tracker";
|
||||
|
||||
const defaultValues: Partial<IUser> = {
|
||||
first_name: "",
|
||||
|
|
@ -48,6 +49,7 @@ export const UserDetails: React.FC<Props> = observer((props) => {
|
|||
// store hooks
|
||||
const { updateCurrentUser } = useUser();
|
||||
const { workspaces } = useWorkspace();
|
||||
const { captureEvent } = useEventTracker();
|
||||
// derived values
|
||||
const workspaceName = workspaces ? Object.values(workspaces)?.[0]?.name : "New Workspace";
|
||||
// form info
|
||||
|
|
@ -76,7 +78,21 @@ export const UserDetails: React.FC<Props> = observer((props) => {
|
|||
},
|
||||
};
|
||||
|
||||
await updateCurrentUser(payload);
|
||||
await updateCurrentUser(payload)
|
||||
.then(() => {
|
||||
captureEvent(USER_DETAILS, {
|
||||
use_case: formData.use_case,
|
||||
state: "SUCCESS",
|
||||
element: "Onboarding",
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
captureEvent(USER_DETAILS, {
|
||||
use_case: formData.use_case,
|
||||
state: "FAILED",
|
||||
element: "Onboarding",
|
||||
});
|
||||
});
|
||||
};
|
||||
const handleDelete = (url: string | null | undefined) => {
|
||||
if (!url) return;
|
||||
|
|
|
|||
|
|
@ -5,12 +5,13 @@ import { Button, Input } from "@plane/ui";
|
|||
// types
|
||||
import { IUser, IWorkspace, TOnboardingSteps } from "@plane/types";
|
||||
// hooks
|
||||
import { useUser, useWorkspace } from "hooks/store";
|
||||
import { useEventTracker, useUser, useWorkspace } from "hooks/store";
|
||||
import useToast from "hooks/use-toast";
|
||||
// services
|
||||
import { WorkspaceService } from "services/workspace.service";
|
||||
// constants
|
||||
import { RESTRICTED_URLS } from "constants/workspace";
|
||||
import { WORKSPACE_CREATED } from "constants/event-tracker";
|
||||
|
||||
type Props = {
|
||||
stepChange: (steps: Partial<TOnboardingSteps>) => Promise<void>;
|
||||
|
|
@ -33,6 +34,7 @@ export const Workspace: React.FC<Props> = (props) => {
|
|||
// store hooks
|
||||
const { updateCurrentUser } = useUser();
|
||||
const { createWorkspace, fetchWorkspaces, workspaces } = useWorkspace();
|
||||
const { captureWorkspaceEvent } = useEventTracker();
|
||||
// toast alert
|
||||
const { setToastAlert } = useToast();
|
||||
|
||||
|
|
@ -46,31 +48,48 @@ export const Workspace: React.FC<Props> = (props) => {
|
|||
setSlugError(false);
|
||||
|
||||
await createWorkspace(formData)
|
||||
.then(async () => {
|
||||
.then(async (res) => {
|
||||
setToastAlert({
|
||||
type: "success",
|
||||
title: "Success!",
|
||||
message: "Workspace created successfully.",
|
||||
});
|
||||
captureWorkspaceEvent({
|
||||
eventName: WORKSPACE_CREATED,
|
||||
payload: {
|
||||
...res,
|
||||
state: "SUCCESS",
|
||||
first_time: true,
|
||||
element: "Onboarding",
|
||||
},
|
||||
});
|
||||
await fetchWorkspaces();
|
||||
await completeStep();
|
||||
})
|
||||
.catch(() =>
|
||||
.catch(() => {
|
||||
captureWorkspaceEvent({
|
||||
eventName: WORKSPACE_CREATED,
|
||||
payload: {
|
||||
state: "FAILED",
|
||||
first_time: true,
|
||||
element: "Onboarding",
|
||||
},
|
||||
});
|
||||
setToastAlert({
|
||||
type: "error",
|
||||
title: "Error!",
|
||||
message: "Workspace could not be created. Please try again.",
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
} else setSlugError(true);
|
||||
})
|
||||
.catch(() => {
|
||||
.catch(() =>
|
||||
setToastAlert({
|
||||
type: "error",
|
||||
title: "Error!",
|
||||
message: "Some error occurred while creating workspace. Please try again.",
|
||||
});
|
||||
});
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const completeStep = async () => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue