mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 20:01:09 +02:00
refactor(analytics): add module context to all Umami events
Resolves event name collisions in the unified app (e.g. view_changed, deck_created, search_performed) by adding a `module` property to every tracked event via createModuleTracker. Also fixes duplicate tracking in Planta routes (now only tracked in mutations.ts). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
779a8ba322
commit
5280cc6dc7
6 changed files with 260 additions and 224 deletions
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
import { db } from '$lib/data/database';
|
import { db } from '$lib/data/database';
|
||||||
import { toPlant, toWateringSchedule } from './queries';
|
import { toPlant, toWateringSchedule } from './queries';
|
||||||
import { trackEvent } from '@manacore/shared-utils/analytics';
|
import { PlantaEvents } from '@manacore/shared-utils/analytics';
|
||||||
import type {
|
import type {
|
||||||
LocalPlant,
|
LocalPlant,
|
||||||
LocalWateringSchedule,
|
LocalWateringSchedule,
|
||||||
|
|
@ -39,7 +39,7 @@ export const plantMutations = {
|
||||||
updatedAt: now,
|
updatedAt: now,
|
||||||
};
|
};
|
||||||
await db.table('plants').add(newLocal);
|
await db.table('plants').add(newLocal);
|
||||||
trackEvent('plant_created');
|
PlantaEvents.plantCreated();
|
||||||
return toPlant(newLocal);
|
return toPlant(newLocal);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Failed to create plant:', e);
|
console.error('Failed to create plant:', e);
|
||||||
|
|
@ -78,7 +78,7 @@ export const plantMutations = {
|
||||||
deletedAt: new Date().toISOString(),
|
deletedAt: new Date().toISOString(),
|
||||||
updatedAt: new Date().toISOString(),
|
updatedAt: new Date().toISOString(),
|
||||||
});
|
});
|
||||||
trackEvent('plant_deleted');
|
PlantaEvents.plantDeleted();
|
||||||
return true;
|
return true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Failed to delete plant:', e);
|
console.error('Failed to delete plant:', e);
|
||||||
|
|
@ -117,7 +117,7 @@ export const wateringMutations = {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
trackEvent('plant_watered');
|
PlantaEvents.plantWatered();
|
||||||
return true;
|
return true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Failed to log watering:', e);
|
console.error('Failed to log watering:', e);
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import { getContext } from 'svelte';
|
import { getContext } from 'svelte';
|
||||||
import { trackEvent } from '@manacore/shared-utils/analytics';
|
|
||||||
import { wateringMutations } from '$lib/modules/planta/mutations';
|
import { wateringMutations } from '$lib/modules/planta/mutations';
|
||||||
import {
|
import {
|
||||||
getActivePlants,
|
getActivePlants,
|
||||||
|
|
@ -49,10 +48,7 @@
|
||||||
|
|
||||||
async function handleWater(plantId: string, e: Event) {
|
async function handleWater(plantId: string, e: Event) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
const success = await wateringMutations.logWatering(plantId);
|
await wateringMutations.logWatering(plantId);
|
||||||
if (success) {
|
|
||||||
trackEvent('plant_watered');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import { getContext } from 'svelte';
|
import { getContext } from 'svelte';
|
||||||
import { trackEvent } from '@manacore/shared-utils/analytics';
|
|
||||||
import { plantMutations, wateringMutations } from '$lib/modules/planta/mutations';
|
import { plantMutations, wateringMutations } from '$lib/modules/planta/mutations';
|
||||||
import {
|
import {
|
||||||
getPlantById,
|
getPlantById,
|
||||||
|
|
@ -31,10 +30,7 @@
|
||||||
async function handleWater() {
|
async function handleWater() {
|
||||||
if (!plant) return;
|
if (!plant) return;
|
||||||
watering = true;
|
watering = true;
|
||||||
const success = await wateringMutations.logWatering(plant.id);
|
await wateringMutations.logWatering(plant.id);
|
||||||
if (success) {
|
|
||||||
trackEvent('plant_watered');
|
|
||||||
}
|
|
||||||
watering = false;
|
watering = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -43,10 +39,7 @@
|
||||||
if (!confirm(`Moechtest du "${plant.name}" wirklich loeschen?`)) return;
|
if (!confirm(`Moechtest du "${plant.name}" wirklich loeschen?`)) return;
|
||||||
|
|
||||||
const success = await plantMutations.delete(plant.id);
|
const success = await plantMutations.delete(plant.id);
|
||||||
if (success) {
|
if (success) goto('/planta');
|
||||||
trackEvent('plant_deleted');
|
|
||||||
goto('/planta');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatDate(date: Date | string | undefined | null): string {
|
function formatDate(date: Date | string | undefined | null): string {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import { plantMutations } from '$lib/modules/planta/mutations';
|
import { plantMutations } from '$lib/modules/planta/mutations';
|
||||||
import { trackEvent } from '@manacore/shared-utils/analytics';
|
|
||||||
|
|
||||||
let plantName = $state('');
|
let plantName = $state('');
|
||||||
let scientificName = $state('');
|
let scientificName = $state('');
|
||||||
|
|
@ -30,7 +29,6 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
trackEvent('plant_created');
|
|
||||||
goto(`/planta/${plant.id}`);
|
goto(`/planta/${plant.id}`);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ import {
|
||||||
function trackAuth(event: string, data?: Record<string, string | number | boolean>): void {
|
function trackAuth(event: string, data?: Record<string, string | number | boolean>): void {
|
||||||
if (typeof window !== 'undefined' && (window as any).umami?.track) {
|
if (typeof window !== 'undefined' && (window as any).umami?.track) {
|
||||||
try {
|
try {
|
||||||
(window as any).umami.track(event, data);
|
(window as any).umami.track(event, { ...data, module: 'auth' });
|
||||||
} catch {
|
} catch {
|
||||||
// Silently ignore tracking errors
|
// Silently ignore tracking errors
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -124,19 +124,59 @@ export function trackError(errorType: string, message?: string): void {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Module Tracker
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
type EventData = Record<string, string | number | boolean>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a module-scoped tracker that automatically includes `module` in every event.
|
||||||
|
* This resolves event name collisions in the unified app (e.g. `view_changed` from todo vs calendar).
|
||||||
|
*/
|
||||||
|
function createModuleTracker(module: string) {
|
||||||
|
return (event: string, data?: EventData) => trackEvent(event, { ...data, module });
|
||||||
|
}
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
// App-Specific Event Helpers
|
// App-Specific Event Helpers
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
|
const track = {
|
||||||
|
auth: createModuleTracker('auth'),
|
||||||
|
landing: createModuleTracker('landing'),
|
||||||
|
chat: createModuleTracker('chat'),
|
||||||
|
picture: createModuleTracker('picture'),
|
||||||
|
todo: createModuleTracker('todo'),
|
||||||
|
calendar: createModuleTracker('calendar'),
|
||||||
|
times: createModuleTracker('times'),
|
||||||
|
contacts: createModuleTracker('contacts'),
|
||||||
|
cards: createModuleTracker('cards'),
|
||||||
|
manacore: createModuleTracker('manacore'),
|
||||||
|
context: createModuleTracker('context'),
|
||||||
|
skilltree: createModuleTracker('skilltree'),
|
||||||
|
nutriphi: createModuleTracker('nutriphi'),
|
||||||
|
planta: createModuleTracker('planta'),
|
||||||
|
questions: createModuleTracker('questions'),
|
||||||
|
photos: createModuleTracker('photos'),
|
||||||
|
storage: createModuleTracker('storage'),
|
||||||
|
mukke: createModuleTracker('mukke'),
|
||||||
|
zitare: createModuleTracker('zitare'),
|
||||||
|
presi: createModuleTracker('presi'),
|
||||||
|
subscription: createModuleTracker('subscription'),
|
||||||
|
memoro: createModuleTracker('memoro'),
|
||||||
|
app: createModuleTracker('app'),
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Auth Events
|
* Auth Events
|
||||||
*/
|
*/
|
||||||
export const AuthEvents = {
|
export const AuthEvents = {
|
||||||
login: (method: 'email' | 'google' | 'github' = 'email') => trackEvent('login', { method }),
|
login: (method: 'email' | 'google' | 'github' = 'email') => track.auth('login', { method }),
|
||||||
logout: () => trackEvent('logout'),
|
logout: () => track.auth('logout'),
|
||||||
signup: (method: 'email' | 'google' | 'github' = 'email') => trackEvent('signup', { method }),
|
signup: (method: 'email' | 'google' | 'github' = 'email') => track.auth('signup', { method }),
|
||||||
signupCompleted: () => trackEvent('signup_completed'),
|
signupCompleted: () => track.auth('signup_completed'),
|
||||||
passwordReset: () => trackEvent('password_reset'),
|
passwordReset: () => track.auth('password_reset'),
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -144,27 +184,27 @@ export const AuthEvents = {
|
||||||
*/
|
*/
|
||||||
export const LandingEvents = {
|
export const LandingEvents = {
|
||||||
ctaClick: (location: 'hero' | 'pricing' | 'features' | 'footer' | string) =>
|
ctaClick: (location: 'hero' | 'pricing' | 'features' | 'footer' | string) =>
|
||||||
trackEvent('cta_click', { location }),
|
track.landing('cta_click', { location }),
|
||||||
pricingViewed: () => trackEvent('pricing_viewed'),
|
pricingViewed: () => track.landing('pricing_viewed'),
|
||||||
pricingPlanSelected: (plan: string) => trackEvent('pricing_plan_selected', { plan }),
|
pricingPlanSelected: (plan: string) => track.landing('pricing_plan_selected', { plan }),
|
||||||
demoStarted: () => trackEvent('demo_started'),
|
demoStarted: () => track.landing('demo_started'),
|
||||||
featureExplored: (feature: string) => trackEvent('feature_explored', { feature }),
|
featureExplored: (feature: string) => track.landing('feature_explored', { feature }),
|
||||||
faqOpened: (question: string) =>
|
faqOpened: (question: string) =>
|
||||||
trackEvent('faq_opened', { question: question.substring(0, 50) }),
|
track.landing('faq_opened', { question: question.substring(0, 50) }),
|
||||||
contactFormSubmitted: () => trackEvent('contact_form_submitted'),
|
contactFormSubmitted: () => track.landing('contact_form_submitted'),
|
||||||
newsletterSubscribed: () => trackEvent('newsletter_subscribed'),
|
newsletterSubscribed: () => track.landing('newsletter_subscribed'),
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Chat App Events
|
* Chat App Events
|
||||||
*/
|
*/
|
||||||
export const ChatEvents = {
|
export const ChatEvents = {
|
||||||
conversationCreated: () => trackEvent('conversation_created'),
|
conversationCreated: () => track.chat('conversation_created'),
|
||||||
messageSent: (modelId?: string) =>
|
messageSent: (modelId?: string) =>
|
||||||
trackEvent('message_sent', modelId ? { model: modelId } : undefined),
|
track.chat('message_sent', modelId ? { model: modelId } : undefined),
|
||||||
modelChanged: (modelId: string) => trackEvent('model_changed', { model: modelId }),
|
modelChanged: (modelId: string) => track.chat('model_changed', { model: modelId }),
|
||||||
conversationDeleted: () => trackEvent('conversation_deleted'),
|
conversationDeleted: () => track.chat('conversation_deleted'),
|
||||||
conversationShared: () => trackEvent('conversation_shared'),
|
conversationShared: () => track.chat('conversation_shared'),
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -172,138 +212,144 @@ export const ChatEvents = {
|
||||||
*/
|
*/
|
||||||
export const PictureEvents = {
|
export const PictureEvents = {
|
||||||
imageGenerated: (model: string, style?: string) =>
|
imageGenerated: (model: string, style?: string) =>
|
||||||
trackEvent('image_generated', { model, ...(style && { style }) }),
|
track.picture('image_generated', { model, ...(style && { style }) }),
|
||||||
imageDownloaded: () => trackEvent('image_downloaded'),
|
imageDownloaded: () => track.picture('image_downloaded'),
|
||||||
imageFavorited: () => trackEvent('image_favorited'),
|
imageFavorited: () => track.picture('image_favorited'),
|
||||||
imageShared: () => trackEvent('image_shared'),
|
imageShared: () => track.picture('image_shared'),
|
||||||
modelSelected: (model: string) => trackEvent('model_selected', { model }),
|
modelSelected: (model: string) => track.picture('model_selected', { model }),
|
||||||
styleSelected: (style: string) => trackEvent('style_selected', { style }),
|
styleSelected: (style: string) => track.picture('style_selected', { style }),
|
||||||
generationFailed: (reason?: string) =>
|
generationFailed: (reason?: string) =>
|
||||||
trackEvent('generation_failed', { reason: reason || 'unknown' }),
|
track.picture('generation_failed', { reason: reason || 'unknown' }),
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Todo App Events
|
* Todo App Events
|
||||||
*/
|
*/
|
||||||
export const TodoEvents = {
|
export const TodoEvents = {
|
||||||
taskCreated: (hasDeadline = false) => trackEvent('task_created', { has_deadline: hasDeadline }),
|
taskCreated: (hasDeadline = false) => track.todo('task_created', { has_deadline: hasDeadline }),
|
||||||
taskCompleted: () => trackEvent('task_completed'),
|
taskCompleted: () => track.todo('task_completed'),
|
||||||
taskDeleted: () => trackEvent('task_deleted'),
|
taskDeleted: () => track.todo('task_deleted'),
|
||||||
taskUncompleted: () => trackEvent('task_uncompleted'),
|
taskUncompleted: () => track.todo('task_uncompleted'),
|
||||||
subtaskCompleted: () => trackEvent('subtask_completed'),
|
subtaskCompleted: () => track.todo('subtask_completed'),
|
||||||
projectCreated: () => trackEvent('project_created'),
|
projectCreated: () => track.todo('project_created'),
|
||||||
projectDeleted: () => trackEvent('project_deleted'),
|
projectDeleted: () => track.todo('project_deleted'),
|
||||||
labelCreated: () => trackEvent('label_created'),
|
labelCreated: () => track.todo('label_created'),
|
||||||
viewChanged: (view: string) => trackEvent('view_changed', { view }),
|
viewChanged: (view: string) => track.todo('view_changed', { view }),
|
||||||
quickAddUsed: () => trackEvent('quick_add_used'),
|
quickAddUsed: () => track.todo('quick_add_used'),
|
||||||
filterUsed: (filterType: string) => trackEvent('filter_used', { filter: filterType }),
|
filterUsed: (filterType: string) => track.todo('filter_used', { filter: filterType }),
|
||||||
reminderCreated: (type: 'relative' | 'absolute') => trackEvent('reminder_created', { type }),
|
reminderCreated: (type: 'relative' | 'absolute') => track.todo('reminder_created', { type }),
|
||||||
recurringTaskCreated: (pattern: string) => trackEvent('recurring_task_created', { pattern }),
|
recurringTaskCreated: (pattern: string) => track.todo('recurring_task_created', { pattern }),
|
||||||
taskReordered: () => trackEvent('task_reordered'),
|
taskReordered: () => track.todo('task_reordered'),
|
||||||
keyboardShortcutUsed: (shortcut: string) => trackEvent('keyboard_shortcut_used', { shortcut }),
|
keyboardShortcutUsed: (shortcut: string) => track.todo('keyboard_shortcut_used', { shortcut }),
|
||||||
taskEdited: () => trackEvent('task_edited'),
|
taskEdited: () => track.todo('task_edited'),
|
||||||
dueDateSet: () => trackEvent('due_date_set'),
|
dueDateSet: () => track.todo('due_date_set'),
|
||||||
priorityChanged: (priority: string) => trackEvent('priority_changed', { priority }),
|
priorityChanged: (priority: string) => track.todo('priority_changed', { priority }),
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calendar App Events
|
* Calendar App Events
|
||||||
*/
|
*/
|
||||||
export const CalendarEvents = {
|
export const CalendarEvents = {
|
||||||
eventCreated: (isRecurring = false) => trackEvent('event_created', { recurring: isRecurring }),
|
eventCreated: (isRecurring = false) =>
|
||||||
eventUpdated: () => trackEvent('event_updated'),
|
track.calendar('event_created', { recurring: isRecurring }),
|
||||||
eventDeleted: () => trackEvent('event_deleted'),
|
eventUpdated: () => track.calendar('event_updated'),
|
||||||
calendarCreated: () => trackEvent('calendar_created'),
|
eventDeleted: () => track.calendar('event_deleted'),
|
||||||
calendarDeleted: () => trackEvent('calendar_deleted'),
|
calendarCreated: () => track.calendar('calendar_created'),
|
||||||
calendarShared: () => trackEvent('calendar_shared'),
|
calendarDeleted: () => track.calendar('calendar_deleted'),
|
||||||
viewChanged: (view: string) => trackEvent('view_changed', { view }),
|
calendarShared: () => track.calendar('calendar_shared'),
|
||||||
reminderSet: (minutesBefore: number) => trackEvent('reminder_set', { minutes: minutesBefore }),
|
viewChanged: (view: string) => track.calendar('view_changed', { view }),
|
||||||
eventDragged: () => trackEvent('event_dragged'),
|
reminderSet: (minutesBefore: number) =>
|
||||||
|
track.calendar('reminder_set', { minutes: minutesBefore }),
|
||||||
|
eventDragged: () => track.calendar('event_dragged'),
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clock App Events
|
* Times App Events (formerly Clock)
|
||||||
*/
|
*/
|
||||||
export const ClockEvents = {
|
export const ClockEvents = {
|
||||||
timerStarted: (type: 'pomodoro' | 'stopwatch' | 'countdown') =>
|
timerStarted: (type: 'pomodoro' | 'stopwatch' | 'countdown') =>
|
||||||
trackEvent('timer_started', { type }),
|
track.times('timer_started', { type }),
|
||||||
timerCompleted: (type: 'pomodoro' | 'stopwatch' | 'countdown', duration: number) =>
|
timerCompleted: (type: 'pomodoro' | 'stopwatch' | 'countdown', duration: number) =>
|
||||||
trackEvent('timer_completed', { type, duration_seconds: duration }),
|
track.times('timer_completed', { type, duration_seconds: duration }),
|
||||||
timerCanceled: () => trackEvent('timer_canceled'),
|
timerCanceled: () => track.times('timer_canceled'),
|
||||||
focusSessionStarted: () => trackEvent('focus_session_started'),
|
focusSessionStarted: () => track.times('focus_session_started'),
|
||||||
focusSessionCompleted: (duration: number) =>
|
focusSessionCompleted: (duration: number) =>
|
||||||
trackEvent('focus_session_completed', { duration_minutes: duration }),
|
track.times('focus_session_completed', { duration_minutes: duration }),
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contacts App Events
|
* Contacts App Events
|
||||||
*/
|
*/
|
||||||
export const ContactsEvents = {
|
export const ContactsEvents = {
|
||||||
contactCreated: () => trackEvent('contact_created'),
|
contactCreated: () => track.contacts('contact_created'),
|
||||||
contactUpdated: () => trackEvent('contact_updated'),
|
contactUpdated: () => track.contacts('contact_updated'),
|
||||||
contactDeleted: () => trackEvent('contact_deleted'),
|
contactDeleted: () => track.contacts('contact_deleted'),
|
||||||
contactFavorited: () => trackEvent('contact_favorited'),
|
contactFavorited: () => track.contacts('contact_favorited'),
|
||||||
contactArchived: () => trackEvent('contact_archived'),
|
contactArchived: () => track.contacts('contact_archived'),
|
||||||
contactImported: (source: 'google' | 'csv' | 'vcard', count?: number) =>
|
contactImported: (source: 'google' | 'csv' | 'vcard', count?: number) =>
|
||||||
trackEvent('contact_imported', { source, ...(count !== undefined && { count }) }),
|
track.contacts('contact_imported', {
|
||||||
contactExported: (format: 'csv' | 'vcard') => trackEvent('contact_exported', { format }),
|
source,
|
||||||
tagCreated: () => trackEvent('tag_created'),
|
...(count !== undefined && { count }),
|
||||||
searchPerformed: () => trackEvent('search_performed'),
|
}),
|
||||||
|
contactExported: (format: 'csv' | 'vcard') => track.contacts('contact_exported', { format }),
|
||||||
|
tagCreated: () => track.contacts('tag_created'),
|
||||||
|
searchPerformed: () => track.contacts('search_performed'),
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cards App Events
|
* Cards App Events
|
||||||
*/
|
*/
|
||||||
export const CardsEvents = {
|
export const CardsEvents = {
|
||||||
deckCreated: () => trackEvent('deck_created'),
|
deckCreated: () => track.cards('deck_created'),
|
||||||
deckDeleted: () => trackEvent('deck_deleted'),
|
deckDeleted: () => track.cards('deck_deleted'),
|
||||||
deckStudied: (cardsCount: number) => trackEvent('deck_studied', { cards: cardsCount }),
|
deckStudied: (cardsCount: number) => track.cards('deck_studied', { cards: cardsCount }),
|
||||||
cardCreated: () => trackEvent('card_created'),
|
cardCreated: () => track.cards('card_created'),
|
||||||
cardDeleted: () => trackEvent('card_deleted'),
|
cardDeleted: () => track.cards('card_deleted'),
|
||||||
cardReviewed: (rating: 1 | 2 | 3 | 4 | 5) => trackEvent('card_reviewed', { rating }),
|
cardReviewed: (rating: 1 | 2 | 3 | 4 | 5) => track.cards('card_reviewed', { rating }),
|
||||||
aiCardsGenerated: (count: number) => trackEvent('ai_cards_generated', { count }),
|
aiCardsGenerated: (count: number) => track.cards('ai_cards_generated', { count }),
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ManaCore Platform Events
|
* ManaCore Platform Events
|
||||||
*/
|
*/
|
||||||
export const ManaCoreEvents = {
|
export const ManaCoreEvents = {
|
||||||
appOpened: (appId: string) => trackEvent('app_opened', { app: appId }),
|
appOpened: (appId: string) => track.manacore('app_opened', { app: appId }),
|
||||||
navClicked: (destination: string) => trackEvent('nav_clicked', { destination }),
|
navClicked: (destination: string) => track.manacore('nav_clicked', { destination }),
|
||||||
onboardingStarted: () => trackEvent('onboarding_started'),
|
onboardingStarted: () => track.manacore('onboarding_started'),
|
||||||
onboardingStepCompleted: (step: string, stepNumber: number) =>
|
onboardingStepCompleted: (step: string, stepNumber: number) =>
|
||||||
trackEvent('onboarding_step_completed', { step, step_number: stepNumber }),
|
track.manacore('onboarding_step_completed', { step, step_number: stepNumber }),
|
||||||
onboardingCompleted: () => trackEvent('onboarding_completed'),
|
onboardingCompleted: () => track.manacore('onboarding_completed'),
|
||||||
onboardingSkipped: (atStep: number) => trackEvent('onboarding_skipped', { at_step: atStep }),
|
onboardingSkipped: (atStep: number) => track.manacore('onboarding_skipped', { at_step: atStep }),
|
||||||
dashboardEditToggled: (editing: boolean) => trackEvent('dashboard_edit_toggled', { editing }),
|
dashboardEditToggled: (editing: boolean) => track.manacore('dashboard_edit_toggled', { editing }),
|
||||||
widgetAdded: (widgetType: string) => trackEvent('widget_added', { widget_type: widgetType }),
|
widgetAdded: (widgetType: string) => track.manacore('widget_added', { widget_type: widgetType }),
|
||||||
widgetRemoved: (widgetType: string) => trackEvent('widget_removed', { widget_type: widgetType }),
|
widgetRemoved: (widgetType: string) =>
|
||||||
|
track.manacore('widget_removed', { widget_type: widgetType }),
|
||||||
widgetResized: (widgetType: string, size: string) =>
|
widgetResized: (widgetType: string, size: string) =>
|
||||||
trackEvent('widget_resized', { widget_type: widgetType, size }),
|
track.manacore('widget_resized', { widget_type: widgetType, size }),
|
||||||
creditsTabViewed: (tab: string) => trackEvent('credits_tab_viewed', { tab }),
|
creditsTabViewed: (tab: string) => track.manacore('credits_tab_viewed', { tab }),
|
||||||
profileUpdated: () => trackEvent('profile_updated'),
|
profileUpdated: () => track.manacore('profile_updated'),
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Context App Events
|
* Context App Events
|
||||||
*/
|
*/
|
||||||
export const ContextEvents = {
|
export const ContextEvents = {
|
||||||
documentCreated: (type: string) => trackEvent('document_created', { type }),
|
documentCreated: (type: string) => track.context('document_created', { type }),
|
||||||
documentDeleted: () => trackEvent('document_deleted'),
|
documentDeleted: () => track.context('document_deleted'),
|
||||||
documentPinned: (pinned: boolean) => trackEvent('document_pinned', { pinned }),
|
documentPinned: (pinned: boolean) => track.context('document_pinned', { pinned }),
|
||||||
spaceCreated: () => trackEvent('space_created'),
|
spaceCreated: () => track.context('space_created'),
|
||||||
spaceDeleted: () => trackEvent('space_deleted'),
|
spaceDeleted: () => track.context('space_deleted'),
|
||||||
aiGenerated: () => trackEvent('ai_generated'),
|
aiGenerated: () => track.context('ai_generated'),
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SkillTree App Events
|
* SkillTree App Events
|
||||||
*/
|
*/
|
||||||
export const SkillTreeEvents = {
|
export const SkillTreeEvents = {
|
||||||
skillCreated: (branch: string) => trackEvent('skill_created', { branch }),
|
skillCreated: (branch: string) => track.skilltree('skill_created', { branch }),
|
||||||
skillDeleted: () => trackEvent('skill_deleted'),
|
skillDeleted: () => track.skilltree('skill_deleted'),
|
||||||
xpAdded: (xp: number, leveledUp: boolean) =>
|
xpAdded: (xp: number, leveledUp: boolean) =>
|
||||||
trackEvent('xp_added', { xp, leveled_up: leveledUp }),
|
track.skilltree('xp_added', { xp, leveled_up: leveledUp }),
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -311,134 +357,137 @@ export const SkillTreeEvents = {
|
||||||
*/
|
*/
|
||||||
export const NutriPhiEvents = {
|
export const NutriPhiEvents = {
|
||||||
mealAdded: (mealType: string, inputType: string) =>
|
mealAdded: (mealType: string, inputType: string) =>
|
||||||
trackEvent('meal_added', { meal_type: mealType, input_type: inputType }),
|
track.nutriphi('meal_added', { meal_type: mealType, input_type: inputType }),
|
||||||
mealDeleted: () => trackEvent('meal_deleted'),
|
mealDeleted: () => track.nutriphi('meal_deleted'),
|
||||||
photoAnalyzed: () => trackEvent('photo_analyzed'),
|
photoAnalyzed: () => track.nutriphi('photo_analyzed'),
|
||||||
textAnalyzed: () => trackEvent('text_analyzed'),
|
textAnalyzed: () => track.nutriphi('text_analyzed'),
|
||||||
goalsUpdated: () => trackEvent('goals_updated'),
|
goalsUpdated: () => track.nutriphi('goals_updated'),
|
||||||
favoriteSaved: () => trackEvent('favorite_saved'),
|
favoriteSaved: () => track.nutriphi('favorite_saved'),
|
||||||
favoriteUsed: () => trackEvent('favorite_used'),
|
favoriteUsed: () => track.nutriphi('favorite_used'),
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Planta App Events
|
* Planta App Events
|
||||||
*/
|
*/
|
||||||
export const PlantaEvents = {
|
export const PlantaEvents = {
|
||||||
plantAnalyzed: () => trackEvent('plant_analyzed'),
|
plantAnalyzed: () => track.planta('plant_analyzed'),
|
||||||
plantCreated: () => trackEvent('plant_created'),
|
plantCreated: () => track.planta('plant_created'),
|
||||||
plantDeleted: () => trackEvent('plant_deleted'),
|
plantDeleted: () => track.planta('plant_deleted'),
|
||||||
plantWatered: () => trackEvent('plant_watered'),
|
plantWatered: () => track.planta('plant_watered'),
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Questions App Events
|
* Questions App Events
|
||||||
*/
|
*/
|
||||||
export const QuestionsEvents = {
|
export const QuestionsEvents = {
|
||||||
questionCreated: (depth: string) => trackEvent('question_created', { depth }),
|
questionCreated: (depth: string) => track.questions('question_created', { depth }),
|
||||||
questionDeleted: () => trackEvent('question_deleted'),
|
questionDeleted: () => track.questions('question_deleted'),
|
||||||
researchStarted: (depth: string) => trackEvent('research_started', { depth }),
|
researchStarted: (depth: string) => track.questions('research_started', { depth }),
|
||||||
collectionCreated: () => trackEvent('collection_created'),
|
collectionCreated: () => track.questions('collection_created'),
|
||||||
collectionDeleted: () => trackEvent('collection_deleted'),
|
collectionDeleted: () => track.questions('collection_deleted'),
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Photos App Events
|
* Photos App Events
|
||||||
*/
|
*/
|
||||||
export const PhotosEvents = {
|
export const PhotosEvents = {
|
||||||
photoUploaded: () => trackEvent('photo_uploaded'),
|
photoUploaded: () => track.photos('photo_uploaded'),
|
||||||
photoFavorited: (favorited: boolean) => trackEvent('photo_favorited', { favorited }),
|
photoFavorited: (favorited: boolean) => track.photos('photo_favorited', { favorited }),
|
||||||
photoDeleted: () => trackEvent('photo_deleted'),
|
photoDeleted: () => track.photos('photo_deleted'),
|
||||||
albumCreated: () => trackEvent('album_created'),
|
albumCreated: () => track.photos('album_created'),
|
||||||
albumDeleted: () => trackEvent('album_deleted'),
|
albumDeleted: () => track.photos('album_deleted'),
|
||||||
photosAddedToAlbum: (count: number) => trackEvent('photos_added_to_album', { count }),
|
photosAddedToAlbum: (count: number) => track.photos('photos_added_to_album', { count }),
|
||||||
photoRemovedFromAlbum: () => trackEvent('photo_removed_from_album'),
|
photoRemovedFromAlbum: () => track.photos('photo_removed_from_album'),
|
||||||
filtersApplied: () => trackEvent('filters_applied'),
|
filtersApplied: () => track.photos('filters_applied'),
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Storage App Events
|
* Storage App Events
|
||||||
*/
|
*/
|
||||||
export const StorageEvents = {
|
export const StorageEvents = {
|
||||||
fileDownloaded: () => trackEvent('file_downloaded'),
|
fileDownloaded: () => track.storage('file_downloaded'),
|
||||||
fileDeleted: () => trackEvent('file_deleted'),
|
fileDeleted: () => track.storage('file_deleted'),
|
||||||
fileFavorited: (favorited: boolean) => trackEvent('file_favorited', { favorited }),
|
fileFavorited: (favorited: boolean) => track.storage('file_favorited', { favorited }),
|
||||||
folderDeleted: () => trackEvent('folder_deleted'),
|
folderDeleted: () => track.storage('folder_deleted'),
|
||||||
folderFavorited: (favorited: boolean) => trackEvent('folder_favorited', { favorited }),
|
folderFavorited: (favorited: boolean) => track.storage('folder_favorited', { favorited }),
|
||||||
shareLinkCopied: () => trackEvent('share_link_copied'),
|
shareLinkCopied: () => track.storage('share_link_copied'),
|
||||||
shareLinkDeleted: () => trackEvent('share_link_deleted'),
|
shareLinkDeleted: () => track.storage('share_link_deleted'),
|
||||||
trashRestored: (type: string) => trackEvent('trash_restored', { type }),
|
trashRestored: (type: string) => track.storage('trash_restored', { type }),
|
||||||
trashEmptied: () => trackEvent('trash_emptied'),
|
trashEmptied: () => track.storage('trash_emptied'),
|
||||||
searchPerformed: (resultsCount: number) =>
|
searchPerformed: (resultsCount: number) =>
|
||||||
trackEvent('search_performed', { results: resultsCount }),
|
track.storage('search_performed', { results: resultsCount }),
|
||||||
viewModeChanged: (mode: string) => trackEvent('view_mode_changed', { mode }),
|
viewModeChanged: (mode: string) => track.storage('view_mode_changed', { mode }),
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mukke App Events
|
* Mukke App Events
|
||||||
*/
|
*/
|
||||||
export const MukkeEvents = {
|
export const MukkeEvents = {
|
||||||
songUploaded: () => trackEvent('song_uploaded'),
|
songUploaded: () => track.mukke('song_uploaded'),
|
||||||
songUploadFailed: () => trackEvent('song_upload_failed'),
|
songUploadFailed: () => track.mukke('song_upload_failed'),
|
||||||
songPlayed: () => trackEvent('song_played'),
|
songPlayed: () => track.mukke('song_played'),
|
||||||
songFavorited: (favorited: boolean) => trackEvent('song_favorited', { favorited }),
|
songFavorited: (favorited: boolean) => track.mukke('song_favorited', { favorited }),
|
||||||
songDeleted: () => trackEvent('song_deleted'),
|
songDeleted: () => track.mukke('song_deleted'),
|
||||||
playlistCreated: () => trackEvent('playlist_created'),
|
playlistCreated: () => track.mukke('playlist_created'),
|
||||||
playlistDeleted: () => trackEvent('playlist_deleted'),
|
playlistDeleted: () => track.mukke('playlist_deleted'),
|
||||||
playlistPlayAll: () => trackEvent('playlist_play_all'),
|
playlistPlayAll: () => track.mukke('playlist_play_all'),
|
||||||
playlistShufflePlay: () => trackEvent('playlist_shuffle_play'),
|
playlistShufflePlay: () => track.mukke('playlist_shuffle_play'),
|
||||||
projectCreated: () => trackEvent('project_created'),
|
projectCreated: () => track.mukke('project_created'),
|
||||||
projectDeleted: () => trackEvent('project_deleted'),
|
projectDeleted: () => track.mukke('project_deleted'),
|
||||||
projectExported: (format: string) => trackEvent('project_exported', { format }),
|
projectExported: (format: string) => track.mukke('project_exported', { format }),
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Zitare App Events
|
* Zitare App Events
|
||||||
*/
|
*/
|
||||||
export const ZitareEvents = {
|
export const ZitareEvents = {
|
||||||
randomQuoteLoaded: () => trackEvent('random_quote_loaded'),
|
randomQuoteLoaded: () => track.zitare('random_quote_loaded'),
|
||||||
quoteShared: (category: string) => trackEvent('quote_shared', { category }),
|
quoteShared: (category: string) => track.zitare('quote_shared', { category }),
|
||||||
quoteFavorited: (category: string) => trackEvent('quote_favorited', { category }),
|
quoteFavorited: (category: string) => track.zitare('quote_favorited', { category }),
|
||||||
quoteUnfavorited: () => trackEvent('quote_unfavorited'),
|
quoteUnfavorited: () => track.zitare('quote_unfavorited'),
|
||||||
categoryViewed: (category: string) => trackEvent('category_viewed', { category }),
|
categoryViewed: (category: string) => track.zitare('category_viewed', { category }),
|
||||||
searchPerformed: (resultsCount: number) =>
|
searchPerformed: (resultsCount: number) =>
|
||||||
trackEvent('search_performed', { results: resultsCount }),
|
track.zitare('search_performed', { results: resultsCount }),
|
||||||
listCreated: () => trackEvent('list_created'),
|
listCreated: () => track.zitare('list_created'),
|
||||||
listDeleted: () => trackEvent('list_deleted'),
|
listDeleted: () => track.zitare('list_deleted'),
|
||||||
quoteLanguageChanged: (language: string) => trackEvent('quote_language_changed', { language }),
|
quoteLanguageChanged: (language: string) => track.zitare('quote_language_changed', { language }),
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Presi App Events
|
* Presi App Events
|
||||||
*/
|
*/
|
||||||
export const PresiEvents = {
|
export const PresiEvents = {
|
||||||
deckCreated: () => trackEvent('deck_created'),
|
deckCreated: () => track.presi('deck_created'),
|
||||||
deckDeleted: () => trackEvent('deck_deleted'),
|
deckDeleted: () => track.presi('deck_deleted'),
|
||||||
slideCreated: () => trackEvent('slide_created'),
|
slideCreated: () => track.presi('slide_created'),
|
||||||
slideEdited: () => trackEvent('slide_edited'),
|
slideEdited: () => track.presi('slide_edited'),
|
||||||
slideDeleted: () => trackEvent('slide_deleted'),
|
slideDeleted: () => track.presi('slide_deleted'),
|
||||||
slideReordered: (direction: 'up' | 'down') => trackEvent('slide_reordered', { direction }),
|
slideReordered: (direction: 'up' | 'down') => track.presi('slide_reordered', { direction }),
|
||||||
presentationStarted: (slideCount: number) =>
|
presentationStarted: (slideCount: number) =>
|
||||||
trackEvent('presentation_started', { slide_count: slideCount }),
|
track.presi('presentation_started', { slide_count: slideCount }),
|
||||||
presentationExited: (duration: number, slidesViewed: number) =>
|
presentationExited: (duration: number, slidesViewed: number) =>
|
||||||
trackEvent('presentation_exited', { duration_seconds: duration, slides_viewed: slidesViewed }),
|
track.presi('presentation_exited', {
|
||||||
shareLinkCreated: () => trackEvent('share_link_created'),
|
duration_seconds: duration,
|
||||||
shareLinkCopied: () => trackEvent('share_link_copied'),
|
slides_viewed: slidesViewed,
|
||||||
shareLinkDeleted: () => trackEvent('share_link_deleted'),
|
}),
|
||||||
sharedDeckViewed: () => trackEvent('shared_deck_viewed'),
|
shareLinkCreated: () => track.presi('share_link_created'),
|
||||||
|
shareLinkCopied: () => track.presi('share_link_copied'),
|
||||||
|
shareLinkDeleted: () => track.presi('share_link_deleted'),
|
||||||
|
sharedDeckViewed: () => track.presi('shared_deck_viewed'),
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subscription/Payment Events
|
* Subscription/Payment Events
|
||||||
*/
|
*/
|
||||||
export const SubscriptionEvents = {
|
export const SubscriptionEvents = {
|
||||||
pricingViewed: () => trackEvent('pricing_viewed'),
|
pricingViewed: () => track.subscription('pricing_viewed'),
|
||||||
planSelected: (plan: string) => trackEvent('plan_selected', { plan }),
|
planSelected: (plan: string) => track.subscription('plan_selected', { plan }),
|
||||||
checkoutStarted: (plan: string) => trackEvent('checkout_started', { plan }),
|
checkoutStarted: (plan: string) => track.subscription('checkout_started', { plan }),
|
||||||
checkoutCompleted: (plan: string) => trackEvent('checkout_completed', { plan }),
|
checkoutCompleted: (plan: string) => track.subscription('checkout_completed', { plan }),
|
||||||
checkoutAbandoned: (plan: string) => trackEvent('checkout_abandoned', { plan }),
|
checkoutAbandoned: (plan: string) => track.subscription('checkout_abandoned', { plan }),
|
||||||
subscriptionCanceled: (plan: string) => trackEvent('subscription_canceled', { plan }),
|
subscriptionCanceled: (plan: string) => track.subscription('subscription_canceled', { plan }),
|
||||||
trialStarted: () => trackEvent('trial_started'),
|
trialStarted: () => track.subscription('trial_started'),
|
||||||
trialEnded: (converted: boolean) => trackEvent('trial_ended', { converted }),
|
trialEnded: (converted: boolean) => track.subscription('trial_ended', { converted }),
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -446,44 +495,44 @@ export const SubscriptionEvents = {
|
||||||
*/
|
*/
|
||||||
export const MemoroEvents = {
|
export const MemoroEvents = {
|
||||||
memoCreated: (mediaType?: string) =>
|
memoCreated: (mediaType?: string) =>
|
||||||
trackEvent('memo_created', mediaType ? { media_type: mediaType } : undefined),
|
track.memoro('memo_created', mediaType ? { media_type: mediaType } : undefined),
|
||||||
memoDeleted: () => trackEvent('memo_deleted'),
|
memoDeleted: () => track.memoro('memo_deleted'),
|
||||||
memoCombined: (count: number) => trackEvent('memo_combined', { memo_count: count }),
|
memoCombined: (count: number) => track.memoro('memo_combined', { memo_count: count }),
|
||||||
memoQuestioned: () => trackEvent('memo_questioned'),
|
memoQuestioned: () => track.memoro('memo_questioned'),
|
||||||
recordingStarted: () => trackEvent('recording_started'),
|
recordingStarted: () => track.memoro('recording_started'),
|
||||||
recordingCompleted: (durationSeconds: number) =>
|
recordingCompleted: (durationSeconds: number) =>
|
||||||
trackEvent('recording_completed', { duration_seconds: durationSeconds }),
|
track.memoro('recording_completed', { duration_seconds: durationSeconds }),
|
||||||
recordingAppended: () => trackEvent('recording_appended'),
|
recordingAppended: () => track.memoro('recording_appended'),
|
||||||
transcriptionRetried: () => trackEvent('transcription_retried'),
|
transcriptionRetried: () => track.memoro('transcription_retried'),
|
||||||
headlineRetried: () => trackEvent('headline_retried'),
|
headlineRetried: () => track.memoro('headline_retried'),
|
||||||
spaceCreated: () => trackEvent('space_created'),
|
spaceCreated: () => track.memoro('space_created'),
|
||||||
spaceDeleted: () => trackEvent('space_deleted'),
|
spaceDeleted: () => track.memoro('space_deleted'),
|
||||||
spaceLeft: () => trackEvent('space_left'),
|
spaceLeft: () => track.memoro('space_left'),
|
||||||
memoLinkedToSpace: () => trackEvent('memo_linked_to_space'),
|
memoLinkedToSpace: () => track.memoro('memo_linked_to_space'),
|
||||||
memoUnlinkedFromSpace: () => trackEvent('memo_unlinked_from_space'),
|
memoUnlinkedFromSpace: () => track.memoro('memo_unlinked_from_space'),
|
||||||
inviteSent: () => trackEvent('invite_sent'),
|
inviteSent: () => track.memoro('invite_sent'),
|
||||||
inviteAccepted: () => trackEvent('invite_accepted'),
|
inviteAccepted: () => track.memoro('invite_accepted'),
|
||||||
inviteDeclined: () => trackEvent('invite_declined'),
|
inviteDeclined: () => track.memoro('invite_declined'),
|
||||||
meetingBotCreated: (platform: string) => trackEvent('meeting_bot_created', { platform }),
|
meetingBotCreated: (platform: string) => track.memoro('meeting_bot_created', { platform }),
|
||||||
meetingBotStopped: () => trackEvent('meeting_bot_stopped'),
|
meetingBotStopped: () => track.memoro('meeting_bot_stopped'),
|
||||||
recordingToMemo: () => trackEvent('recording_to_memo'),
|
recordingToMemo: () => track.memoro('recording_to_memo'),
|
||||||
blueprintSelected: (blueprintId: string) =>
|
blueprintSelected: (blueprintId: string) =>
|
||||||
trackEvent('blueprint_selected', { blueprint_id: blueprintId }),
|
track.memoro('blueprint_selected', { blueprint_id: blueprintId }),
|
||||||
playbackStarted: () => trackEvent('playback_started'),
|
playbackStarted: () => track.memoro('playback_started'),
|
||||||
settingsUpdated: (setting: string) => trackEvent('settings_updated', { setting }),
|
settingsUpdated: (setting: string) => track.memoro('settings_updated', { setting }),
|
||||||
themeChanged: (theme: string) => trackEvent('theme_changed', { theme }),
|
themeChanged: (theme: string) => track.memoro('theme_changed', { theme }),
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* General App Events
|
* General App Events (cross-module, e.g. theme/language changes)
|
||||||
*/
|
*/
|
||||||
export const AppEvents = {
|
export const AppEvents = {
|
||||||
appOpened: (app: string) => trackEvent('app_opened', { app }),
|
appOpened: (app: string) => track.app('app_opened', { app }),
|
||||||
themeChanged: (theme: 'light' | 'dark' | 'system') => trackEvent('theme_changed', { theme }),
|
themeChanged: (theme: 'light' | 'dark' | 'system') => track.app('theme_changed', { theme }),
|
||||||
languageChanged: (language: string) => trackEvent('language_changed', { language }),
|
languageChanged: (language: string) => track.app('language_changed', { language }),
|
||||||
feedbackSubmitted: (type: 'bug' | 'feature' | 'other') =>
|
feedbackSubmitted: (type: 'bug' | 'feature' | 'other') =>
|
||||||
trackEvent('feedback_submitted', { type }),
|
track.app('feedback_submitted', { type }),
|
||||||
helpOpened: () => trackEvent('help_opened'),
|
helpOpened: () => track.app('help_opened'),
|
||||||
settingsOpened: () => trackEvent('settings_opened'),
|
settingsOpened: () => track.app('settings_opened'),
|
||||||
shareClicked: (platform: string) => trackEvent('share_clicked', { platform }),
|
shareClicked: (platform: string) => track.app('share_clicked', { platform }),
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue