npm package: @madlogic/chat-client
Description: The JavaScript client for Chat Service
Author: Madlogic
Latest version: 1.5.2

# Madlogic Chat Client JS

**@madlogic/chat-client** is a JavaScript client for Madlogic Chat Service to build chat applications.

## INSTALLATION

```bash
yarn add @madlogic/chat-client
```

## BACKEND NODEJS

#### Initializing Chat client

```javascript
import { ChatClient } from '@madlogic/chat-client';

const SERVER_CLIENT_CONFIG = {
  workspace_name: 'TestApp',
  workspace_secret: '#####',
  server_url: 'https://chat.madlogic.nl',
};

// Initialize chat client
const serverClient = new ChatClient(SERVER_CLIENT_CONFIG);
```

#### Syncing/Updating user

When a user starts a chat conversation with another user both users need to be present in the Chat Service database. So you'll want to make sure that users are synced in advance.

```javascript
const user = await serverClient.syncUser({
  id: 'user_1',
  email: 'user_1@app.domain',
  first_name: 'Abc',
  last_name: 'Xyz',
  display_name: 'Abc Xyz',
  picture: 'https://path.to/avatar.png',
  metadata: {
    custom_field: '...',
  },
});
```

#### Generating user token

The backend creates a token for a user. You hand that token to the client side during login or registration. This token allows the client side to connect to the chat API for that user.

```javascript
// Generate a token for the user with id 'user_1'
const token = await serverClient.generateUserToken('user_1', {
  expires_in: '30 days',
});
```

Options:

