npm package: @shopkit/app-shell
Description: App shell components for Shopkit storefronts
Latest version: 1.0.1

# @shopkit/app-shell

App shell components for Shopkit storefronts. Provides master wrapper, analytics, toast notifications, head scripts, and navigation progress indicator.

## Installation

```bash
bun add @shopkit/app-shell
```

## Peer Dependencies

```json
{
  "react": "^18.0.0",
  "react-dom": "^18.0.0",
  "next": ">=14.0.0",
  "next-intl": ">=4.0.0",
  "@shopkit/core": "^0.1.0",
  "@shopkit/asset-cache": "^1.0.0"
}
```

## Quick Start

```tsx
// layout.tsx
import { AppShell, AppHead, AppAnalytics } from "@shopkit/app-shell";

export default async function RootLayout({ children }) {
  const theme = await getTheme();
  const messages = await getMessages();

  return (
    <html>
      <head>
        <AppHead />
      </head>
      <body>
        <AppShell config={{ merchantName: "my-store", locale: "en", messages, theme }}>
          {children}
        </AppShell>
        <AppAnalytics />
      </body>
    </html>
  );
}
```

## Components

### AppShell

Master provider wrapper that combines all required providers into a single component.

```tsx
import { AppShell } from "@shopkit/app-shell";

<AppShell
  config={{
    merchantName: "my-store",
    locale: "en",
    messages: { /* i18n messages */ },
    theme: { /* theme object */ },
  }}
>
  {children}
</AppShell>
```

**Props:**
| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `config.merchantName` | `string` | Yes | Merchant identifier |
| `config.locale` | `string` | Yes | Current locale (e.g., "en", "hi") |
| `config.messages` | `Record<string, unknown>` | Yes | i18n messages |
| `config.theme` | `Theme \| null` | Yes | Theme from @shopkit/core |
| `config.analytics` | `AnalyticsConfig` | No | Analytics configuration |
| `config.fonts` | `FontConfig` | No | Font configuration |
| `config.experiments` | `ExperimentConfig` | No | A/B testing config |

**Includes:**
- `AppRouteLoader` - Navigation progress bar
- `NextIntlClientProvider` - i18n provider
- `ThemeProvider` - Theme management
- `AppToast` + `AppToastContainer` - Toast notifications
- `AuthProvider` - Authentication context
- `AssetCacheInitializer` - Asset caching
- `AppAnalyticsInit` - Analytics initialization

---

### AppHead

Head scripts and resource hints for optimal performance.

```tsx
import { AppHead } from "@shopkit/app-shell";

<head>
  <AppHead
    config={{
      abTesting: {
        prtConfigUrl: "https://...",
        prtAbUrl: "https://...",
      },
      prefetch: {
        dnsPrefetch: ["https://cdn.example.com"],
        preloadScripts: ["https://example.com/script.js"],
      },
    }}
  />
</head>
```

**Props:**
| Prop | Type | Description |
|------|------|-------------|
| `config.abTesting.prtConfigUrl` | `string` | A/B testing config URL |
| `config.abTesting.prtAbUrl` | `string` | A/B testing script URL |
| `config.prefetch.dnsPrefetch` | `string[]` | Domains to DNS prefetch |
| `config.prefetch.preloadScripts` | `string[]` | Scripts to preload |
| `config.clarity.projectId` | `string` | Microsoft Clarity ID |

**Environment Variables:**
- `NEXT_PUBLIC_PRT_CONFIG_URL`
- `NEXT_PUBLIC_PRT_AB_URL`
- `NEXT_PUBLIC_CLARITY_ID`

---

### AppAnalytics

Body analytics scripts for GA, PostHog, and Facebook Pixel.

```tsx
import { AppAnalytics } from "@shopkit/app-shell";

<body>
  {/* ... content ... */}
  <AppAnalytics
    config={{
      googleAnalytics: { measurementId: "G-XXXXX" },
      posthog: { apiKey: "phc_XXXXX", apiHost: "https://..." },
      facebookPixel: { pixelId: "XXXXX" },
    }}
  />
</body>
```

**Environment Variables (used as defaults):**
- `NEXT_PUBLIC_GA_ID` - Google Analytics measurement ID
- `NEXT_PUBLIC_GOOGLE_ADS_ID` - Google Ads conversion ID
- `NEXT_PUBLIC_POSTHOG_KEY` - PostHog API key
- `NEXT_PUBLIC_POSTHOG_HOST` - PostHog API host
- `NEXT_PUBLIC_PIXEL_ID` - Facebook Pixel ID

---

### AppProductTracker

