# Analytics Service Layer

This directory contains the service layer implementation for analytics tracking in the KLZ Cables application.

## Overview

The analytics service layer provides a clean abstraction over different analytics implementations (Umami, Google Analytics, etc.) while maintaining a consistent API.

## Architecture

```
lib/services/analytics/
├── analytics-service.ts          # Interface definition
├── umami-analytics-service.ts    # Umami implementation
├── noop-analytics-service.ts     # No-op fallback implementation
└── README.md                     # This file
```

## Components

### 1. AnalyticsService Interface (`analytics-service.ts`)

Defines the contract for all analytics services:

```typescript
export interface AnalyticsService {
  track(eventName: string, props?: AnalyticsEventProperties): void;
  trackPageview(url?: string): void;
}
```

**Key Features:**

- Type-safe event properties
- Consistent API across implementations
- Well-documented with JSDoc comments

### 2. UmamiAnalyticsService (`umami-analytics-service.ts`)

Implements the `AnalyticsService` interface for Umami analytics.

**Features:**

- Type-safe event tracking
- Automatic pageview tracking
- Browser environment detection
- Graceful error handling
- Comprehensive JSDoc documentation

**Usage:**

```typescript
import { UmamiAnalyticsService } from "@/lib/services/analytics/umami-analytics-service";

const service = new UmamiAnalyticsService({ enabled: true });
service.track("button_click", { button_id: "cta" });
service.trackPageview("/products/123");
```

### 3. NoopAnalyticsService (`noop-analytics-service.ts`)

A no-op implementation used as a fallback when analytics are disabled.

**Features:**

- Maintains the same API as other services
- Safe to call even when analytics are disabled
- No performance impact
- Comprehensive JSDoc documentation

**Usage:**

```typescript
import { NoopAnalyticsService } from "@/lib/services/analytics/noop-analytics-service";

const service = new NoopAnalyticsService();
service.track("button_click", { button_id: "cta" }); // Does nothing
service.trackPageview("/products/123"); // Does nothing
```

## Service Selection

The service layer automatically selects the appropriate implementation based on environment variables:

```typescript
// In lib/services/create-services.ts
const umamiEnabled = Boolean(process.env.NEXT_PUBLIC_UMAMI_WEBSITE_ID);

const analytics = umamiEnabled
  ? new UmamiAnalyticsService({ enabled: true })
  : new NoopAnalyticsService();
```

## Environment Variables

### Required for Umami

```bash
NEXT_PUBLIC_UMAMI_WEBSITE_ID=59a7db94-0100-4c7e-98ef-99f45b17f9c3
```

### Optional (defaults provided)

```bash
NEXT_PUBLIC_UMAMI_SCRIPT_URL=https://analytics.infra.mintel.me/script.js
```

## API Reference

### AnalyticsService Interface

#### `track(eventName: string, props?: AnalyticsEventProperties): void`

Track a custom event with optional properties.

**Parameters:**

- `eventName` - The name of the event to track
- `props` - Optional event properties (metadata)

**Example:**

```typescript
service.track("product_add_to_cart", {
  product_id: "123",
  product_name: "Cable",
  price: 99.99,
  quantity: 1,
});
```

#### `trackPageview(url?: string): void`

Track a pageview.

**Parameters:**

- `url` - The URL to track (defaults to current location)

**Example:**

```typescript
// Track current page
service.trackPageview();

// Track custom URL
service.trackPageview("/products/123?category=cables");
```

### UmamiAnalyticsService

#### Constructor

```typescript
new UmamiAnalyticsService(options: UmamiAnalyticsServiceOptions)
```

**Options:**

- `enabled: boolean` - Whether analytics are enabled

**Example:**

```typescript
const service = new UmamiAnalyticsService({ enabled: true });
```

### NoopAnalyticsService

#### Constructor

```typescript
new NoopAnalyticsService();
```

**Example:**

```typescript
const service = new NoopAnalyticsService();
```

## Type Definitions

### AnalyticsEventProperties

```typescript
type AnalyticsEventProperties = Record<
  string,
  string | number | boolean | null | undefined
>;
```

**Example:**

```typescript
const properties: AnalyticsEventProperties = {
  product_id: "123",
  product_name: "Cable",
  price: 99.99,
  quantity: 1,
  in_stock: true,
  discount: null,
};
```

### UmamiAnalyticsServiceOptions

```typescript
type UmamiAnalyticsServiceOptions = {
  enabled: boolean;
};
```

## Best Practices

### 1. Use the Service Layer

Always use the service layer instead of calling Umami directly:

```typescript
// ✅ Good
import { getAppServices } from "@/lib/services/create-services";

const services = getAppServices();
services.analytics.track("button_click", { button_id: "cta" });

// ❌ Avoid
(window as any).umami?.track("button_click", { button_id: "cta" });
```

### 2. Check Environment

The service layer automatically handles environment detection:

```typescript
// ✅ Safe - works in both server and client
const services = getAppServices();
services.analytics.track("event", { prop: "value" });

// ❌ Unsafe - may fail in server environment
if (typeof window !== "undefined") {
  window.umami?.track("event", { prop: "value" });
}
```