- `expires_in` (optional): expressed in seconds or a string describing a time span [vercel/ms](https://github.com/vercel/ms)
  > Eg: `60`, `"2 days"`, `"10h"`, `"7d"`. A numeric value is interpreted as a seconds count. If you use a string be sure you provide the time units (days, hours, etc), otherwise milliseconds unit is used by default (`"120"` is equal to `"120ms"`).

#### Remove a user

```javascript
// Remove user with id 'user_1'
const response = await serverClient.removeUser('user_1');
```

#### Push notifications

Chat Service supports push for both Android and iOS through integration with Firebase Cloud Messaging.

```javascript
const response = await serverClient.updateWorkspaceSettings({
  fcm_config: {
    service_account_key_base64: 'FCM_SERVICE_ACCOUNT_KEY_BASE64',
  },
});
```

> To encrypt a JSON file to Base64 string:
>
> ```bash
> base64 ~/Downloads/fcm-service-account-key.json
> ```

## JS APPLICATION (REACT/REACT NATIVE)

#### Initializing Chat client

```javascript
import { ChatClient } from '@madlogic/chat-client';

// Initialize chat client
const chatClient = new ChatClient({
  workspace_name: 'TestApp',
  server_url: 'https://chat.madlogic.nl',
});
```

#### Connect user to Chat server

```javascript
// Connect user
const user = await chatClient.connectUser('USER_TOKEN');
```

#### Query users

```javascript
const filter = {};

const query = { page: 1, per_page: 20, sort_by: 'created_at', sort_order: 'desc' };

const result = await chatClient.queryUsers(filter, query);

console.log(result); // { total_count: 10, items: [...] }
```

#### Create channel

```javascript
// Create TEAM channel
const channel = await chatClient.createTeamChannel({
  name: 'channel-abc',
  description: 'ABC Channel',
  image: 'https://picsum.photos/300/200',
  members: ['user_1'],
  public: true,
});

// Create DM (Direct Message) channel
const channel = await chatClient.createDMChannel({
  members: ['user_1'],
});
```

#### Get channel detail

```javascript
const channel = chatClient.channel('channel-id');
const channelDetail = await channel.getDetail();
```

#### Query channels

```javascript
const filter = {};

const query = { page: 1, per_page: 20, sort_by: 'last_message_at', sort_order: 'desc' };

const result = await chatClient.queryChannels(filter, query);

console.log(result); // { total_count: 10, items: [...] }
```

#### Update channel

```javascript
const channel = chatClient.channel('channel-id');
const updated = await channel.update({
  name: 'channel-abc',
  description: 'ABC Channel',
  image: 'https://picsum.photos/300/200',
});
```

#### Freeze / Unfreeze a channel

Freezing a channel will disallow sending new messages. Sending a message to a frozen channel will return an error.

```javascript
const channel = chatClient.channel('channel-id');
// Freeze
await channel.update({ frozen: true });
// Unfreeze
await channel.update({ frozen: false });
```

#### Remove a channel

```javascript
const channel = chatClient.channel('channel-id');
await channel.remove();
```

#### Query members

```javascript
const filter = {};

const query = { page: 1, per_page: 20, sort_by: 'joined_at', sort_order: 'desc' };

const channel = chatClient.channel('channel-id');

const result = await channel.queryMembers(filter, query);

console.log(result); // { total_count: 10, items: [...] }
```

#### Add members

```javascript
const channel = chatClient.channel('channel-id');
const result = await channel.addMembers(['user_1', 'user_2']);
```

#### Remove members

```javascript
const channel = chatClient.channel('channel-id');
await channel.removeMembers(['user_1', 'user_2']);
```

#### Leave a channel

```javascript
const channel = chatClient.channel('channel-id');
await channel.leave();
```

#### Query messages

```javascript
const filter = {};

const query = { page: 1, per_page: 20, sort_by: 'sent_at', sort_order: 'desc' };

const channel = chatClient.channel('channel-id');

const result = await channel.queryMessages(filter, query);

console.log(result); // { total_count: 10, items: [...] }
```

#### Send message

```javascript
const channel = chatClient.channel('channel-id');

// Send a regular message
channel.sendMessage({
  text: 'Hello World!',
});

// Send message with attachments
channel.sendMessage({
  text: 'Hello World!',
  attachments: [
    {
      type: 'image',
      title: 'Madlogic News',
      thumb_url: 'https://path.to/thumb_url.png',
      asset_url: 'https://path.to/asset_url.png',
    },
  ],
});
```

#### Typing

```javascript
const channel = chatClient.channel('channel-id');

// Start typing
channel.startTyping();
// Stop typing
channel.stopTyping();
```

#### Unread counts

```javascript
const channel = chatClient.channel('channel-id');

// Count of unread messages for the current user on a channel
const count = await channel.countUnread();
console.log(count); // 12

// Mark all messages on a channel as read
await channel.markRead();
```

#### Events

You always receive these events. Examples are: `message:new`, `ws:connected`, `ws:disconnected`,...

```javascript
// Listen for a new message from all channels
chatClient.on('message:new', (newMessage) => {
  console.log(newMessage);
});

// Listen for new message on a specific channel
chatClient.channel('channel-id').on('message:new', (newMessage) => {
  console.log(newMessage);
});

// Listen for typing from all channels
chatClient.on('typing:start', (payload) => {
  console.log(payload);
});

// Listen for typing from a specific channel
chatClient.channel('channel-id').on('typing:start', (payload) => {
  console.log(payload);
});
```

> Events:
>
> - `ws:connected`
> - `ws:reconnected`
> - `ws:disconnected`
> - `ws:error`
> - `message:new`
> - `typing:start`
> - `typing:stop`
> - `user:profile`
> - `channel:update`

#### Register a push device

```javascript
const device = await chatClient.registerDevice('d93ud8...', 'iOS');
```

#### Unregister a push device

```javascript
await chatClient.unregisterDevice('d93ud8...');
```

#### Upload attachment

```javascript
const FILE = 'string | NodeJS.ReadableStream | Buffer | File';
const onUploadProgress = (e) => console.log(e);
const { url } = await chatClient.uploadAttachment(FILE, onUploadProgress);
```