# Presence Client

## Content

The **[Presence](https://developer.mescius.com/spreadjs/api/collaboration/js-collaboration-presence-client/classes/Presence)** class is the core class provided by `js-collaboration-presence-client`, used to manage the local user's presence state and communicate with the server. It establishes a connection with the server through a Connection object, allowing users to:

* Submit local state (e.g., selected area)
* Listen for changes in other users' states
* Reflect the states of all collaborators on the interface

## Properties

| Property Name | Description | Type |
| ------------- | ----------- | ---- |
| `localState` | The presence state object of the local user. | `P` |
| `otherStates` | A collection of other users' presence states, stored as key-value pairs (key is the user ID, value is the state object). | `IPresences<P>` |
| `connection` | The connection object to the server. | `Connection` |

## Methods

### submitLocalState

Sends the local state to the server, which will broadcast it to other clients. The [message type](/spreadjs/docs/v18/spreadjs-collaboration-server/collaboration-framework/js-collaboration/messages-sending-and-receiving) is `"presence"`.

```typescript
submitLocalState(p: P): void;
```

**Parameter**
`p (P)`：The local user's Presence state object.
**Example**

```typescript
presence.submitLocalState({ userId: xxx, selection: xxx }); // Submit the user ID and selection information.
```

### submitLocalStateField

Updates a specified field of the local Presence object and submits it to the server. The server will broadcast the updated information to other clients. The [message type](/spreadjs/docs/v18/spreadjs-collaboration-server/collaboration-framework/js-collaboration/messages-sending-and-receiving) is `"presence"`.

```typescript
submitLocalStateField(name: string, value: unknown): void;
```

**Parameters**

* `name` (`string`)：The name of the field in the Presence object to update.
* `value` (`unknown`)：The new value to set.

**Example**

```typescript
presence.submitLocalState({ userId: 'id1', selection: 'range1' }); // presence.localState is { userId: 'id1', selection: 'range1' }
presence.submitLocalStateField('selection', 'range2') // presence.localState is { userId: 'id1', selection: 'range2' }
```

### removeLocalState

Removes the local presence object from the server, and the server will broadcast this to other clients.

```typescript
removeLocalState(): void;
```

### subscribe

Subscribes to other users' states.

```typescript
subscribe(): Promise<void>;
```

**Return**
`Promise<void>`：Returns a promise that resolves when subscription is complete; access other states via "presence.otherStates".
**Example**

```typescript
const uiComponent = new xxx.uiComponent(); // Replace with your UI component
await presence.subscribe();
uiComponent.showPresences(presence.otherStates);// Replace with your UI component's function to display presences.
```

### destroy

Destroys the instance and releases all resources.

```typescript
destroy: () => void;
```

## Events

Presence supports the following events, managed using the `on`, `once`, and `off` methods:

| Event Name | Description | Parameter |
| ---------- | ----------- | --------- |
| `add` | User joins | `addedPresences: IPresences<P>` |
| `update` | User presence state updates | `updatedPresences: IPresences<P>` |
| `remove` | User leaves | `removedPresencesIds: string[]` |

### on

Registers an event listener.

```typescript
on<NAME extends keyof IPresenceEvents<P>>(name: NAME, f: IPresenceEvents<P>[NAME]): IPresenceEvents<P>[NAME]
```

**Parameters**

* `name (NAME)`: name of the event, must be a key in the IPresenceEvents\<P> interface.
* `f (IPresenceEvents<P>[NAME])`: The event handler function.

**Return**
`IPresenceEvents<P>[NAME]`: The registered event handler.
**Example**

```typescript
presence.on('add', (addedPresences) => {
    console.log(addedPresences);
});
```

### once

Registers an event listener that triggers only once.

```typescript
once<NAME extends keyof IPresenceEvents<P>>(name: NAME, f: IPresenceEvents<P>[NAME]): void
```

**Parameters**

* `name (NAME)`: The name of the event, must be a key in the IPresenceEvents\<P> interface.
* `f (IPresenceEvents<P>[NAME])`: The event handler function.

**Example**

```typescript
presence.once('update', (updatedPresences) => {
    console.log(updatedPresences);
});
```

### off

Removes a specified event listener.

```typescript
off<NAME extends keyof IPresenceEvents<P>>(name: NAME, f: IPresenceEvents<P>[NAME]): void
```

**Parameters**

* `name (NAME)`: The name of the event, must be a key in the IPresenceEvents\<P> interface.
* `f (IPresenceEvents<P>[NAME])`: The event handler function.

# Usage

1. Install npm Packages

    ```bash
    npm install @mescius/js-collaboration-client @mescius/js-collaboration-presence-client
    ```
2. Create a `Presence` Instance

    ```typescript
    import { Client } from "@mescius/js-collaboration-client";
    import { Presence } from "@mescius/js-collaboration-presence-client";
    
    const conn = new Client('ws://localhost:8080/').connect('room1');
    const presence = new Presence(conn);
    ```
3. Subscribe to "Presence" States

    ```typescript
    const uiComponent = new xxx.uiComponent(); // Replace with your UI component
    await presence.subscribe();
    uiComponent.showPresences(presence.otherStates); // Replace with your UI component's function to display presences.
    ```
4. Listen for "Presence" State Changes

    ```typescript
    presence.on('add', () => {
        uiComponent.showPresences(presence.otherStates);
    });
    presence.on('update', () => {
        uiComponent.showPresences(presence.otherStates);
    });
    presence.on('remove', () => {
        uiComponent.showPresences(presence.otherStates);
    });
    ```
5. Submit Local "Presence" State on Initialization

    ```typescript
    presence.submitLocalState({ userId: xxx, selection: xxx }); // Replace with actual user ID and selection information
    ```
6. Submit "Presence" State on UI Component State Changes

    ```typescript
    uiComponent.on('selectionChanges', () => {
        // Partial update of presence, only updating selection. Replace with actual selection information.
        presence.submitLocalStateField('selection', xxx);
    });
    ```

### Complete Example

```typescript
import { Client } from "@mescius/js-collaboration-client";
import { Presence } from "@mescius/js-collaboration-presence-client";

const conn = new Client('ws://localhost:8080/').connect('room1');
const presence = new Presence(conn);
const uiComponent = new xxx.uiComponent(); // Replace with your UI component

presence.subscribe().then(() => {
    uiComponent.showPresences(presence.otherStates); // Replace with your UI component's function to display presences.

    presence.submitLocalState({ userId: xxx, selection: xxx }); // Replace with actual user ID and selection information

    uiComponent.on('selectionChanges', () => {
        // Partial update of presence, only updating selection, Replace with actual selection information.
        presence.submitLocalStateField('selection', xxx);
    });

    presence.on('add', () => {
        uiComponent.showPresences(presence.otherStates);
    });
    presence.on('update', () => {
        uiComponent.showPresences(presence.otherStates);
    });
    presence.on('remove', () => {
        uiComponent.showPresences(presence.otherStates);
    });
});
```

# API

For a complete API introduction, see: [js-collaboration-presence-client](/spreadjs/api/v18/collaboration/js-collaboration-presence-client/README#spreadjs-api)