### 3. Use Type-Safe Events

Import events from the centralized definitions:

```typescript
import { AnalyticsEvents } from "@/components/analytics/analytics-events";

// ✅ Type-safe
services.analytics.track(AnalyticsEvents.BUTTON_CLICK, {
  button_id: "cta",
});

// ❌ Prone to typos
services.analytics.track("button_click", {
  button_id: "cta",
});
```

### 4. Handle Disabled Analytics

The service layer gracefully handles disabled analytics:

```typescript
// When NEXT_PUBLIC_UMAMI_WEBSITE_ID is not set:
// - NoopAnalyticsService is used
// - All calls are safe (no-op)
// - No errors are thrown

const services = getAppServices();
services.analytics.track("event", { prop: "value" }); // Safe, does nothing
```

## Testing

### Mocking for Tests

```typescript
// __tests__/analytics-mock.ts
export const mockAnalytics = {
  track: jest.fn(),
  trackPageview: jest.fn(),
};

jest.mock("@/lib/services/create-services", () => ({
  getAppServices: () => ({
    analytics: mockAnalytics,
  }),
}));

// Usage in tests
import { mockAnalytics } from "./analytics-mock";

test("tracks button click", () => {
  // ... test code ...
  expect(mockAnalytics.track).toHaveBeenCalledWith("button_click", {
    button_id: "cta",
  });
});
```

### Development Mode

In development, the service layer logs to console:

```bash
# Console output:
[Umami] Tracked event: button_click { button_id: 'cta' }
[Umami] Tracked pageview: /products/123
```

## Error Handling

The service layer includes built-in error handling:

1. **Environment Detection** - Checks for browser environment
2. **Service Availability** - Checks if Umami is loaded
3. **Graceful Degradation** - Falls back to NoopAnalyticsService if needed

```typescript
// These are all safe:
const services = getAppServices();
services.analytics.track("event", { prop: "value" }); // Works or does nothing
services.analytics.trackPageview("/path"); // Works or does nothing
```

## Performance

### Singleton Pattern

The service layer uses a singleton pattern for performance:

```typescript
// First call creates the singleton
const services1 = getAppServices();

// Subsequent calls return the cached singleton
const services2 = getAppServices();

// services1 === services2 (same instance)
```

### Lazy Initialization

Services are only created when first accessed:

```typescript
// Services are not created until getAppServices() is called
// This keeps initial bundle size minimal
```

## Integration with Components

### Client Components

```typescript
'use client';

import { getAppServices } from '@/lib/services/create-services';

function MyComponent() {
  const handleClick = () => {
    const services = getAppServices();
    services.analytics.track('button_click', { button_id: 'my-button' });
  };

  return <button onClick={handleClick}>Click Me</button>;
}
```

### Server Components

```typescript
import { getAppServices } from '@/lib/services/create-services';

async function MyServerComponent() {
  const services = getAppServices();

  // Note: Analytics won't work in server components
  // Use client components for analytics tracking
  // But you can still access other services like cache

  const data = await services.cache.get('key');

  return <div>{data}</div>;
}
```

## Troubleshooting

### Analytics Not Working

1. **Check environment variables:**

   ```bash
   echo $NEXT_PUBLIC_UMAMI_WEBSITE_ID
   ```

2. **Verify service selection:**

   ```typescript
   import { getAppServices } from "@/lib/services/create-services";

   const services = getAppServices();
   console.log(services.analytics); // Should be UmamiAnalyticsService
   ```

3. **Check Umami dashboard:**
   - Log into Umami
   - Verify website ID matches
   - Check if data is being received

### Common Issues

| Issue               | Solution                            |
| ------------------- | ----------------------------------- |
| No data in Umami    | Check website ID and script URL     |
| Events not tracking | Verify service is being used        |
| Script not loading  | Check network connection, CORS      |
| Wrong data          | Verify event properties are correct |

## Related Files

- [`components/analytics/useAnalytics.ts`](../components/analytics/useAnalytics.ts) - Custom hook for easy event tracking
- [`components/analytics/analytics-events.ts`](../components/analytics/analytics-events.ts) - Event definitions
- [`components/analytics/UmamiScript.tsx`](../components/analytics/UmamiScript.tsx) - Script loader component
- [`components/analytics/AnalyticsProvider.tsx`](../components/analytics/AnalyticsProvider.tsx) - Route change tracker
- [`lib/services/create-services.ts`](../lib/services/create-services.ts) - Service factory

## Summary

The analytics service layer provides:

- ✅ **Type-safe API** - TypeScript throughout
- ✅ **Clean abstraction** - Easy to switch analytics providers
- ✅ **Graceful degradation** - Safe no-op fallback
- ✅ **Comprehensive documentation** - JSDoc comments and examples
- ✅ **Performance optimized** - Singleton pattern, lazy initialization
- ✅ **Error handling** - Safe in all environments

This layer is the foundation for all analytics tracking in the application.
