chore: onboarding events added

This commit is contained in:
LAKHAN BAHETI 2024-05-23 12:19:16 +05:30
parent 509d5fe554
commit e44873e15a
9 changed files with 61 additions and 19 deletions

View File

@ -43,6 +43,7 @@ export const AuthRoot: FC<TAuthRoot> = observer((props) => {
const [email, setEmail] = useState(emailParam ? emailParam.toString() : ""); const [email, setEmail] = useState(emailParam ? emailParam.toString() : "");
const [errorInfo, setErrorInfo] = useState<TAuthErrorInfo | undefined>(undefined); const [errorInfo, setErrorInfo] = useState<TAuthErrorInfo | undefined>(undefined);
const [isPasswordAutoset, setIsPasswordAutoset] = useState(true); const [isPasswordAutoset, setIsPasswordAutoset] = useState(true);
const [isExistingEmail, setIsExistingEmail] = useState(false);
// hooks // hooks
const { config } = useInstance(); const { config } = useInstance();
@ -101,6 +102,7 @@ export const AuthRoot: FC<TAuthRoot> = observer((props) => {
setAuthStep(EAuthSteps.PASSWORD); setAuthStep(EAuthSteps.PASSWORD);
} }
} }
setIsExistingEmail(response.existing);
}) })
.catch((error) => { .catch((error) => {
const errorhandler = authErrorHandler(error?.error_code?.toString(), data?.email || undefined); const errorhandler = authErrorHandler(error?.error_code?.toString(), data?.email || undefined);
@ -138,6 +140,7 @@ export const AuthRoot: FC<TAuthRoot> = observer((props) => {
<AuthUniqueCodeForm <AuthUniqueCodeForm
mode={authMode} mode={authMode}
email={email} email={email}
isExistingEmail={isExistingEmail}
handleEmailClear={() => { handleEmailClear={() => {
setEmail(""); setEmail("");
setAuthStep(EAuthSteps.EMAIL); setAuthStep(EAuthSteps.EMAIL);

View File

@ -8,7 +8,12 @@ import { Button, Input, Spinner } from "@plane/ui";
// components // components
import { ForgotPasswordPopover, PasswordStrengthMeter } from "@/components/account"; import { ForgotPasswordPopover, PasswordStrengthMeter } from "@/components/account";
// constants // constants
import { FORGOT_PASSWORD } from "@/constants/event-tracker"; import {
FORGOT_PASSWORD,
SIGN_IN_WITH_CODE,
SIGN_IN_WITH_PASSWORD,
SIGN_UP_WITH_PASSWORD,
} from "@/constants/event-tracker";
// helpers // helpers
import { EAuthModes, EAuthSteps } from "@/helpers/authentication.helper"; import { EAuthModes, EAuthSteps } from "@/helpers/authentication.helper";
import { API_BASE_URL } from "@/helpers/common.helper"; import { API_BASE_URL } from "@/helpers/common.helper";
@ -68,6 +73,7 @@ export const AuthPasswordForm: React.FC<Props> = observer((props: Props) => {
const redirectToUniqueCodeSignIn = async () => { const redirectToUniqueCodeSignIn = async () => {
handleAuthStep(EAuthSteps.UNIQUE_CODE); handleAuthStep(EAuthSteps.UNIQUE_CODE);
captureEvent(SIGN_IN_WITH_CODE);
}; };
const passwordSupport = const passwordSupport =
@ -114,7 +120,10 @@ export const AuthPasswordForm: React.FC<Props> = observer((props: Props) => {
className="mt-5 space-y-4" className="mt-5 space-y-4"
method="POST" method="POST"
action={`${API_BASE_URL}/auth/${mode === EAuthModes.SIGN_IN ? "sign-in" : "sign-up"}/`} action={`${API_BASE_URL}/auth/${mode === EAuthModes.SIGN_IN ? "sign-in" : "sign-up"}/`}
onSubmit={() => setIsSubmitting(true)} onSubmit={() => {
setIsSubmitting(true);
captureEvent(mode === EAuthModes.SIGN_IN ? SIGN_IN_WITH_PASSWORD : SIGN_UP_WITH_PASSWORD);
}}
onError={() => setIsSubmitting(false)} onError={() => setIsSubmitting(false)}
> >
<input type="hidden" name="csrfmiddlewaretoken" value={csrfToken} /> <input type="hidden" name="csrfmiddlewaretoken" value={csrfToken} />

View File

@ -1,10 +1,13 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { CircleCheck, XCircle } from "lucide-react"; import { CircleCheck, XCircle } from "lucide-react";
import { Button, Input, Spinner } from "@plane/ui"; import { Button, Input, Spinner } from "@plane/ui";
// constants
import { CODE_VERIFIED } from "@/constants/event-tracker";
// helpers // helpers
import { EAuthModes } from "@/helpers/authentication.helper"; import { EAuthModes } from "@/helpers/authentication.helper";
import { API_BASE_URL } from "@/helpers/common.helper"; import { API_BASE_URL } from "@/helpers/common.helper";
// hooks // hooks
import { useEventTracker } from "@/hooks/store";
import useTimer from "@/hooks/use-timer"; import useTimer from "@/hooks/use-timer";
// services // services
import { AuthService } from "@/services/auth.service"; import { AuthService } from "@/services/auth.service";
@ -15,6 +18,7 @@ const authService = new AuthService();
type TAuthUniqueCodeForm = { type TAuthUniqueCodeForm = {
mode: EAuthModes; mode: EAuthModes;
email: string; email: string;
isExistingEmail: boolean;
handleEmailClear: () => void; handleEmailClear: () => void;
generateEmailUniqueCode: (email: string) => Promise<{ code: string } | undefined>; generateEmailUniqueCode: (email: string) => Promise<{ code: string } | undefined>;
}; };
@ -30,9 +34,9 @@ const defaultValues: TUniqueCodeFormValues = {
}; };
export const AuthUniqueCodeForm: React.FC<TAuthUniqueCodeForm> = (props) => { export const AuthUniqueCodeForm: React.FC<TAuthUniqueCodeForm> = (props) => {
const { mode, email, handleEmailClear, generateEmailUniqueCode } = props; const { mode, email, handleEmailClear, generateEmailUniqueCode, isExistingEmail } = props;
// hooks // hooks
// const { captureEvent } = useEventTracker(); const { captureEvent } = useEventTracker();
// derived values // derived values
const defaultResetTimerValue = 5; const defaultResetTimerValue = 5;
// states // states
@ -73,7 +77,13 @@ export const AuthUniqueCodeForm: React.FC<TAuthUniqueCodeForm> = (props) => {
className="mt-5 space-y-4" className="mt-5 space-y-4"
method="POST" method="POST"
action={`${API_BASE_URL}/auth/${mode === EAuthModes.SIGN_IN ? "magic-sign-in" : "magic-sign-up"}/`} action={`${API_BASE_URL}/auth/${mode === EAuthModes.SIGN_IN ? "magic-sign-in" : "magic-sign-up"}/`}
onSubmit={() => setIsSubmitting(true)} onSubmit={() => {
setIsSubmitting(true);
captureEvent(CODE_VERIFIED, {
state: "SUCCESS",
first_time: isExistingEmail,
});
}}
onError={() => setIsSubmitting(false)} onError={() => setIsSubmitting(false)}
> >
<input type="hidden" name="csrfmiddlewaretoken" value={csrfToken} /> <input type="hidden" name="csrfmiddlewaretoken" value={csrfToken} />

View File

@ -5,7 +5,7 @@ import { IUser, IWorkspace, TOnboardingSteps } from "@plane/types";
// ui // ui
import { Button, CustomSelect, Input, Spinner, TOAST_TYPE, setToast } from "@plane/ui"; import { Button, CustomSelect, Input, Spinner, TOAST_TYPE, setToast } from "@plane/ui";
// constants // constants
import { WORKSPACE_CREATED } from "@/constants/event-tracker"; import { E_ONBOARDING, WORKSPACE_CREATED } from "@/constants/event-tracker";
import { ORGANIZATION_SIZE, RESTRICTED_URLS } from "@/constants/workspace"; import { ORGANIZATION_SIZE, RESTRICTED_URLS } from "@/constants/workspace";
// hooks // hooks
import { useEventTracker, useUserProfile, useWorkspace } from "@/hooks/store"; import { useEventTracker, useUserProfile, useWorkspace } from "@/hooks/store";
@ -66,10 +66,10 @@ export const CreateWorkspace: React.FC<Props> = (props) => {
captureWorkspaceEvent({ captureWorkspaceEvent({
eventName: WORKSPACE_CREATED, eventName: WORKSPACE_CREATED,
payload: { payload: {
...res, workspace_id: res.id,
state: "SUCCESS", state: "SUCCESS",
first_time: true, first_time: true,
element: "Onboarding", element: E_ONBOARDING,
}, },
}); });
await fetchWorkspaces(); await fetchWorkspaces();
@ -81,7 +81,7 @@ export const CreateWorkspace: React.FC<Props> = (props) => {
payload: { payload: {
state: "FAILED", state: "FAILED",
first_time: true, first_time: true,
element: "Onboarding", element: E_ONBOARDING,
}, },
}); });
setToast({ setToast({

View File

@ -13,7 +13,7 @@ import { PasswordStrengthMeter } from "@/components/account";
import { UserImageUploadModal } from "@/components/core"; import { UserImageUploadModal } from "@/components/core";
import { OnboardingHeader, SwitchOrDeleteAccountDropdown } from "@/components/onboarding"; import { OnboardingHeader, SwitchOrDeleteAccountDropdown } from "@/components/onboarding";
// constants // constants
import { USER_DETAILS } from "@/constants/event-tracker"; import { E_ONBOARDING, USER_DETAILS, USER_PERSONALIZATION } from "@/constants/event-tracker";
// helpers // helpers
import { getPasswordStrength } from "@/helpers/password.helper"; import { getPasswordStrength } from "@/helpers/password.helper";
// hooks // hooks
@ -141,7 +141,13 @@ export const ProfileSetup: React.FC<Props> = observer((props) => {
]); ]);
captureEvent(USER_DETAILS, { captureEvent(USER_DETAILS, {
state: "SUCCESS", state: "SUCCESS",
element: "Onboarding", element: E_ONBOARDING,
});
captureEvent(USER_PERSONALIZATION, {
use_case: formData.use_case,
role: formData.role,
state: "SUCCESS",
element: E_ONBOARDING,
}); });
setToast({ setToast({
type: TOAST_TYPE.SUCCESS, type: TOAST_TYPE.SUCCESS,
@ -155,7 +161,7 @@ export const ProfileSetup: React.FC<Props> = observer((props) => {
} catch { } catch {
captureEvent(USER_DETAILS, { captureEvent(USER_DETAILS, {
state: "FAILED", state: "FAILED",
element: "Onboarding", element: E_ONBOARDING,
}); });
setToast({ setToast({
type: TOAST_TYPE.ERROR, type: TOAST_TYPE.ERROR,
@ -179,7 +185,7 @@ export const ProfileSetup: React.FC<Props> = observer((props) => {
} catch { } catch {
captureEvent(USER_DETAILS, { captureEvent(USER_DETAILS, {
state: "FAILED", state: "FAILED",
element: "Onboarding", element: E_ONBOARDING,
}); });
setToast({ setToast({
type: TOAST_TYPE.ERROR, type: TOAST_TYPE.ERROR,
@ -199,9 +205,11 @@ export const ProfileSetup: React.FC<Props> = observer((props) => {
updateUserProfile(profileUpdatePayload), updateUserProfile(profileUpdatePayload),
totalSteps > 2 && stepChange({ profile_complete: true }), totalSteps > 2 && stepChange({ profile_complete: true }),
]); ]);
captureEvent(USER_DETAILS, { captureEvent(USER_PERSONALIZATION, {
use_case: formData.use_case,
role: formData.role,
state: "SUCCESS", state: "SUCCESS",
element: "Onboarding", element: E_ONBOARDING,
}); });
setToast({ setToast({
type: TOAST_TYPE.SUCCESS, type: TOAST_TYPE.SUCCESS,
@ -213,9 +221,9 @@ export const ProfileSetup: React.FC<Props> = observer((props) => {
finishOnboarding(); finishOnboarding();
} }
} catch { } catch {
captureEvent(USER_DETAILS, { captureEvent(USER_PERSONALIZATION, {
state: "FAILED", state: "FAILED",
element: "Onboarding", element: E_ONBOARDING,
}); });
setToast({ setToast({
type: TOAST_TYPE.ERROR, type: TOAST_TYPE.ERROR,

View File

@ -192,11 +192,14 @@ export const SETUP_PASSWORD = "Password setup";
export const PASSWORD_CREATE_SELECTED = "Password created"; export const PASSWORD_CREATE_SELECTED = "Password created";
export const PASSWORD_CREATE_SKIPPED = "Skipped to setup"; export const PASSWORD_CREATE_SKIPPED = "Skipped to setup";
export const SIGN_IN_WITH_PASSWORD = "Sign in with password"; export const SIGN_IN_WITH_PASSWORD = "Sign in with password";
export const SIGN_UP_WITH_PASSWORD = "Sign up with password";
export const SIGN_IN_WITH_CODE = "Sign in with magic link";
export const FORGOT_PASSWORD = "Forgot password clicked"; export const FORGOT_PASSWORD = "Forgot password clicked";
export const FORGOT_PASS_LINK = "Forgot password link generated"; export const FORGOT_PASS_LINK = "Forgot password link generated";
export const NEW_PASS_CREATED = "New password created"; export const NEW_PASS_CREATED = "New password created";
// Onboarding Events // Onboarding Events
export const USER_DETAILS = "User details added"; export const USER_DETAILS = "User details added";
export const USER_PERSONALIZATION = "User personalization added";
export const USER_ONBOARDING_COMPLETED = "User onboarding completed"; export const USER_ONBOARDING_COMPLETED = "User onboarding completed";
// Product Tour Events // Product Tour Events
export const PRODUCT_TOUR_STARTED = "Product tour started"; export const PRODUCT_TOUR_STARTED = "Product tour started";
@ -222,3 +225,6 @@ export const SNOOZED_NOTIFICATIONS = "Snoozed notifications viewed";
export const ARCHIVED_NOTIFICATIONS = "Archived notifications viewed"; export const ARCHIVED_NOTIFICATIONS = "Archived notifications viewed";
// Groups // Groups
export const GROUP_WORKSPACE = "Workspace_metrics"; export const GROUP_WORKSPACE = "Workspace_metrics";
//Elements
export const E_ONBOARDING = "Onboarding";

View File

@ -115,7 +115,7 @@ const ForgotPasswordPage: NextPageWithLayout = () => {
New to Plane?{" "} New to Plane?{" "}
<Link <Link
href="/" href="/"
onClick={() => captureEvent(NAVIGATE_TO_SIGNUP, {})} onClick={() => captureEvent(NAVIGATE_TO_SIGNUP)}
className="font-semibold text-custom-primary-100 hover:underline" className="font-semibold text-custom-primary-100 hover:underline"
> >
Create an account Create an account

View File

@ -9,6 +9,8 @@ import { Button, Input } from "@plane/ui";
// components // components
import { AuthBanner, PasswordStrengthMeter } from "@/components/account"; import { AuthBanner, PasswordStrengthMeter } from "@/components/account";
import { PageHead } from "@/components/core"; import { PageHead } from "@/components/core";
// constants
import { NEW_PASS_CREATED } from "@/constants/event-tracker";
// helpers // helpers
import { import {
EAuthenticationErrorCodes, EAuthenticationErrorCodes,
@ -19,6 +21,8 @@ import {
} from "@/helpers/authentication.helper"; } from "@/helpers/authentication.helper";
import { API_BASE_URL } from "@/helpers/common.helper"; import { API_BASE_URL } from "@/helpers/common.helper";
import { getPasswordStrength } from "@/helpers/password.helper"; import { getPasswordStrength } from "@/helpers/password.helper";
// hooks
import { useEventTracker } from "@/hooks/store";
// layouts // layouts
import DefaultLayout from "@/layouts/default-layout"; import DefaultLayout from "@/layouts/default-layout";
// lib // lib
@ -66,6 +70,7 @@ const ResetPasswordPage: NextPageWithLayout = () => {
// hooks // hooks
const { resolvedTheme } = useTheme(); const { resolvedTheme } = useTheme();
const { captureEvent } = useEventTracker();
const handleShowPassword = (key: keyof typeof showPassword) => const handleShowPassword = (key: keyof typeof showPassword) =>
setShowPassword((prev) => ({ ...prev, [key]: !prev[key] })); setShowPassword((prev) => ({ ...prev, [key]: !prev[key] }));
@ -132,6 +137,7 @@ const ResetPasswordPage: NextPageWithLayout = () => {
<form <form
className="mt-5 space-y-4" className="mt-5 space-y-4"
method="POST" method="POST"
onSubmit={() => captureEvent(NEW_PASS_CREATED)}
action={`${API_BASE_URL}/auth/reset-password/${uidb64?.toString()}/${token?.toString()}/`} action={`${API_BASE_URL}/auth/reset-password/${uidb64?.toString()}/${token?.toString()}/`}
> >
<input type="hidden" name="csrfmiddlewaretoken" value={csrfToken} /> <input type="hidden" name="csrfmiddlewaretoken" value={csrfToken} />

View File

@ -51,7 +51,7 @@ const SignInPage: NextPageWithLayout = observer(() => {
New to Plane?{" "} New to Plane?{" "}
<Link <Link
href="/" href="/"
onClick={() => captureEvent(NAVIGATE_TO_SIGNUP, {})} onClick={() => captureEvent(NAVIGATE_TO_SIGNUP)}
className="font-semibold text-custom-primary-100 hover:underline" className="font-semibold text-custom-primary-100 hover:underline"
> >
Create an account Create an account