diff --git a/src/PosthogTrackers.ts b/src/PosthogTrackers.ts index 18b6edc064..48b5d59300 100644 --- a/src/PosthogTrackers.ts +++ b/src/PosthogTrackers.ts @@ -17,6 +17,7 @@ limitations under the License. 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"; import PageType from "./PageTypes"; import Views from "./Views"; @@ -106,6 +107,19 @@ export default class PosthogTrackers { 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({ + eventName: "PinUnpinAction", + kind, + from, + }); + } } export class PosthogScreenTracker extends PureComponent<{ screenName: ScreenName }> { diff --git a/src/TextForEvent.tsx b/src/TextForEvent.tsx index 96eb38f01b..d85b7519ae 100644 --- a/src/TextForEvent.tsx +++ b/src/TextForEvent.tsx @@ -40,12 +40,13 @@ import { WIDGET_LAYOUT_EVENT_TYPE } from "./stores/widgets/WidgetLayoutStore"; import { RightPanelPhases } from "./stores/right-panel/RightPanelStorePhases"; import defaultDispatcher from "./dispatcher/dispatcher"; import { RoomSettingsTab } from "./components/views/dialogs/RoomSettingsDialog"; -import AccessibleButton, { ButtonEvent } from "./components/views/elements/AccessibleButton"; +import AccessibleButton from "./components/views/elements/AccessibleButton"; import RightPanelStore from "./stores/right-panel/RightPanelStore"; import { highlightEvent, isLocationEvent } from "./utils/EventUtils"; import { ElementCall } from "./models/Call"; import { textForVoiceBroadcastStoppedEvent, VoiceBroadcastInfoEventType } from "./voice-broadcast"; import { getSenderName } from "./utils/event/getSenderName"; +import PosthogTrackers from "./PosthogTrackers.ts"; function getRoomMemberDisplayname(client: MatrixClient, event: MatrixEvent, userId = event.getSender()): string { const roomId = event.getRoomId(); @@ -563,6 +564,7 @@ function textForPowerEvent(event: MatrixEvent, client: MatrixClient): (() => str } const onPinnedMessagesClick = (): void => { + PosthogTrackers.trackInteraction("PinnedMessageStateEventClick"); RightPanelStore.instance.setCard({ phase: RightPanelPhases.PinnedMessages }, false); }; @@ -590,7 +592,10 @@ function textForPinnedEvent(event: MatrixEvent, client: MatrixClient, allowJSX: a: (sub) => ( highlightEvent(roomId, messageId)} + onClick={() => { + PosthogTrackers.trackInteraction("PinnedMessageStateEventClick"); + highlightEvent(roomId, messageId); + }} > {sub} @@ -623,7 +628,10 @@ function textForPinnedEvent(event: MatrixEvent, client: MatrixClient, allowJSX: a: (sub) => ( highlightEvent(roomId, messageId)} + onClick={() => { + PosthogTrackers.trackInteraction("PinnedMessageStateEventClick"); + highlightEvent(roomId, messageId); + }} > {sub} diff --git a/src/components/views/context_menus/MessageContextMenu.tsx b/src/components/views/context_menus/MessageContextMenu.tsx index 9da62c7d23..31f6a06cc1 100644 --- a/src/components/views/context_menus/MessageContextMenu.tsx +++ b/src/components/views/context_menus/MessageContextMenu.tsx @@ -60,6 +60,7 @@ import { getShareableLocationEvent } from "../../../events/location/getShareable import { ShowThreadPayload } from "../../../dispatcher/payloads/ShowThreadPayload"; import { CardContext } from "../right_panel/context"; import PinningUtils from "../../../utils/PinningUtils"; +import PosthogTrackers from "../../../PosthogTrackers.ts"; interface IReplyInThreadButton { mxEvent: MatrixEvent; @@ -243,9 +244,11 @@ export default class MessageContextMenu extends React.Component this.closeMenu(); }; - private onPinClick = (): void => { + private onPinClick = (isPinned: boolean): void => { // Pin or unpin in background PinningUtils.pinOrUnpinEvent(MatrixClientPeg.safeGet(), this.props.mxEvent); + PosthogTrackers.trackPinUnpinMessage(isPinned ? "Pin" : "Unpin", "Timeline"); + this.closeMenu(); }; @@ -618,7 +621,7 @@ export default class MessageContextMenu extends React.Component this.onPinClick(isPinned)} /> ); } diff --git a/src/components/views/dialogs/UnpinAllDialog.tsx b/src/components/views/dialogs/UnpinAllDialog.tsx index 4b752e820f..e6ce5f556b 100644 --- a/src/components/views/dialogs/UnpinAllDialog.tsx +++ b/src/components/views/dialogs/UnpinAllDialog.tsx @@ -22,6 +22,7 @@ import { logger } from "matrix-js-sdk/src/logger"; import BaseDialog from "../dialogs/BaseDialog"; import { _t } from "../../../languageHandler"; import PinningUtils from "../../../utils/PinningUtils.ts"; +import PosthogTrackers from "../../../PosthogTrackers.ts"; /** * Properties for {@link UnpinAllDialog}. @@ -61,6 +62,7 @@ export function UnpinAllDialog({ matrixClient, roomId, onFinished }: UnpinAllDia onClick={async () => { try { await PinningUtils.unpinAllEvents(matrixClient, roomId); + PosthogTrackers.trackPinUnpinMessage("Unpin", "UnpinAll"); } catch (e) { logger.error("Failed to unpin all events:", e); } diff --git a/src/components/views/messages/MessageActionBar.tsx b/src/components/views/messages/MessageActionBar.tsx index bb870e3dbe..3c9da8b294 100644 --- a/src/components/views/messages/MessageActionBar.tsx +++ b/src/components/views/messages/MessageActionBar.tsx @@ -67,6 +67,7 @@ import { GetRelationsForEvent, IEventTileType } from "../rooms/EventTile"; import { VoiceBroadcastInfoEventType } from "../../../voice-broadcast/types"; import { ButtonEvent } from "../elements/AccessibleButton"; import PinningUtils from "../../../utils/PinningUtils"; +import PosthogTrackers from "../../../PosthogTrackers.ts"; interface IOptionsButtonProps { mxEvent: MatrixEvent; @@ -407,12 +408,13 @@ export default class MessageActionBar extends React.PureComponent => { + private onPinClick = async (event: ButtonEvent, isPinned: boolean): Promise => { // Don't open the regular browser or our context menu on right-click event.preventDefault(); event.stopPropagation(); await PinningUtils.pinOrUnpinEvent(MatrixClientPeg.safeGet(), this.props.mxEvent); + PosthogTrackers.trackPinUnpinMessage(isPinned ? "Pin" : "Unpin", "Timeline"); }; public render(): React.ReactNode { @@ -441,8 +443,8 @@ export default class MessageActionBar extends React.PureComponent this.onPinClick(e, isPinned)} + onContextMenu={(e: ButtonEvent) => this.onPinClick(e, isPinned)} key="pin" placement="left" > diff --git a/src/components/views/right_panel/RoomSummaryCard.tsx b/src/components/views/right_panel/RoomSummaryCard.tsx index ece150495e..f4dcccdae9 100644 --- a/src/components/views/right_panel/RoomSummaryCard.tsx +++ b/src/components/views/right_panel/RoomSummaryCard.tsx @@ -95,6 +95,7 @@ const onRoomFilesClick = (): void => { }; const onRoomPinsClick = (): void => { + PosthogTrackers.trackInteraction("PinnedMessageRoomInfoButton"); RightPanelStore.instance.pushCard({ phase: RightPanelPhases.PinnedMessages }, true); }; diff --git a/src/components/views/rooms/PinnedEventTile.tsx b/src/components/views/rooms/PinnedEventTile.tsx index af4ff71916..ed3fa105ec 100644 --- a/src/components/views/rooms/PinnedEventTile.tsx +++ b/src/components/views/rooms/PinnedEventTile.tsx @@ -42,6 +42,7 @@ import { OpenForwardDialogPayload } from "../../../dispatcher/payloads/OpenForwa import { createRedactEventDialog } from "../dialogs/ConfirmRedactDialog"; import { ShowThreadPayload } from "../../../dispatcher/payloads/ShowThreadPayload"; import PinningUtils from "../../../utils/PinningUtils.ts"; +import PosthogTrackers from "../../../PosthogTrackers.ts"; const AVATAR_SIZE = "32px"; @@ -152,6 +153,8 @@ function PinMenu({ event, room, permalinkCreator }: PinMenuProps): JSX.Element { * View the event in the timeline. */ const onViewInTimeline = useCallback(() => { + PosthogTrackers.trackInteraction("PinnedMessageListViewTimeline"); + dis.dispatch({ action: Action.ViewRoom, event_id: event.getId(), @@ -173,6 +176,7 @@ function PinMenu({ event, room, permalinkCreator }: PinMenuProps): JSX.Element { */ const onUnpin = useCallback(async (): Promise => { await PinningUtils.pinOrUnpinEvent(matrixClient, event); + PosthogTrackers.trackPinUnpinMessage("Unpin", "MessagePinningList"); }, [event, matrixClient]); const contentActionable = isContentActionable(event); diff --git a/src/components/views/rooms/PinnedMessageBanner.tsx b/src/components/views/rooms/PinnedMessageBanner.tsx index 3f6a1b14a6..8c9d2cf252 100644 --- a/src/components/views/rooms/PinnedMessageBanner.tsx +++ b/src/components/views/rooms/PinnedMessageBanner.tsx @@ -32,6 +32,7 @@ import dis from "../../../dispatcher/dispatcher"; import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload"; import { Action } from "../../../dispatcher/actions"; import MessageEvent from "../messages/MessageEvent"; +import PosthogTrackers from "../../../PosthogTrackers.ts"; /** * The props for the {@link PinnedMessageBanner} component. @@ -68,6 +69,8 @@ export function PinnedMessageBanner({ room, permalinkCreator }: PinnedMessageBan const shouldUseMessageEvent = pinnedEvent.isRedacted() || pinnedEvent.isDecryptionFailure(); const onBannerClick = (): void => { + PosthogTrackers.trackInteraction("PinnedMessageBannerClick"); + // Scroll to the pinned message dis.dispatch({ action: Action.ViewRoom, @@ -309,6 +312,9 @@ function BannerButton({ room }: BannerButtonProps): JSX.Element { className="mx_PinnedMessageBanner_actions" kind="tertiary" onClick={() => { + if (isPinnedMessagesPhase) PosthogTrackers.trackInteraction("PinnedMessageBannerCloseListButton"); + else PosthogTrackers.trackInteraction("PinnedMessageBannerViewAllButton"); + RightPanelStore.instance.showOrHidePhase(RightPanelPhases.PinnedMessages); }} >