From 45c11a1730116d7b62244376cfa7ed3c094470be Mon Sep 17 00:00:00 2001 From: Till JS Date: Sun, 22 Mar 2026 19:07:06 +0100 Subject: [PATCH] feat(analytics): add event tracking to picture, storage, clock, mukke, planta Track key user actions in remaining web apps: - Picture: image_generated (with model ID), generation_failed - Storage: file_uploaded (with size in KB), folder_created - Clock: timer_started (with timer type) - Mukke: song_uploaded - Planta: plant_created Co-Authored-By: Claude Opus 4.6 (1M context) --- apps/clock/apps/web/src/lib/stores/timers.svelte.ts | 2 ++ apps/mukke/apps/web/src/lib/stores/library.svelte.ts | 2 ++ .../apps/web/src/lib/components/generate/GenerateForm.svelte | 3 +++ apps/planta/apps/web/src/lib/api/plants.ts | 2 ++ apps/storage/apps/web/src/lib/stores/files.svelte.ts | 3 +++ 5 files changed, 12 insertions(+) diff --git a/apps/clock/apps/web/src/lib/stores/timers.svelte.ts b/apps/clock/apps/web/src/lib/stores/timers.svelte.ts index 3da6805de..4813fda64 100644 --- a/apps/clock/apps/web/src/lib/stores/timers.svelte.ts +++ b/apps/clock/apps/web/src/lib/stores/timers.svelte.ts @@ -7,6 +7,7 @@ import { api } from '$lib/api/client'; import { sessionTimersStore } from './session-timers.svelte'; import { authStore } from './auth.svelte'; import type { Timer, CreateTimerInput, UpdateTimerInput } from '@clock/shared'; +import { ClockEvents } from '@manacore/shared-utils/analytics'; // State let timers = $state([]); @@ -134,6 +135,7 @@ export const timersStore = { if (response.data) { timers = timers.map((t) => (t.id === id ? response.data! : t)); + ClockEvents.timerStarted(response.data.type as 'pomodoro' | 'stopwatch' | 'countdown'); } return { success: true, data: response.data }; }, diff --git a/apps/mukke/apps/web/src/lib/stores/library.svelte.ts b/apps/mukke/apps/web/src/lib/stores/library.svelte.ts index 380415d0b..a28aebfd1 100644 --- a/apps/mukke/apps/web/src/lib/stores/library.svelte.ts +++ b/apps/mukke/apps/web/src/lib/stores/library.svelte.ts @@ -8,6 +8,7 @@ import type { SortDirection, } from '@mukke/shared'; import { authStore } from './auth.svelte'; +import { trackEvent } from '@manacore/shared-utils/analytics'; interface LibraryState { songs: Song[]; @@ -267,6 +268,7 @@ function createLibraryStore() { }); state.songs = [uploadData.song, ...state.songs]; + trackEvent('song_uploaded'); return uploadData.song; }, diff --git a/apps/picture/apps/web/src/lib/components/generate/GenerateForm.svelte b/apps/picture/apps/web/src/lib/components/generate/GenerateForm.svelte index 26764b7ee..2db70a3ec 100644 --- a/apps/picture/apps/web/src/lib/components/generate/GenerateForm.svelte +++ b/apps/picture/apps/web/src/lib/components/generate/GenerateForm.svelte @@ -9,6 +9,7 @@ import Button from '../ui/Button.svelte'; import Card from '../ui/Card.svelte'; import { XCircle, Lightning } from '@manacore/shared-icons'; + import { PictureEvents } from '@manacore/shared-utils/analytics'; let prompt = $state(''); let negativePrompt = $state(''); @@ -86,12 +87,14 @@ // Success - redirect to gallery generationProgress.set('Complete!'); + PictureEvents.imageGenerated(selectedModelId); setTimeout(() => { goto('/app/gallery'); }, 1000); } catch (error) { console.error('Generation error:', error); generationError.set(error instanceof Error ? error.message : 'Failed to generate image'); + PictureEvents.generationFailed(error instanceof Error ? error.message : 'unknown'); } finally { isGenerating.set(false); } diff --git a/apps/planta/apps/web/src/lib/api/plants.ts b/apps/planta/apps/web/src/lib/api/plants.ts index e6b337b17..c28b8fc56 100644 --- a/apps/planta/apps/web/src/lib/api/plants.ts +++ b/apps/planta/apps/web/src/lib/api/plants.ts @@ -4,6 +4,7 @@ import { fetchApi } from './client'; import type { Plant, PlantWithDetails, CreatePlantDto, UpdatePlantDto } from '@planta/shared'; +import { trackEvent } from '@manacore/shared-utils/analytics'; export const plantsApi = { async getAll(): Promise { @@ -33,6 +34,7 @@ export const plantsApi = { console.error('Failed to create plant:', error); return null; } + trackEvent('plant_created'); return data; }, 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 903bd9361..d98ae0697 100644 --- a/apps/storage/apps/web/src/lib/stores/files.svelte.ts +++ b/apps/storage/apps/web/src/lib/stores/files.svelte.ts @@ -4,6 +4,7 @@ import { filesApi, foldersApi } from '$lib/api/client'; import type { StorageFile, StorageFolder } from '$lib/api/client'; +import { trackEvent } from '@manacore/shared-utils/analytics'; let files = $state([]); let folders = $state([]); @@ -95,6 +96,7 @@ export const filesStore = { const result = await filesApi.upload(file, currentFolder?.id); if (result.data) { files = [...files, result.data]; + trackEvent('file_uploaded', { size: Math.round(file.size / 1024) }); } return result; }, @@ -103,6 +105,7 @@ export const filesStore = { const result = await foldersApi.create(name, currentFolder?.id, color); if (result.data) { folders = [...folders, result.data]; + trackEvent('folder_created'); } return result; },