From bade0a17dbef07be743008dbeba373ff35493766 Mon Sep 17 00:00:00 2001 From: Till JS Date: Wed, 25 Mar 2026 09:34:07 +0100 Subject: [PATCH] feat(analytics): add custom event tracking to Storage app Add StorageEvents helper (11 events) and integrate tracking into: - Files store: download, delete, favorite, view mode toggle - Shared page: share link copy/delete - Trash page: restore, empty trash - Search page: search performed with results count Updates ManaScore analytics from 3/5 to 4/5 (customEvents: true). Co-Authored-By: Claude Opus 4.6 (1M context) --- .../content/manascore/2026-03-19-storage.md | 2 +- .../apps/web/src/lib/stores/files.svelte.ts | 8 +++++++- .../apps/web/src/routes/search/+page.svelte | 2 ++ .../apps/web/src/routes/shared/+page.svelte | 3 +++ .../apps/web/src/routes/trash/+page.svelte | 3 +++ packages/shared-utils/src/analytics.ts | 18 ++++++++++++++++++ 6 files changed, 34 insertions(+), 2 deletions(-) diff --git a/apps/manacore/apps/landing/src/content/manascore/2026-03-19-storage.md b/apps/manacore/apps/landing/src/content/manascore/2026-03-19-storage.md index d06b8b07b..d394a3c5a 100644 --- a/apps/manacore/apps/landing/src/content/manascore/2026-03-19-storage.md +++ b/apps/manacore/apps/landing/src/content/manascore/2026-03-19-storage.md @@ -21,7 +21,7 @@ scores: ux: 75 analytics: pageViewTracking: true - customEvents: false + customEvents: true authTracking: true landingTracking: false publicDashboard: true diff --git a/apps/storage/apps/web/src/lib/stores/files.svelte.ts b/apps/storage/apps/web/src/lib/stores/files.svelte.ts index d98ae0697..1dbe973db 100644 --- a/apps/storage/apps/web/src/lib/stores/files.svelte.ts +++ b/apps/storage/apps/web/src/lib/stores/files.svelte.ts @@ -4,7 +4,7 @@ import { filesApi, foldersApi } from '$lib/api/client'; import type { StorageFile, StorageFolder } from '$lib/api/client'; -import { trackEvent } from '@manacore/shared-utils/analytics'; +import { trackEvent, StorageEvents } from '@manacore/shared-utils/analytics'; let files = $state([]); let folders = $state([]); @@ -35,6 +35,7 @@ export const filesStore = { setViewMode(mode: 'grid' | 'list') { viewMode = mode; + StorageEvents.viewModeChanged(mode); if (typeof localStorage !== 'undefined') { localStorage.setItem('storage-view-mode', mode); } @@ -114,6 +115,7 @@ export const filesStore = { const result = await filesApi.delete(id); if (!result.error) { files = files.filter((f) => f.id !== id); + StorageEvents.fileDeleted(); } return result; }, @@ -122,6 +124,7 @@ export const filesStore = { const result = await foldersApi.delete(id); if (!result.error) { folders = folders.filter((f) => f.id !== id); + StorageEvents.folderDeleted(); } return result; }, @@ -130,6 +133,7 @@ export const filesStore = { const result = await filesApi.toggleFavorite(id); if (result.data) { files = files.map((f) => (f.id === id ? result.data! : f)); + StorageEvents.fileFavorited(result.data.isFavorite); } return result; }, @@ -138,6 +142,7 @@ export const filesStore = { const result = await foldersApi.toggleFavorite(id); if (result.data) { folders = folders.map((f) => (f.id === id ? result.data! : f)); + StorageEvents.folderFavorited(result.data.isFavorite); } return result; }, @@ -185,6 +190,7 @@ export const filesStore = { a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); + StorageEvents.fileDownloaded(); return true; } return false; diff --git a/apps/storage/apps/web/src/routes/search/+page.svelte b/apps/storage/apps/web/src/routes/search/+page.svelte index a0938a148..48bc91134 100644 --- a/apps/storage/apps/web/src/routes/search/+page.svelte +++ b/apps/storage/apps/web/src/routes/search/+page.svelte @@ -4,6 +4,7 @@ import { onMount } from 'svelte'; import { MagnifyingGlass, GridFour, List } from '@manacore/shared-icons'; import { searchApi } from '$lib/api/client'; + import { StorageEvents } from '@manacore/shared-utils/analytics'; import type { StorageFile, StorageFolder } from '$lib/api/client'; import { filesStore } from '$lib/stores/files.svelte'; import FileGrid from '$lib/components/files/FileGrid.svelte'; @@ -38,6 +39,7 @@ if (result.data) { files = result.data.files; folders = result.data.folders; + StorageEvents.searchPerformed(files.length + folders.length); } loading = false; diff --git a/apps/storage/apps/web/src/routes/shared/+page.svelte b/apps/storage/apps/web/src/routes/shared/+page.svelte index 8d2ff292c..79121fb27 100644 --- a/apps/storage/apps/web/src/routes/shared/+page.svelte +++ b/apps/storage/apps/web/src/routes/shared/+page.svelte @@ -2,6 +2,7 @@ import { onMount } from 'svelte'; import { ShareNetwork, Link, Copy, Trash } from '@manacore/shared-icons'; import { sharesApi } from '$lib/api/client'; + import { StorageEvents } from '@manacore/shared-utils/analytics'; import type { Share } from '$lib/api/client'; import { toastStore } from '@manacore/shared-ui'; @@ -30,6 +31,7 @@ async function copyShareLink(token: string) { const url = `${window.location.origin}/s/${token}`; await navigator.clipboard.writeText(url); + StorageEvents.shareLinkCopied(); toastStore.success('Link kopiert!'); } @@ -41,6 +43,7 @@ toastStore.error(result.error); } else { shares = shares.filter((s) => s.id !== id); + StorageEvents.shareLinkDeleted(); toastStore.success('Share-Link gelöscht'); } } diff --git a/apps/storage/apps/web/src/routes/trash/+page.svelte b/apps/storage/apps/web/src/routes/trash/+page.svelte index 9300e9de9..74fde5986 100644 --- a/apps/storage/apps/web/src/routes/trash/+page.svelte +++ b/apps/storage/apps/web/src/routes/trash/+page.svelte @@ -2,6 +2,7 @@ import { onMount } from 'svelte'; import { Trash, ArrowCounterClockwise, Warning } from '@manacore/shared-icons'; import { trashApi } from '$lib/api/client'; + import { StorageEvents } from '@manacore/shared-utils/analytics'; import type { StorageFile, StorageFolder } from '$lib/api/client'; import { toastStore } from '@manacore/shared-ui'; @@ -39,6 +40,7 @@ } else { folders = folders.filter((f) => f.id !== id); } + StorageEvents.trashRestored(type); toastStore.success('Wiederhergestellt'); } } @@ -68,6 +70,7 @@ } else { files = []; folders = []; + StorageEvents.trashEmptied(); toastStore.success('Papierkorb geleert'); } } diff --git a/packages/shared-utils/src/analytics.ts b/packages/shared-utils/src/analytics.ts index b8c0bbf16..0a3ab5fef 100644 --- a/packages/shared-utils/src/analytics.ts +++ b/packages/shared-utils/src/analytics.ts @@ -275,6 +275,24 @@ export const ManaCoreEvents = { profileUpdated: () => trackEvent('profile_updated'), }; +/** + * Storage App Events + */ +export const StorageEvents = { + fileDownloaded: () => trackEvent('file_downloaded'), + fileDeleted: () => trackEvent('file_deleted'), + fileFavorited: (favorited: boolean) => trackEvent('file_favorited', { favorited }), + folderDeleted: () => trackEvent('folder_deleted'), + folderFavorited: (favorited: boolean) => trackEvent('folder_favorited', { favorited }), + shareLinkCopied: () => trackEvent('share_link_copied'), + shareLinkDeleted: () => trackEvent('share_link_deleted'), + trashRestored: (type: string) => trackEvent('trash_restored', { type }), + trashEmptied: () => trackEvent('trash_emptied'), + searchPerformed: (resultsCount: number) => + trackEvent('search_performed', { results: resultsCount }), + viewModeChanged: (mode: string) => trackEvent('view_mode_changed', { mode }), +}; + /** * Mukke App Events */