import Link from 'next/link';
import { Callout, Steps, Tabs } from 'nextra/components';
import { DeviceIdWarning } from 'src/components/device-id-warning';
import { PersonalDataWarning } from 'src/components/personal-data-warning';

import SdkConfig from 'src/components/sdk-config.mdx';

# Next.js

Keep in mind that all tracking here happens on the client!

Read more about server side tracking in the [Server Side Tracking](#track-server-events) section.

## Installation

<Steps>
### Install dependencies

```bash
pnpm install @openpanel/nextjs
```

### Initialize

Add `OpenpanelProvider` to your root layout component.

```tsx
import { OpenpanelProvider } from '@openpanel/nextjs';

export default RootLayout({ children }) {
  return (
    <>
      <OpenpanelProvider
        url="https://api.openpanel.dev"
        clientId="your-client-id"
        trackScreenViews={true}
        // trackAttributes={true}
        // trackOutgoingLinks={true}
        // If you have a user id, you can pass it here to identify the user
        // profileId={'123'}
      />
      {children}
    </>
  )
}
```

#### Config

<SdkConfig />

### Ready!

You're now ready to use the library.

```typescript
import {
  decrement,
  increment,
  setProfile,
  setProfileId,
  trackEvent,
} from '@openpanel/nextjs';

// Sends an event with payload foo: bar
trackEvent('my_event', { foo: 'bar' });

// Identify with profile id
setProfileId('123');

// or with additional data
setProfile({
  profileId: '123',
  firstName: 'John',
  lastName: 'Doe',
  email: 'john.doe@openpanel.dev',
});

// Increment a property
increment('app_opened'); // increment by 1
increment('app_opened', 5); // increment by 5

// Decrement a property
decrement('app_opened'); // decrement by 1
decrement('app_opened', 5); // decrement by 5
```

</Steps>

## Usage

### Track event

<Tabs items={['JS', 'window', 'HTML']}>
  <Tabs.Tab>
    ```typescript
    import { trackEvent } from '@openpanel/nextjs';
    trackEvent('my_event', { foo: 'bar' });
    ```
  </Tabs.Tab>
  <Tabs.Tab>
    ```javascript
    window.op('event', 'my_event', { foo: 'bar' });
    ```
  </Tabs.Tab>
  <Tabs.Tab>
    For this to work you need to enable `trackAttributes` in the config.
    ```html
    <button data-event="my_event" data-foo="bar">Track event</button>
    ```
  </Tabs.Tab>
</Tabs>

### Identify

#### Set Profile Id

Keep track of your users by identifying them with a unique id. This is a good features if you have things behind a login and want to track user behavior.

<PersonalDataWarning />

```typescript
import { setProfileId } from '@openpanel/nextjs';

const profileId = '123';
setProfileId(profileId);
```

Or if you want to identify the user with a server component.

```typescript
import { SetProfileId } from '@openpanel/nextjs';

export function Layout({ children }) {
  return (
    <>
      <SetProfileId value={'123'} />
      {children}
    </>
  )
}
```

#### Additional data

This method does the same as `setProfileId` but also allows you to update the profile with additional data.

<PersonalDataWarning />

```typescript
import { setProfile } from '@openpanel/nextjs';

const profileId = '123';
setProfile({
  profileId,
  // firstName?: string;
  // lastName?: string;
  // email?: string;
  // avatar?: string;
  // properties?: Record<string, unknown>;
});
```

Or if you want to identify the user with a server component.

```typescript
import { SetProfile } from '@openpanel/nextjs';

export function Layout({ children }) {
  return (
    <>
      <SetProfile profileId={'12'} firstName={'Joe'} lastName={'Doe'} email={'joe.doe@openpanel.dev'} avatar={'https://image.com'} properties={{...}} />
      {children}
    </>
  )
}
```

#### Increment property

Increment a property on the profile.

```typescript
import { increment } from '@openpanel/nextjs';

// Increment by 1
increment('app_opened');

// Increment by 5
increment('app_opened', 5);
```

#### Decrement property

Decrement a property on the profile.

```typescript
import { decrement } from '@openpanel/nextjs';

// Increment by 1
decrement('app_opened');

// Increment by 5
decrement('app_opened', 5);
```

#### Clear / Logout

Clear the profile id and all the data.

```typescript
import { clear } from '@openpanel/nextjs';

clear();
```

## Track server events

If you want to track server-side events, you should create an instance of our Javascript SDK. It's exported from `@openpanel/nextjs`

<Callout>
When using server events it's important that you use a secret to authenticate the request. This is to prevent unauthorized requests since we cannot use cors headers.

You can use the same clientId but you should pass the associated client secret to the SDK.

</Callout>

```typescript
import { OpenpanelSdk } from '@openpanel/nextjs';

const opServer = new OpenpanelSdk({
  clientId: '{YOUR_CLIENT_ID}',
  clientSecret: '{YOUR_CLIENT_SECRET}',
});

opServer.event('my_server_event', { ok: '✅' });

// Pass `profileId` to track events for a specific user
opServer.event('my_server_event', { profileId: '123', ok: '✅' });
```

### Serverless & Vercel

If you log events in a serverless environment like Vercel, you can use `waitUntil` to ensure the event is logged before the function is done.

Otherwise your function might close before the event is logged. Read more about it [here](https://vercel.com/docs/functions/functions-api-reference#waituntil).

```typescript
import { waitUntil } from '@vercel/functions';
import { opServer } from 'path/to/your-sdk-instance';

export function GET() {
  // Returns a response immediately while keeping the function alive
  waitUntil(opServer.event('my_server_event', { foo: 'bar' }));
  return new Response(`You're event has been logged!`);
}
```

## Proxy events

With `createNextRouteHandler` you can proxy your events through your server, this will ensure all events are tracked since there is a lot of adblockers that block requests to third party domains.

```typescript
// file: /app/api/op/[...op]/route.ts
import { createNextRouteHandler } from '@openpanel/nextjs';

export const { POST } = createNextRouteHandler({
  clientId: '{YOUR_CLIENT_ID}',
  clientSecret: '{YOUR_CLIENT_SECRET}',
});
```

Remember to change the `url` in the `OpenpanelProvider` to your own server.

```tsx
<OpenpanelProvider
  url="/api/op" // <---
  clientId="your-client-id"
  trackScreenViews={true}
/>
```
