Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial version #2

Merged
merged 20 commits into from
May 7, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 0 additions & 10 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,4 @@ module.exports = {
version: 'detect',
},
},
overrides: [
{
files: [
'**/*.stories.tsx',
],
rules: {
'import/no-default-export': 'off',
},
},
],
};
8 changes: 4 additions & 4 deletions .github/workflows/branch-validations.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
with:
node-version: 16
node-version: 20

- name: Cache dependencies
id: cache-dependencies
Expand All @@ -41,7 +41,7 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
with:
node-version: 16
node-version: 20

- name: Cache dependencies
id: cache-dependencies
Expand All @@ -65,7 +65,7 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
with:
node-version: 16
node-version: 20

- name: Cache dependencies
id: cache-dependencies
Expand All @@ -89,7 +89,7 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
with:
node-version: 16
node-version: 20

- name: Cache dependencies
id: cache-dependencies
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/deploy-published-releases.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
with:
node-version: 16
node-version: 20

- name: Cache dependencies
id: cache-dependencies
Expand Down
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
coverage/
node_modules/
build/
storybook-static/
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2021 Croct.com
Copyright (c) 2024 Croct.com

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
167 changes: 152 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
<p align="center">
<a href="https://www.npmjs.com/package/@croct/plug-next"><img alt="Version" src="https://img.shields.io/npm/v/@croct/plug-next"/></a>
<a href="https://github.com/croct-tech/plug-next/actions?query=workflow%3AValidations"><img alt="Build" src="https://github.com/croct-tech/plug-next/workflows/Validations/badge.svg"/></a>
<a href="https://codeclimate.com/repos/60665953e0608a018c001907/maintainability"><img alt="Maintainability" src="https://api.codeclimate.com/v1/badges/24f7d3e788ed2c66f2ab/maintainability"/></a>
<a href="https://codeclimate.com/repos/60665953e0608a018c001907/test_coverage"><img alt="Coverage" src="https://api.codeclimate.com/v1/badges/24f7d3e788ed2c66f2ab/test_coverage"/></a>
<a href="https://codeclimate.com/repos/6637c6af2b3e4d40361ecb09/maintainability"><img alt="Maintainability" src="https://api.codeclimate.com/v1/badges/0552346701398a87ef7b/maintainability"/></a>
<a href="https://codeclimate.com/repos/6637c6af2b3e4d40361ecb09/test_coverage"><img alt="Coverage" src="https://api.codeclimate.com/v1/badges/0552346701398a87ef7b/test_coverage"/></a>
<br />
<br />
<a href="https://github.com/croct-tech/plug-next/releases">📦 Releases</a>
Expand Down Expand Up @@ -47,6 +47,19 @@ npm install @croct/plug-next
Before you can start using the library, you need to set the environment variables and configure a middleware to
populate the request scope with the client context.

#### Environment variables

Create or update the `.env.local` file in the root of your project and add the following environment variables:

```dotenv
CROCT_API_KEY=<API_KEY>
NEXT_PUBLIC_CROCT_APP_ID=<APP_ID>
```

You can find your API Key and Application ID in the Croct dashboard under Workspaces > Applications > Setup.
marcospassos marked this conversation as resolved.
Show resolved Hide resolved
The API key is a secret key that should be kept confidential and never exposed to the client side. To create a new API key
go to Workspaces > Applications > API Keys.
marcospassos marked this conversation as resolved.
Show resolved Hide resolved

#### Middleware

The configuration of the middleware slightly varies depending on whether you already have a middleware in your application or not.
Expand Down Expand Up @@ -129,19 +142,6 @@ export {config} from '@croct/plug-next/middleware';
export const middleware = withCroct(logHeaders);
```

#### Environment variables

Create or update the `.env.local` file in the root of your project and add the following environment variables:

```dotenv
CROCT_API_KEY=<API_KEY>
NEXT_PUBLIC_CROCT_APP_ID=<APP_ID>
```

You can find your API Key and Application ID in the Croct dashboard under Workspaces > Applications > Setup.
The API key is a secret key that should be kept confidential and never exposed to the client side. To create a new API key
go to Workspaces > Applications > API Keys.

### Initialization

You connect Croct to your application with the `<CroctProvider />` component. The `<CroctProvider />` uses a regular React's
Expand Down Expand Up @@ -219,6 +219,143 @@ export default async function Example(): Promise<ReactElement> {
}
```

### Identifying users

By default, all users are considered anonymous. However, if your application has logged-in areas,
you may want to link the Croct user profile with your application's user ID. This allows you
to personalize the user experience consistently across devices and sessions.

The SDK offers two options for identifying users, which you can choose depending on how you
manage user sessions in your application.

#### Automatic identification

The first method is to provide the middleware with a function that resolves the user ID from the request,
so that it can automatically handle the entire process of identifying and anonymizing users for you.

This is the recommended approach if you have a secure way to determine the user ID from the request,
such as a session token or JWT token.

Here is an example of how to implement this function:

```ts
import {NextRequest, NextResponse} from 'next/server';

function resolveUserId(request: NextRequest): string|null {
const userToken = request.cookies.get('my-session-token');

if (userToken === null) {
return null;
}

try {
// The logic to extract the user ID from the token and validate it.
return userId;
} catch {
return null;
}
}

export {config} from '@croct/plug-next/middleware';

export const middleware = withCroct({userIdResolver: resolveUserId});
```

#### Manual identification

If you do not have a way to automatically identify users, you can use the `identify` and `anonymize` functions
to manually handle the identification and anonymization of users.

The example above shows an example using [server actions](https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations):

```tsx
// app/actions.ts
'use server';

import {anonymize, identify} from '@croct/plug-next/server';

export async function identifyUser(userId: string): Promise<void> {
await identify(userId);
}

export async function anonymizeUser(): Promise<void> {
await anonymize();
}
```

Now, suppose you have the following form in your application:

```tsx
'use client';

import React, {FunctionComponent} from 'react';
import {login} from '@/app/services';
import {identifyUser} from '@/app/actions';

export const LoginForm: FunctionComponent = () => {
const onSubmit = async (form: FormData): Promise<void> => {
const username = form.get('username');
const password = form.get('password');

await login(username, password)
};

return (
<form action={onSubmit}>
<input type="text" name="username" />
<input type="password" name="password" />
<button type="submit">Login</button>
</form>
);
};
```

After successful login, you can identify the user as follows:

```tsx
'use client';

import React, {FunctionComponent} from 'react';
import {login} from '@/app/services';
import {identifyUser} from '@/app/actions';

export const LoginForm: FunctionComponent = () => {
const onSubmit = async (form: FormData): Promise<void> => {
const username = form.get('username');
const password = form.get('password');

if (await login(username, password)) {
// Identify the user after successfully logging in
await identifyUser(username);
}
};

return (
<form action={onSubmit}>
<input type="text" name="username" />
<input type="password" name="password" />
<button type="submit">Login</button>
</form>
);
};
```

You can anonymize the user after logging out in the same way:

```tsx
'use client';

import React, {FunctionComponent} from 'react';
import Link from 'next/link';
import {anonymizeUser} from '@/app/actions';

export const LogoutLink: FunctionComponent = () => (
<Link href="/login" onClick={() => anonymizeUser()}>
Anonymize
</Link>
);
```

## Support

If this documentation has not answered all your questions, don't worry.
Expand Down
Loading
Loading