diff --git a/package.json b/package.json index b242fb213fb..9e640c5816f 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "@fontsource/fira-code": "^5", "@fontsource/inter": "^5", "@formatjs/intl-segmenter": "^12.0.0", - "@matrix-org/analytics-events": "^0.31.0", + "@matrix-org/analytics-events": "^0.32.0", "@matrix-org/emojibase-bindings": "^1.5.0", "@matrix-org/react-sdk-module-api": "^2.4.0", "@sentry/browser": "^10.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d85789e15ef..088cc68c924 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -100,8 +100,8 @@ importers: specifier: ^12.0.0 version: 12.1.1 '@matrix-org/analytics-events': - specifier: ^0.31.0 - version: 0.31.0 + specifier: ^0.32.0 + version: 0.32.0 '@matrix-org/emojibase-bindings': specifier: ^1.5.0 version: 1.5.0 @@ -2642,8 +2642,8 @@ packages: '@maplibre/vt-pbf@4.2.1': resolution: {integrity: sha512-IxZBGq/+9cqf2qdWlFuQ+ZfoMhWpxDUGQZ/poPHOJBvwMUT1GuxLo6HgYTou+xxtsOsjfbcjI8PZaPCtmt97rA==} - '@matrix-org/analytics-events@0.31.0': - resolution: {integrity: sha512-rZrtHt6X1cnleWPPSp56fngYBiq2Db1jQt+bATEUlDwwiMCrG3D5ojYqOQ03MlgySLIZLBAAam//bZAqiGWOwQ==} + '@matrix-org/analytics-events@0.32.0': + resolution: {integrity: sha512-Z5hl4wJdIvskFCOzHAh/7tQKlyvJ/5/JdvfTTySuJ/v47VmkCGvkdDD6ODT9+15psj3O8Cc2Ofgh2KqDJjd6kg==} '@matrix-org/emojibase-bindings@1.5.0': resolution: {integrity: sha512-+W9/ow2Z3iQa7ZOF698PBhwNcgGkn36B5Sr8VDPx8N8CH7+Uw+7TrtbtKPZVdgf4m/THmgmfX40jS5YDBsLaYg==} @@ -12612,7 +12612,7 @@ snapshots: pbf: 4.0.1 supercluster: 8.0.1 - '@matrix-org/analytics-events@0.31.0': {} + '@matrix-org/analytics-events@0.32.0': {} '@matrix-org/emojibase-bindings@1.5.0': dependencies: diff --git a/src/PosthogTrackers.ts b/src/PosthogTrackers.ts index 2650403d3b0..a3f00e1117e 100644 --- a/src/PosthogTrackers.ts +++ b/src/PosthogTrackers.ts @@ -10,10 +10,12 @@ import { PureComponent, type SyntheticEvent } from "react"; import { type WebScreen as ScreenEvent } from "@matrix-org/analytics-events/types/typescript/WebScreen"; import { type Interaction as InteractionEvent } from "@matrix-org/analytics-events/types/typescript/Interaction"; import { type PinUnpinAction } from "@matrix-org/analytics-events/types/typescript/PinUnpinAction"; +import { type RoomListSortingAlgorithmChanged } from "@matrix-org/analytics-events/types/typescript/RoomListSortingAlgorithmChanged"; import PageType from "./PageTypes"; import Views from "./Views"; import { PosthogAnalytics } from "./PosthogAnalytics"; +import { SortingAlgorithm } from "./stores/room-list-v3/skip-list/sorters"; export type ScreenName = ScreenEvent["$current_url"]; export type InteractionName = InteractionEvent["name"]; @@ -38,6 +40,12 @@ const loggedInPageTypeMap: Record = { [PageType.UserView]: "User", }; +const SortingAlgorithmMap: Record = { + [SortingAlgorithm.Recency]: "Activity", + [SortingAlgorithm.Unread]: "Unread", + [SortingAlgorithm.Alphabetic]: "Alphabetic", +}; + export default class PosthogTrackers { private static internalInstance: PosthogTrackers; @@ -112,6 +120,22 @@ export default class PosthogTrackers { from, }); } + + /** + * Track when the user chooses a different sorting algorithm for the room-list. + * @param oldAlgorithm - The old algorithm. + * @param newAlgorithm - The new algorithm. + */ + public static trackRoomListSortingAlgorithmChange( + oldAlgorithm: SortingAlgorithm, + newAlgorithm: SortingAlgorithm, + ): void { + PosthogAnalytics.instance.trackEvent({ + eventName: "RoomListSortingAlgorithmChanged", + oldAlgorithm: SortingAlgorithmMap[oldAlgorithm], + newAlgorithm: SortingAlgorithmMap[newAlgorithm], + }); + } } export class PosthogScreenTracker extends PureComponent<{ screenName: ScreenName }> { diff --git a/src/viewmodels/room-list/RoomListHeaderViewModel.ts b/src/viewmodels/room-list/RoomListHeaderViewModel.ts index e99268190c8..8a5547e6e97 100644 --- a/src/viewmodels/room-list/RoomListHeaderViewModel.ts +++ b/src/viewmodels/room-list/RoomListHeaderViewModel.ts @@ -170,20 +170,26 @@ export class RoomListHeaderViewModel }; public sort = (option: SortOption): void => { - let sortingAlgorithm: SortingAlgorithm; + const oldSortingAlgorithm = RoomListStoreV3.instance.activeSortAlgorithm; + let newSortingAlgorithm: SortingAlgorithm; switch (option) { case "alphabetical": - sortingAlgorithm = SortingAlgorithm.Alphabetic; + newSortingAlgorithm = SortingAlgorithm.Alphabetic; break; case "recent": - sortingAlgorithm = SortingAlgorithm.Recency; + newSortingAlgorithm = SortingAlgorithm.Recency; break; case "unread-first": - sortingAlgorithm = SortingAlgorithm.Unread; + newSortingAlgorithm = SortingAlgorithm.Unread; break; } - RoomListStoreV3.instance.resort(sortingAlgorithm); + RoomListStoreV3.instance.resort(newSortingAlgorithm); this.snapshot.merge({ activeSortOption: option }); + + // Record analytics for this action + if (oldSortingAlgorithm) { + PosthogTrackers.trackRoomListSortingAlgorithmChange(oldSortingAlgorithm, newSortingAlgorithm); + } }; public toggleMessagePreview = (): void => { diff --git a/test/viewmodels/room-list/RoomListHeaderViewModel-test.ts b/test/viewmodels/room-list/RoomListHeaderViewModel-test.ts index 7025abe7c1a..936389603db 100644 --- a/test/viewmodels/room-list/RoomListHeaderViewModel-test.ts +++ b/test/viewmodels/room-list/RoomListHeaderViewModel-test.ts @@ -25,6 +25,7 @@ import { } from "../../../src/utils/space"; import { createTestClient, mkSpace } from "../../test-utils"; import { createRoom, hasCreateRoomRights } from "../../../src/viewmodels/room-list/utils"; +import PosthogTrackers from "../../../src/PosthogTrackers"; jest.mock("../../../src/PosthogTrackers", () => ({ trackInteraction: jest.fn(), @@ -276,10 +277,25 @@ describe("RoomListHeaderViewModel", () => { const resortSpy = jest.spyOn(RoomListStoreV3.instance, "resort").mockImplementation(jest.fn()); vm = new RoomListHeaderViewModel({ matrixClient, spaceStore: SpaceStore.instance }); vm.sort(option); - expect(resortSpy).toHaveBeenCalledWith(expectedAlgorithm); }); + it("should track analytics on resort", () => { + jest.spyOn(RoomListStoreV3.instance, "activeSortAlgorithm", "get").mockReturnValue( + SortingAlgorithm.Alphabetic, + ); + PosthogTrackers.trackRoomListSortingAlgorithmChange = jest.fn(); + + vm = new RoomListHeaderViewModel({ matrixClient, spaceStore: SpaceStore.instance }); + jest.spyOn(RoomListStoreV3.instance, "resort").mockImplementation(jest.fn()); + vm.sort("unread-first"); + + expect(PosthogTrackers.trackRoomListSortingAlgorithmChange).toHaveBeenCalledWith( + SortingAlgorithm.Alphabetic, + SortingAlgorithm.Unread, + ); + }); + it("should toggle message preview from enabled to disabled", () => { jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName: string) => { if (settingName === "RoomList.showMessagePreview") return true;