Product detail page (PDP) view tracking with engagement metrics.

```tsx
import { AppProductTracker } from "@shopkit/app-shell";

<AppProductTracker
  productData={{
    id: "variant-123",
    title: "Amazing Product",
    price: 999.99,
    currency: "INR",
    category: "Electronics",
    brand: "MyBrand",
  }}
  dwellTimeSeconds={20}
  disableDwellTracking={false}
/>
```

**Props:**
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `productData.id` | `string` | Required | Product/variant ID |
| `productData.title` | `string` | Required | Product title |
| `productData.price` | `number` | Required | Product price |
| `productData.currency` | `string` | `"INR"` | Currency code |
| `productData.category` | `string` | - | Product category |
| `productData.brand` | `string` | - | Brand name |
| `dwellTimeSeconds` | `number` | `20` | Seconds before firing engagement event |
| `disableDwellTracking` | `boolean` | `false` | Disable dwell tracking |

**Events Fired:**
1. `view_item` - Immediately on mount
2. `viewed_product` - After dwell time (engagement signal)

---

### Toast System

#### AppToast (Provider)

```tsx
import { AppToast, AppToastContainer } from "@shopkit/app-shell";

<AppToast>
  {children}
  <AppToastContainer />
</AppToast>
```

#### useToast (Hook)

```tsx
import { useToast } from "@shopkit/app-shell";

function MyComponent() {
  const { addToast, removeToast, clearToasts, toasts } = useToast();

  const showSuccess = () => {
    addToast({
      type: "success",
      title: "Success!",
      message: "Item added to cart",
      duration: 3000, // optional, defaults to 3000ms
    });
  };

  return <button onClick={showSuccess}>Add to Cart</button>;
}
```

**Toast Types:**
- `success` - Green success message
- `error` - Red error message
- `warning` - Amber warning message
- `info` - Blue info message

**Toast Containers:**
- `AppToastContainer` - Bottom-right, minimal style
- `AppToastContainerV1` - Top-right, with icons

---

### AppRouteLoader

Navigation progress indicator that shows during page transitions.

```tsx
import { AppRouteLoader } from "@shopkit/app-shell";

// Usually included in AppShell, but can be used standalone
<AppRouteLoader />
```

**Features:**
- Animated progress bar (0-90% during load)
- Completes to 100% on navigation finish
- Ignores external links, button clicks, modifier keys
- Handles browser back/forward navigation
- 5-second timeout fallback

---

## Type Exports

```tsx
import type {
  // AppShell
  AppShellConfig,
  AppShellProps,
  AnalyticsConfig,
  FontConfig,
  ExperimentConfig,

  // AppHead
  AppHeadConfig,
  AppHeadProps,
  ABTestingConfig,
  PrefetchConfig,
  ClarityConfig,

  // AppAnalytics
  AppAnalyticsConfig,
  AppAnalyticsProps,
  GoogleAnalyticsConfig,
  PostHogConfig,
  FacebookPixelConfig,
  TrackingContext,
  AppAnalyticsInitConfig,
  AppAnalyticsInitProps,
  TrackedProductData,
  AppProductTrackerProps,

  // AppToast
  Toast,
  ToastContextType,
  AppToastProps,
} from "@shopkit/app-shell";
```

---

## Environment Variables Reference

```bash
# Google Analytics
NEXT_PUBLIC_GA_ID=G-XXXXXXXXXX
NEXT_PUBLIC_GOOGLE_ADS_ID=AW-XXXXXXXXXX

# Facebook Pixel
NEXT_PUBLIC_PIXEL_ID=XXXXXXXXXX

# PostHog
NEXT_PUBLIC_POSTHOG_KEY=phc_XXXXXXXXXX
NEXT_PUBLIC_POSTHOG_HOST=https://app.posthog.com

# A/B Testing
NEXT_PUBLIC_PRT_CONFIG_URL=https://...
NEXT_PUBLIC_PRT_AB_URL=https://...

# Microsoft Clarity
NEXT_PUBLIC_CLARITY_ID=XXXXXXXXXX

# Shopify Analytics
NEXT_PUBLIC_SHOPIFY_SHOP_ID=XXXXX
NEXT_PUBLIC_SHOPIFY_STORE_ANALYTIC_DOMAIN=example.myshopify.com
```

---

## Testing

```bash
bun run test        # Run tests
bun run test:watch  # Watch mode
bun run test:coverage  # With coverage
```

---

## Development

```bash
bun run dev         # Watch mode for development
bun run build       # Build the package
bun run typecheck   # Type check
bun run clean       # Clean dist folder
```

---

## License

MIT