element-web-Github/src/PosthogTrackers.ts

135 lines
4.5 KiB
TypeScript
Raw Normal View History

2022-02-09 22:25:58 +08:00
/*
Copyright 2024 New Vector Ltd.
2022-02-09 22:25:58 +08:00
Copyright 2022 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
2022-02-09 22:25:58 +08:00
*/
import { PureComponent, SyntheticEvent } from "react";
import { WebScreen as ScreenEvent } from "@matrix-org/analytics-events/types/typescript/WebScreen";
import { Interaction as InteractionEvent } from "@matrix-org/analytics-events/types/typescript/Interaction";
import { PinUnpinAction } from "@matrix-org/analytics-events/types/typescript/PinUnpinAction";
2022-02-09 22:25:58 +08:00
import PageType from "./PageTypes";
import Views from "./Views";
import { PosthogAnalytics } from "./PosthogAnalytics";
export type ScreenName = ScreenEvent["$current_url"];
export type InteractionName = InteractionEvent["name"];
2022-02-09 22:25:58 +08:00
const notLoggedInMap: Record<Exclude<Views, Views.LOGGED_IN>, ScreenName> = {
[Views.LOADING]: "Loading",
[Views.CONFIRM_LOCK_THEFT]: "ConfirmStartup",
2022-02-09 22:25:58 +08:00
[Views.WELCOME]: "Welcome",
[Views.LOGIN]: "Login",
[Views.REGISTER]: "Register",
[Views.USE_CASE_SELECTION]: "UseCaseSelection",
2022-02-09 22:25:58 +08:00
[Views.FORGOT_PASSWORD]: "ForgotPassword",
[Views.COMPLETE_SECURITY]: "CompleteSecurity",
[Views.E2E_SETUP]: "E2ESetup",
[Views.SOFT_LOGOUT]: "SoftLogout",
[Views.LOCK_STOLEN]: "SessionLockStolen",
2022-02-09 22:25:58 +08:00
};
const loggedInPageTypeMap: Record<PageType, ScreenName> = {
[PageType.HomePage]: "Home",
[PageType.RoomView]: "Room",
[PageType.UserView]: "User",
};
export default class PosthogTrackers {
private static internalInstance: PosthogTrackers;
public static get instance(): PosthogTrackers {
if (!PosthogTrackers.internalInstance) {
PosthogTrackers.internalInstance = new PosthogTrackers();
}
return PosthogTrackers.internalInstance;
}
private view: Views = Views.LOADING;
private pageType?: PageType;
private override?: ScreenName;
2022-02-09 22:25:58 +08:00
public trackPageChange(view: Views, pageType: PageType | undefined, durationMs: number): void {
this.view = view;
this.pageType = pageType;
if (this.override) return;
this.trackPage(durationMs);
}
private trackPage(durationMs?: number): void {
2022-12-12 19:24:14 +08:00
const screenName =
this.view === Views.LOGGED_IN ? loggedInPageTypeMap[this.pageType!] : notLoggedInMap[this.view];
2022-02-09 22:25:58 +08:00
PosthogAnalytics.instance.trackEvent<ScreenEvent>({
eventName: "$pageview",
$current_url: screenName,
2022-02-09 22:25:58 +08:00
durationMs,
});
}
public trackOverride(screenName: ScreenName): void {
if (!screenName) return;
this.override = screenName;
PosthogAnalytics.instance.trackEvent<ScreenEvent>({
eventName: "$pageview",
$current_url: screenName,
2022-02-09 22:25:58 +08:00
});
}
public clearOverride(screenName: ScreenName): void {
if (screenName !== this.override) return;
this.override = undefined;
2022-02-09 22:25:58 +08:00
this.trackPage();
}
public static trackInteraction(name: InteractionName, ev?: SyntheticEvent | Event, index?: number): void {
let interactionType: InteractionEvent["interactionType"];
if (ev?.type === "click") {
interactionType = "Pointer";
} else if (ev?.type.startsWith("key")) {
interactionType = "Keyboard";
}
PosthogAnalytics.instance.trackEvent<InteractionEvent>({
eventName: "Interaction",
interactionType,
index,
name,
});
}
/**
* Track a pin or unpin action on a message.
* @param kind - Is pin or unpin.
* @param from - From where the action is triggered.
*/
public static trackPinUnpinMessage(kind: PinUnpinAction["kind"], from: PinUnpinAction["from"]): void {
PosthogAnalytics.instance.trackEvent<PinUnpinAction>({
eventName: "PinUnpinAction",
kind,
from,
});
}
2022-02-09 22:25:58 +08:00
}
export class PosthogScreenTracker extends PureComponent<{ screenName: ScreenName }> {
public componentDidMount(): void {
2022-02-09 22:25:58 +08:00
PosthogTrackers.instance.trackOverride(this.props.screenName);
}
public componentDidUpdate(): void {
2022-02-09 22:25:58 +08:00
// We do not clear the old override here so that we do not send the non-override screen as a transition
PosthogTrackers.instance.trackOverride(this.props.screenName);
}
public componentWillUnmount(): void {
2022-02-09 22:25:58 +08:00
PosthogTrackers.instance.clearOverride(this.props.screenName);
}
public render(): React.ReactNode {
2022-02-09 22:25:58 +08:00
return null; // no need to render anything, we just need to hook into the React lifecycle
}
}