From 999e1b74211af52f7a01e8d8613ab8ac7dd08af1 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 9 Feb 2022 14:42:08 +0000 Subject: [PATCH] Wire up bunch of interaction events into Posthog (#7707) --- src/PosthogTrackers.ts | 18 +++++++++++++++++- src/SlashCommands.tsx | 14 ++++++++++++++ .../views/context_menus/RoomContextMenu.tsx | 19 +++++++++++++++---- src/components/views/right_panel/BaseCard.tsx | 11 +++++++---- .../views/right_panel/RoomSummaryCard.tsx | 17 ++++++++++------- src/components/views/right_panel/UserInfo.tsx | 12 ++++++++++-- .../views/rooms/EditMessageComposer.tsx | 14 ++++++++++++-- src/components/views/rooms/MemberList.tsx | 7 +++++-- .../views/rooms/MessageComposer.tsx | 4 +++- src/components/views/rooms/RoomTile.tsx | 14 +++++++++++++- .../views/rooms/SendMessageComposer.tsx | 9 +++++++++ .../tabs/room/GeneralRoomSettingsTab.tsx | 7 +++++-- 12 files changed, 120 insertions(+), 26 deletions(-) diff --git a/src/PosthogTrackers.ts b/src/PosthogTrackers.ts index 4e13bf2a80..c67dfc9b98 100644 --- a/src/PosthogTrackers.ts +++ b/src/PosthogTrackers.ts @@ -14,8 +14,9 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { PureComponent } from "react"; +import { PureComponent, SyntheticEvent } from "react"; import { Screen as ScreenEvent } from "matrix-analytics-events/types/typescript/Screen"; +import { Interaction as InteractionEvent } from "matrix-analytics-events/types/typescript/Interaction"; import PageType from "./PageTypes"; import Views from "./Views"; @@ -88,6 +89,21 @@ export default class PosthogTrackers { this.override = null; this.trackPage(); } + + public static trackInteraction(name: InteractionEvent["name"], ev?: SyntheticEvent): void { + let interactionType: InteractionEvent["interactionType"]; + if (ev?.type === "click") { + interactionType = "Pointer"; + } else if (ev?.type.startsWith("key")) { + interactionType = "Keyboard"; + } + + PosthogAnalytics.instance.trackEvent({ + eventName: "Interaction", + interactionType, + name, + }); + } } export class PosthogScreenTracker extends PureComponent<{ screenName: ScreenName }> { diff --git a/src/SlashCommands.tsx b/src/SlashCommands.tsx index 054dc026b5..cec942b890 100644 --- a/src/SlashCommands.tsx +++ b/src/SlashCommands.tsx @@ -25,6 +25,7 @@ import * as ContentHelpers from 'matrix-js-sdk/src/content-helpers'; import { parseFragment as parseHtml, Element as ChildElement } from "parse5"; import { logger } from "matrix-js-sdk/src/logger"; import { IContent } from 'matrix-js-sdk/src/models/event'; +import { SlashCommand as SlashCommandEvent } from "matrix-analytics-events/types/typescript/SlashCommand"; import { MatrixClientPeg } from './MatrixClientPeg'; import dis from './dispatcher/dispatcher'; @@ -62,6 +63,7 @@ import { shouldShowComponent } from "./customisations/helpers/UIComponents"; import { TimelineRenderingType } from './contexts/RoomContext'; import RoomViewStore from "./stores/RoomViewStore"; import { XOR } from "./@types/common"; +import { PosthogAnalytics } from "./PosthogAnalytics"; // XXX: workaround for https://github.com/microsoft/TypeScript/issues/31816 interface HTMLInputEvent extends Event { @@ -105,6 +107,7 @@ interface ICommandOpts { aliases?: string[]; args?: string; description: string; + analyticsName?: SlashCommandEvent["command"]; runFn?: RunFn; category: string; hideCompletionAfterSpace?: boolean; @@ -121,6 +124,7 @@ export class Command { public readonly category: string; public readonly hideCompletionAfterSpace: boolean; public readonly renderingTypes?: TimelineRenderingType[]; + public readonly analyticsName?: SlashCommandEvent["command"]; private readonly _isEnabled?: () => boolean; constructor(opts: ICommandOpts) { @@ -133,6 +137,7 @@ export class Command { this.hideCompletionAfterSpace = opts.hideCompletionAfterSpace || false; this._isEnabled = opts.isEnabled; this.renderingTypes = opts.renderingTypes; + this.analyticsName = opts.analyticsName; } public getCommand() { @@ -167,6 +172,13 @@ export class Command { ); } + if (this.analyticsName) { + PosthogAnalytics.instance.trackEvent({ + eventName: "SlashCommand", + command: this.analyticsName, + }); + } + return this.runFn.bind(this)(roomId, args); } @@ -488,6 +500,7 @@ export const Commands = [ command: 'invite', args: ' []', description: _td('Invites user with given id to current room'), + analyticsName: "invite", isEnabled: () => shouldShowComponent(UIComponent.InviteUsers), runFn: function(roomId, args) { if (args) { @@ -674,6 +687,7 @@ export const Commands = [ command: 'part', args: '[]', description: _td('Leave room'), + analyticsName: "part", runFn: function(roomId, args) { const cli = MatrixClientPeg.get(); diff --git a/src/components/views/context_menus/RoomContextMenu.tsx b/src/components/views/context_menus/RoomContextMenu.tsx index 5bcf8e5e25..ac8ca84cde 100644 --- a/src/components/views/context_menus/RoomContextMenu.tsx +++ b/src/components/views/context_menus/RoomContextMenu.tsx @@ -36,7 +36,6 @@ import { EchoChamber } from "../../../stores/local-echo/EchoChamber"; import { RoomNotifState } from "../../../RoomNotifs"; import Modal from "../../../Modal"; import ExportDialog from "../dialogs/ExportDialog"; -import { onRoomFilesClick, onRoomMembersClick } from "../right_panel/RoomSummaryCard"; import RoomViewStore from "../../../stores/RoomViewStore"; import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases'; import { ROOM_NOTIFICATIONS_TAB } from "../dialogs/RoomSettingsDialog"; @@ -44,6 +43,7 @@ import { useEventEmitterState } from "../../../hooks/useEventEmitter"; import RightPanelStore from "../../../stores/right-panel/RightPanelStore"; import DMRoomMap from "../../../utils/DMRoomMap"; import { Action } from "../../../dispatcher/actions"; +import PosthogTrackers from "../../../PosthogTrackers"; interface IProps extends IContextMenuProps { room: Room; @@ -86,6 +86,8 @@ const RoomContextMenu = ({ room, onFinished, ...props }: IProps) => { room_id: room.roomId, }); onFinished(); + + PosthogTrackers.trackInteraction("WebRoomHeaderContextMenuLeaveItem", ev); }; leaveOption = { roomId: room.roomId, }); onFinished(); + + PosthogTrackers.trackInteraction("WebRoomHeaderContextMenuInviteItem", ev); }; inviteOption = { if (room.getMyMembership() === "join") { const isFavorite = roomTags.includes(DefaultTagID.Favourite); favouriteOption = onTagRoom(e, DefaultTagID.Favourite)} + onClick={(e) => { + onTagRoom(e, DefaultTagID.Favourite); + PosthogTrackers.trackInteraction("WebRoomHeaderContextMenuFavouriteToggle", e); + }} active={isFavorite} label={isFavorite ? _t("Favourited") : _t("Favourite")} iconClassName="mx_RoomTile_iconStar" @@ -171,6 +178,8 @@ const RoomContextMenu = ({ room, onFinished, ...props }: IProps) => { initial_tab_id: ROOM_NOTIFICATIONS_TAB, }); onFinished(); + + PosthogTrackers.trackInteraction("WebRoomHeaderContextMenuNotificationsItem", ev); }} label={_t("Notifications")} iconClassName={iconClassName} @@ -190,8 +199,9 @@ const RoomContextMenu = ({ room, onFinished, ...props }: IProps) => { ev.stopPropagation(); ensureViewingRoom(); - onRoomMembersClick(false); + RightPanelStore.instance.pushCard({ phase: RightPanelPhases.RoomMemberList }, false); onFinished(); + PosthogTrackers.trackInteraction("WebRoomHeaderContextMenuPeopleItem", ev); }} label={_t("People")} iconClassName="mx_RoomTile_iconPeople" @@ -258,7 +268,7 @@ const RoomContextMenu = ({ room, onFinished, ...props }: IProps) => { ev.stopPropagation(); ensureViewingRoom(); - onRoomFilesClick(false); + RightPanelStore.instance.pushCard({ phase: RightPanelPhases.FilePanel }, false); onFinished(); }} label={_t("Files")} @@ -291,6 +301,7 @@ const RoomContextMenu = ({ room, onFinished, ...props }: IProps) => { room_id: room.roomId, }); onFinished(); + PosthogTrackers.trackInteraction("WebRoomHeaderContextMenuSettingsItem", ev); }} label={_t("Settings")} iconClassName="mx_RoomTile_iconSettings" diff --git a/src/components/views/right_panel/BaseCard.tsx b/src/components/views/right_panel/BaseCard.tsx index 0ecf0e5e6b..f45e82e952 100644 --- a/src/components/views/right_panel/BaseCard.tsx +++ b/src/components/views/right_panel/BaseCard.tsx @@ -19,7 +19,7 @@ import classNames from 'classnames'; import AutoHideScrollbar from "../../structures/AutoHideScrollbar"; import { _t } from "../../../languageHandler"; -import AccessibleButton from "../elements/AccessibleButton"; +import AccessibleButton, { ButtonEvent } from "../elements/AccessibleButton"; import RightPanelStore from '../../../stores/right-panel/RightPanelStore'; import { backLabelForPhase } from '../../../stores/right-panel/RightPanelStorePhases'; @@ -30,8 +30,9 @@ interface IProps { className?: string; withoutScrollContainer?: boolean; closeLabel?: string; - onClose?(): void; - cardState?; + onClose?(ev: ButtonEvent): void; + onBack?(ev: ButtonEvent): void; + cardState?: any; } interface IGroupProps { @@ -49,6 +50,7 @@ export const Group: React.FC = ({ className, title, children }) => const BaseCard: React.FC = ({ closeLabel, onClose, + onBack, className, header, footer, @@ -59,7 +61,8 @@ const BaseCard: React.FC = ({ const cardHistory = RightPanelStore.instance.roomPhaseHistory; if (cardHistory.length > 1) { const prevCard = cardHistory[cardHistory.length - 2]; - const onBackClick = () => { + const onBackClick = (ev: ButtonEvent) => { + onBack?.(ev); RightPanelStore.instance.popCard(); }; const label = backLabelForPhase(prevCard.phase) ?? _t("Back"); diff --git a/src/components/views/right_panel/RoomSummaryCard.tsx b/src/components/views/right_panel/RoomSummaryCard.tsx index c7d76115a6..e3a4f3740f 100644 --- a/src/components/views/right_panel/RoomSummaryCard.tsx +++ b/src/components/views/right_panel/RoomSummaryCard.tsx @@ -23,7 +23,7 @@ import { useIsEncrypted } from '../../../hooks/useIsEncrypted'; import BaseCard, { Group } from "./BaseCard"; import { _t } from '../../../languageHandler'; import RoomAvatar from "../avatars/RoomAvatar"; -import AccessibleButton from "../elements/AccessibleButton"; +import AccessibleButton, { ButtonEvent } from "../elements/AccessibleButton"; import defaultDispatcher from "../../../dispatcher/dispatcher"; import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases'; import Modal from "../../../Modal"; @@ -47,6 +47,7 @@ import RoomName from "../elements/RoomName"; import UIStore from "../../../stores/UIStore"; import ExportDialog from "../dialogs/ExportDialog"; import RightPanelStore from "../../../stores/right-panel/RightPanelStore"; +import PosthogTrackers from "../../../PosthogTrackers"; interface IProps { room: Room; @@ -59,7 +60,7 @@ interface IAppsSectionProps { interface IButtonProps { className: string; - onClick(): void; + onClick(ev: ButtonEvent): void; } const Button: React.FC = ({ children, className, onClick }) => { @@ -229,16 +230,18 @@ const AppsSection: React.FC = ({ room }) => { ; }; -export const onRoomMembersClick = (allowClose = true) => { - RightPanelStore.instance.pushCard({ phase: RightPanelPhases.RoomMemberList }, allowClose); +const onRoomMembersClick = (ev: ButtonEvent) => { + RightPanelStore.instance.pushCard({ phase: RightPanelPhases.RoomMemberList }, true); + PosthogTrackers.trackInteraction("WebRightPanelRoomInfoPeopleButton", ev); }; -export const onRoomFilesClick = (allowClose = true) => { - RightPanelStore.instance.pushCard({ phase: RightPanelPhases.FilePanel }, allowClose); +const onRoomFilesClick = () => { + RightPanelStore.instance.pushCard({ phase: RightPanelPhases.FilePanel }, true); }; -const onRoomSettingsClick = () => { +const onRoomSettingsClick = (ev: ButtonEvent) => { defaultDispatcher.dispatch({ action: "open_room_settings" }); + PosthogTrackers.trackInteraction("WebRightPanelRoomInfoSettingsButton", ev); }; const RoomSummaryCard: React.FC = ({ room, onClose }) => { diff --git a/src/components/views/right_panel/UserInfo.tsx b/src/components/views/right_panel/UserInfo.tsx index 476ffc763b..5acd736b0c 100644 --- a/src/components/views/right_panel/UserInfo.tsx +++ b/src/components/views/right_panel/UserInfo.tsx @@ -34,7 +34,7 @@ import Modal from '../../../Modal'; import { _t } from '../../../languageHandler'; import createRoom, { findDMForUser, privateShouldBeEncrypted } from '../../../createRoom'; import DMRoomMap from '../../../utils/DMRoomMap'; -import AccessibleButton from '../elements/AccessibleButton'; +import AccessibleButton, { ButtonEvent } from '../elements/AccessibleButton'; import SdkConfig from '../../../SdkConfig'; import RoomViewStore from "../../../stores/RoomViewStore"; import MultiInviter from "../../../utils/MultiInviter"; @@ -78,6 +78,7 @@ import RightPanelStore from '../../../stores/right-panel/RightPanelStore'; import { IRightPanelCardState } from '../../../stores/right-panel/RightPanelStoreIPanelState'; import { useUserStatusMessage } from "../../../hooks/useUserStatusMessage"; import UserIdentifierCustomisations from '../../../customisations/UserIdentifier'; +import PosthogTrackers from "../../../PosthogTrackers"; export interface IDevice { deviceId: string; @@ -422,7 +423,7 @@ const UserOptionsSection: React.FC<{ if (canInvite && (member?.membership ?? 'leave') === 'leave' && shouldShowComponent(UIComponent.InviteUsers)) { const roomId = member && member.roomId ? member.roomId : RoomViewStore.getRoomId(); - const onInviteUserButton = async () => { + const onInviteUserButton = async (ev: ButtonEvent) => { try { // We use a MultiInviter to re-use the invite logic, even though // we're only inviting one user. @@ -438,6 +439,8 @@ const UserOptionsSection: React.FC<{ description: ((err && err.message) ? err.message : _t("Operation failed")), }); } + + PosthogTrackers.trackInteraction("WebRightPanelRoomUserInfoInviteButton", ev); }; inviteUserButton = ( @@ -1719,6 +1722,11 @@ const UserInfo: React.FC = ({ onClose={onClose} closeLabel={closeLabel} cardState={cardState} + onBack={(ev: ButtonEvent) => { + if (RightPanelStore.instance.previousCard.phase === RightPanelPhases.RoomMemberList) { + PosthogTrackers.trackInteraction("WebRightPanelRoomUserInfoBackButton", ev); + } + }} > { content } ; diff --git a/src/components/views/rooms/EditMessageComposer.tsx b/src/components/views/rooms/EditMessageComposer.tsx index c7ee882526..73361bafad 100644 --- a/src/components/views/rooms/EditMessageComposer.tsx +++ b/src/components/views/rooms/EditMessageComposer.tsx @@ -20,6 +20,7 @@ import { EventStatus, IContent, MatrixEvent } from 'matrix-js-sdk/src/models/eve import { MsgType } from 'matrix-js-sdk/src/@types/event'; import { Room } from 'matrix-js-sdk/src/models/room'; import { logger } from "matrix-js-sdk/src/logger"; +import { Composer as ComposerEvent } from "matrix-analytics-events/types/typescript/Composer"; import { _t } from '../../../languageHandler'; import dis from '../../../dispatcher/dispatcher'; @@ -46,6 +47,7 @@ import RoomContext from '../../../contexts/RoomContext'; import { ComposerType } from "../../../dispatcher/payloads/ComposerInsertPayload"; import { getSlashCommand, isSlashCommand, runSlashCommand, shouldSendAnyway } from "../../../editor/commands"; import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts"; +import { PosthogAnalytics } from "../../../PosthogAnalytics"; function getHtmlReplyFallback(mxEvent: MatrixEvent): string { const html = mxEvent.getContent().formatted_body; @@ -295,9 +297,17 @@ class EditMessageComposer extends React.Component => { if (this.state.saveDisabled) return; - const startTime = CountlyAnalytics.getTimestamp(); const editedEvent = this.props.editState.getEvent(); + PosthogAnalytics.instance.trackEvent({ + eventName: "Composer", + isEditing: true, + inThread: !!editedEvent?.getThread(), + isReply: !!editedEvent.replyEventId, + }); + + const startTime = CountlyAnalytics.getTimestamp(); + // Replace emoticon at the end of the message if (SettingsStore.getValue('MessageComposerInput.autoReplaceEmoji')) { const caret = this.editorRef.current?.getCaret(); @@ -323,7 +333,7 @@ class EditMessageComposer extends React.Component { ; } - onInviteButtonClick = (): void => { + private onInviteButtonClick = (ev: ButtonEvent): void => { + PosthogTrackers.trackInteraction("WebRightPanelMemberListInviteButton", ev); + if (MatrixClientPeg.get().isGuest()) { dis.dispatch({ action: 'require_registration' }); return; diff --git a/src/components/views/rooms/MessageComposer.tsx b/src/components/views/rooms/MessageComposer.tsx index 5ae984975d..ba674184fb 100644 --- a/src/components/views/rooms/MessageComposer.tsx +++ b/src/components/views/rooms/MessageComposer.tsx @@ -13,6 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ + import React, { createRef } from 'react'; import classNames from 'classnames'; import { MatrixEvent, IEventRelation } from "matrix-js-sdk/src/models/event"; @@ -47,12 +48,13 @@ import UIStore, { UI_EVENTS } from '../../../stores/UIStore'; import RoomContext from '../../../contexts/RoomContext'; import { SettingUpdatedPayload } from "../../../dispatcher/payloads/SettingUpdatedPayload"; import MessageComposerButtons from './MessageComposerButtons'; +import { ButtonEvent } from '../elements/AccessibleButton'; let instanceCount = 0; const NARROW_MODE_BREAKPOINT = 500; interface ISendButtonProps { - onClick: () => void; + onClick: (ev: ButtonEvent) => void; title?: string; // defaults to something generic } diff --git a/src/components/views/rooms/RoomTile.tsx b/src/components/views/rooms/RoomTile.tsx index 97750f01af..5579525aa6 100644 --- a/src/components/views/rooms/RoomTile.tsx +++ b/src/components/views/rooms/RoomTile.tsx @@ -52,6 +52,7 @@ import IconizedContextMenu, { } from "../context_menus/IconizedContextMenu"; import { CommunityPrototypeStore, IRoomProfile } from "../../../stores/CommunityPrototypeStore"; import { replaceableComponent } from "../../../utils/replaceableComponent"; +import PosthogTrackers from "../../../PosthogTrackers"; interface IProps { room: Room; @@ -255,6 +256,8 @@ export default class RoomTile extends React.PureComponent { ev.stopPropagation(); const target = ev.target as HTMLButtonElement; this.setState({ notificationsMenuPosition: target.getBoundingClientRect() }); + + PosthogTrackers.trackInteraction("WebRoomListRoomTileNotificationsMenu", ev); }; private onCloseNotificationsMenu = () => { @@ -322,6 +325,8 @@ export default class RoomTile extends React.PureComponent { room_id: this.props.room.roomId, }); this.setState({ generalMenuPosition: null }); // hide the menu + + PosthogTrackers.trackInteraction("WebRoomListRoomTileContextMenuLeaveItem", ev); }; private onForgetRoomClick = (ev: ButtonEvent) => { @@ -344,6 +349,8 @@ export default class RoomTile extends React.PureComponent { room_id: this.props.room.roomId, }); this.setState({ generalMenuPosition: null }); // hide the menu + + PosthogTrackers.trackInteraction("WebRoomListRoomTileContextMenuSettingsItem", ev); }; private onCopyRoomClick = (ev: ButtonEvent) => { @@ -366,6 +373,8 @@ export default class RoomTile extends React.PureComponent { roomId: this.props.room.roomId, }); this.setState({ generalMenuPosition: null }); // hide the menu + + PosthogTrackers.trackInteraction("WebRoomListRoomTileContextMenuInviteItem", ev); }; private async saveNotifState(ev: ButtonEvent, newState: RoomNotifState) { @@ -500,7 +509,10 @@ export default class RoomTile extends React.PureComponent { > this.onTagRoom(e, DefaultTagID.Favourite)} + onClick={(e) => { + this.onTagRoom(e, DefaultTagID.Favourite); + PosthogTrackers.trackInteraction("WebRoomListRoomTileContextMenuFavouriteToggle", e); + }} active={isFavorite} label={favouriteLabel} iconClassName="mx_RoomTile_iconStar" diff --git a/src/components/views/rooms/SendMessageComposer.tsx b/src/components/views/rooms/SendMessageComposer.tsx index 406fed0971..6743fe436b 100644 --- a/src/components/views/rooms/SendMessageComposer.tsx +++ b/src/components/views/rooms/SendMessageComposer.tsx @@ -21,6 +21,7 @@ import { DebouncedFunc, throttle } from 'lodash'; import { EventType, RelationType } from "matrix-js-sdk/src/@types/event"; import { logger } from "matrix-js-sdk/src/logger"; import { Room } from 'matrix-js-sdk/src/models/room'; +import { Composer as ComposerEvent } from "matrix-analytics-events/types/typescript/Composer"; import dis from '../../../dispatcher/dispatcher'; import EditorModel from '../../../editor/model'; @@ -57,6 +58,7 @@ import DocumentPosition from "../../../editor/position"; import { ComposerType } from "../../../dispatcher/payloads/ComposerInsertPayload"; import { getSlashCommand, isSlashCommand, runSlashCommand, shouldSendAnyway } from "../../../editor/commands"; import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts"; +import { PosthogAnalytics } from "../../../PosthogAnalytics"; interface IAddReplyOpts { permalinkCreator?: RoomPermalinkCreator; @@ -344,6 +346,13 @@ export class SendMessageComposer extends React.Component({ + eventName: "Composer", + isEditing: false, + inThread: this.props.relation?.rel_type === RelationType.Thread, + isReply: !!this.props.replyToEvent, + }); + // Replace emoticon at the end of the message if (SettingsStore.getValue('MessageComposerInput.autoReplaceEmoji')) { const indexOfLastPart = model.parts.length - 1; diff --git a/src/components/views/settings/tabs/room/GeneralRoomSettingsTab.tsx b/src/components/views/settings/tabs/room/GeneralRoomSettingsTab.tsx index df3272a1fb..203ad321c9 100644 --- a/src/components/views/settings/tabs/room/GeneralRoomSettingsTab.tsx +++ b/src/components/views/settings/tabs/room/GeneralRoomSettingsTab.tsx @@ -18,7 +18,7 @@ import React, { ContextType } from 'react'; import { _t } from "../../../../../languageHandler"; import RoomProfileSettings from "../../../room_settings/RoomProfileSettings"; -import AccessibleButton from "../../../elements/AccessibleButton"; +import AccessibleButton, { ButtonEvent } from "../../../elements/AccessibleButton"; import dis from "../../../../../dispatcher/dispatcher"; import MatrixClientContext from "../../../../../contexts/MatrixClientContext"; import SettingsStore from "../../../../../settings/SettingsStore"; @@ -27,6 +27,7 @@ import { replaceableComponent } from "../../../../../utils/replaceableComponent" import UrlPreviewSettings from "../../../room_settings/UrlPreviewSettings"; import RelatedGroupSettings from "../../../room_settings/RelatedGroupSettings"; import AliasSettings from "../../../room_settings/AliasSettings"; +import PosthogTrackers from "../../../../../PosthogTrackers"; interface IProps { roomId: string; @@ -49,11 +50,13 @@ export default class GeneralRoomSettingsTab extends React.Component { + private onLeaveClick = (ev: ButtonEvent): void => { dis.dispatch({ action: 'leave_room', room_id: this.props.roomId, }); + + PosthogTrackers.trackInteraction("WebRoomSettingsLeaveButton", ev); }; public render(): JSX.Element {