From 1fe8f8902dd76ad388ea1ceec8e5b3429405345b Mon Sep 17 00:00:00 2001 From: Till JS Date: Wed, 25 Mar 2026 12:12:01 +0100 Subject: [PATCH] feat(analytics): add custom event tracking to NutriPhi and ManaDeck Add NutriPhiEvents (mealAdded, mealDeleted, photoAnalyzed, textAnalyzed, goalsUpdated, favoriteSaved, favoriteUsed) to shared analytics utils. Add deckDeleted and cardDeleted to ManaDeckEvents. Wire up event calls in NutriPhi meals store and ManaDeck deck/card stores. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../apps/web/src/lib/stores/cardStore.svelte.ts | 3 +++ .../apps/web/src/lib/stores/deckStore.svelte.ts | 3 +++ .../apps/web/src/lib/stores/meals.svelte.ts | 3 +++ packages/shared-utils/src/analytics.ts | 16 ++++++++++++++++ 4 files changed, 25 insertions(+) diff --git a/apps/manadeck/apps/web/src/lib/stores/cardStore.svelte.ts b/apps/manadeck/apps/web/src/lib/stores/cardStore.svelte.ts index 5fb41522b..19ac0adcc 100644 --- a/apps/manadeck/apps/web/src/lib/stores/cardStore.svelte.ts +++ b/apps/manadeck/apps/web/src/lib/stores/cardStore.svelte.ts @@ -1,6 +1,7 @@ import type { Card, CreateCardInput, UpdateCardInput } from '$lib/types/card'; import { PUBLIC_API_URL } from '$env/static/public'; import { authService } from '$lib/auth'; +import { ManaDeckEvents } from '@manacore/shared-utils/analytics'; // Svelte 5 runes-based card store let cards = $state([]); @@ -128,6 +129,7 @@ export const cardStore = { if (response.card) { const card = mapCardFromApi(response.card); cards = [...cards, card]; + ManaDeckEvents.cardCreated(); return card; } return null; @@ -191,6 +193,7 @@ export const cardStore = { // Remove from list cards = cards.filter((c) => c.id !== id); + ManaDeckEvents.cardDeleted(); // Clear current if it's the same if (currentCard?.id === id) { diff --git a/apps/manadeck/apps/web/src/lib/stores/deckStore.svelte.ts b/apps/manadeck/apps/web/src/lib/stores/deckStore.svelte.ts index 255a390f1..a3c8eb3d1 100644 --- a/apps/manadeck/apps/web/src/lib/stores/deckStore.svelte.ts +++ b/apps/manadeck/apps/web/src/lib/stores/deckStore.svelte.ts @@ -1,6 +1,7 @@ import type { Deck, CreateDeckInput, UpdateDeckInput } from '$lib/types/deck'; import { PUBLIC_API_URL } from '$env/static/public'; import { authService } from '$lib/auth'; +import { ManaDeckEvents } from '@manacore/shared-utils/analytics'; // Svelte 5 runes-based deck store let decks = $state([]); @@ -109,6 +110,7 @@ export const deckStore = { if (response.deck) { const deck = { ...response.deck, card_count: 0 }; decks = [deck, ...decks]; + ManaDeckEvents.deckCreated(); return deck; } return null; @@ -165,6 +167,7 @@ export const deckStore = { // Remove from list decks = decks.filter((d) => d.id !== id); + ManaDeckEvents.deckDeleted(); // Clear current if it's the same if (currentDeck?.id === id) { diff --git a/apps/nutriphi/apps/web/src/lib/stores/meals.svelte.ts b/apps/nutriphi/apps/web/src/lib/stores/meals.svelte.ts index f1a55c20a..f520b333a 100644 --- a/apps/nutriphi/apps/web/src/lib/stores/meals.svelte.ts +++ b/apps/nutriphi/apps/web/src/lib/stores/meals.svelte.ts @@ -1,5 +1,6 @@ import { apiClient } from '$lib/api/client'; import type { Meal, MealNutrition, DailySummary } from '@nutriphi/shared'; +import { NutriPhiEvents } from '@manacore/shared-utils/analytics'; interface MealWithNutrition extends Meal { nutrition: MealNutrition | null; @@ -59,6 +60,7 @@ class MealsStore { const meal = await apiClient.post('/meals', mealData); this.meals = [...this.meals, meal]; await this.fetchDailySummary(); + NutriPhiEvents.mealAdded(mealData.mealType, mealData.inputType); return meal; } catch (err) { const message = @@ -74,6 +76,7 @@ class MealsStore { await apiClient.delete(`/meals/${mealId}`); this.meals = this.meals.filter((m) => m.id !== mealId); await this.fetchDailySummary(); + NutriPhiEvents.mealDeleted(); } catch (err) { this.deleteError = err instanceof Error ? err.message : 'Mahlzeit konnte nicht gelöscht werden'; diff --git a/packages/shared-utils/src/analytics.ts b/packages/shared-utils/src/analytics.ts index 1591434de..d023d0475 100644 --- a/packages/shared-utils/src/analytics.ts +++ b/packages/shared-utils/src/analytics.ts @@ -249,8 +249,10 @@ export const ContactsEvents = { */ export const ManaDeckEvents = { deckCreated: () => trackEvent('deck_created'), + deckDeleted: () => trackEvent('deck_deleted'), deckStudied: (cardsCount: number) => trackEvent('deck_studied', { cards: cardsCount }), cardCreated: () => trackEvent('card_created'), + cardDeleted: () => trackEvent('card_deleted'), cardReviewed: (rating: 1 | 2 | 3 | 4 | 5) => trackEvent('card_reviewed', { rating }), aiCardsGenerated: (count: number) => trackEvent('ai_cards_generated', { count }), }; @@ -297,6 +299,20 @@ export const SkillTreeEvents = { trackEvent('xp_added', { xp, leveled_up: leveledUp }), }; +/** + * NutriPhi App Events + */ +export const NutriPhiEvents = { + mealAdded: (mealType: string, inputType: string) => + trackEvent('meal_added', { meal_type: mealType, input_type: inputType }), + mealDeleted: () => trackEvent('meal_deleted'), + photoAnalyzed: () => trackEvent('photo_analyzed'), + textAnalyzed: () => trackEvent('text_analyzed'), + goalsUpdated: () => trackEvent('goals_updated'), + favoriteSaved: () => trackEvent('favorite_saved'), + favoriteUsed: () => trackEvent('favorite_used'), +}; + /** * Planta App Events */