From 3075e515bdf134dc2756e5bd2a666f16dc450a27 Mon Sep 17 00:00:00 2001 From: Till JS Date: Wed, 25 Mar 2026 09:59:42 +0100 Subject: [PATCH] feat(analytics): add custom event tracking to Photos app Add PhotosEvents helper (8 events) and integrate tracking into: - Photos store: favorite toggle, delete, filters applied - Albums store: create, delete, add/remove photos - Upload page: photo uploaded Updates ManaScore analytics from 3/5 to 4/5 (customEvents: true). Co-Authored-By: Claude Opus 4.6 (1M context) --- .../src/content/manascore/2026-03-19-photos.md | 2 +- .../apps/web/src/lib/stores/albums.svelte.ts | 5 +++++ .../apps/web/src/lib/stores/photos.svelte.ts | 4 ++++ .../apps/web/src/routes/(app)/upload/+page.svelte | 2 ++ packages/shared-utils/src/analytics.ts | 14 ++++++++++++++ 5 files changed, 26 insertions(+), 1 deletion(-) diff --git a/apps/manacore/apps/landing/src/content/manascore/2026-03-19-photos.md b/apps/manacore/apps/landing/src/content/manascore/2026-03-19-photos.md index ce102eccb..95f2a48e5 100644 --- a/apps/manacore/apps/landing/src/content/manascore/2026-03-19-photos.md +++ b/apps/manacore/apps/landing/src/content/manascore/2026-03-19-photos.md @@ -17,7 +17,7 @@ scores: ux: 55 analytics: pageViewTracking: true - customEvents: false + customEvents: true authTracking: true landingTracking: false publicDashboard: true diff --git a/apps/photos/apps/web/src/lib/stores/albums.svelte.ts b/apps/photos/apps/web/src/lib/stores/albums.svelte.ts index 6cdae860b..d2d774062 100644 --- a/apps/photos/apps/web/src/lib/stores/albums.svelte.ts +++ b/apps/photos/apps/web/src/lib/stores/albums.svelte.ts @@ -3,6 +3,7 @@ */ import { api } from '$lib/api/client'; +import { PhotosEvents } from '@manacore/shared-utils/analytics'; import type { Album, Photo } from '@photos/shared'; // State @@ -92,6 +93,7 @@ export const albumStore = { } if (result.data) { albums = [...albums, result.data]; + PhotosEvents.albumCreated(); return result.data; } return null; @@ -138,6 +140,7 @@ export const albumStore = { return false; } albums = albums.filter((a) => a.id !== id); + PhotosEvents.albumDeleted(); if (currentAlbum?.id === id) { currentAlbum = null; albumPhotos = []; @@ -159,6 +162,7 @@ export const albumStore = { error = result.error.message; return false; } + PhotosEvents.photosAddedToAlbum(mediaIds.length); // Reload album to get updated items if (currentAlbum?.id === albumId) { await this.loadAlbum(albumId); @@ -181,6 +185,7 @@ export const albumStore = { return false; } albumPhotos = albumPhotos.filter((p) => p.id !== mediaId); + PhotosEvents.photoRemovedFromAlbum(); return true; } catch (e) { error = e instanceof Error ? e.message : 'Failed to remove photo from album'; diff --git a/apps/photos/apps/web/src/lib/stores/photos.svelte.ts b/apps/photos/apps/web/src/lib/stores/photos.svelte.ts index 4d92f9e6d..acbcc0b56 100644 --- a/apps/photos/apps/web/src/lib/stores/photos.svelte.ts +++ b/apps/photos/apps/web/src/lib/stores/photos.svelte.ts @@ -3,6 +3,7 @@ */ import { api } from '$lib/api/client'; +import { PhotosEvents } from '@manacore/shared-utils/analytics'; import type { Photo, PhotoFilters, PhotoStats } from '@photos/shared'; // State @@ -104,6 +105,7 @@ export const photoStore = { */ async setFilters(newFilters: Partial) { filters = { ...filters, ...newFilters, offset: 0 }; + PhotosEvents.filtersApplied(); await this.loadPhotos(true); }, @@ -135,6 +137,7 @@ export const photoStore = { try { const result = await api.post<{ isFavorited: boolean }>(`/favorites/${mediaId}/toggle`); if (result.data) { + PhotosEvents.photoFavorited(result.data.isFavorited); // Update photo in list photos = photos.map((p) => p.id === mediaId ? { ...p, isFavorited: result.data!.isFavorited } : p @@ -160,6 +163,7 @@ export const photoStore = { return false; } photos = photos.filter((p) => p.id !== mediaId); + PhotosEvents.photoDeleted(); if (selectedPhoto?.id === mediaId) { selectedPhoto = null; } diff --git a/apps/photos/apps/web/src/routes/(app)/upload/+page.svelte b/apps/photos/apps/web/src/routes/(app)/upload/+page.svelte index d5e6f16f6..ca6ce9e64 100644 --- a/apps/photos/apps/web/src/routes/(app)/upload/+page.svelte +++ b/apps/photos/apps/web/src/routes/(app)/upload/+page.svelte @@ -2,6 +2,7 @@ import { _ } from 'svelte-i18n'; import { goto } from '$app/navigation'; import { uploadWithAuth } from '$lib/api/client'; + import { PhotosEvents } from '@manacore/shared-utils/analytics'; import UploadDropzone from '$lib/components/upload/UploadDropzone.svelte'; interface UploadFile { @@ -52,6 +53,7 @@ files[i].status = 'success'; files[i].progress = 100; + PhotosEvents.photoUploaded(); } catch (e) { files[i].status = 'error'; files[i].error = e instanceof Error ? e.message : 'Upload failed'; diff --git a/packages/shared-utils/src/analytics.ts b/packages/shared-utils/src/analytics.ts index 0a3ab5fef..b248aadde 100644 --- a/packages/shared-utils/src/analytics.ts +++ b/packages/shared-utils/src/analytics.ts @@ -275,6 +275,20 @@ export const ManaCoreEvents = { profileUpdated: () => trackEvent('profile_updated'), }; +/** + * Photos App Events + */ +export const PhotosEvents = { + photoUploaded: () => trackEvent('photo_uploaded'), + photoFavorited: (favorited: boolean) => trackEvent('photo_favorited', { favorited }), + photoDeleted: () => trackEvent('photo_deleted'), + albumCreated: () => trackEvent('album_created'), + albumDeleted: () => trackEvent('album_deleted'), + photosAddedToAlbum: (count: number) => trackEvent('photos_added_to_album', { count }), + photoRemovedFromAlbum: () => trackEvent('photo_removed_from_album'), + filtersApplied: () => trackEvent('filters_applied'), +}; + /** * Storage App Events */