# Presence Client

## Content

**[Presence](/spreadjs/api/v19/collaboration/js-collaboration-presence-client/classes/Presence)** 클래스는 `js-collaboration-presence-client`에서 제공하는 핵심 클래스로, 로컬 사용자의 Presence 상태를 관리하고 서버와 통신하는 데 사용됩니다. Connection 객체를 통해 서버와 연결을 설정하며, 다음 기능을 제공합니다.

* 로컬 상태 제출(예: 선택 영역)
* 다른 사용자의 상태 변경 수신
* 모든 동시 작업 사용자의 상태를 인터페이스에 반영

## 속성

| 속성 이름 | 설명 | 타입 |
| ----- | --- | --- |
| `localState` | 로컬 사용자의 Presence 상태 객체 | `P` |
| `otherStates` | 다른 사용자들의 Presence 상태 컬렉션(키: 사용자 ID, 값: 상태 객체) | `IPresences<P>` |
| `connection` | 서버와의 연결 객체 | `Connection` |

## 메서드

### submitLocalState

로컬 상태를 서버로 전송하며, 서버는 이를 다른 클라이언트에 브로드캐스트합니다. [메시지 타입](/spreadjs/docs/v19/spreadjs-collaboration-server/collaboration-framework/js-collaboration/messages-sending-and-receiving)은 `"presence"`입니다.

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

**매개변수**
`p (P)`：로컬 사용자의 Presence 상태 객체
**예제**

```typescript
presence.submitLocalState({ userId: xxx, selection: xxx }); // 사용자 ID와 선택 정보 제출
```

### submitLocalStateField

로컬 Presence 객체의 특정 필드를 업데이트하고 서버로 전송합니다. 서버는 업데이트된 정보를 다른 클라이언트에 브로드캐스트합니다. [메시지 타입](/spreadjs/docs/v19/spreadjs-collaboration-server/collaboration-framework/js-collaboration/messages-sending-and-receiving)은 `"presence"`입니다.

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

**매개변수**

* `name` (`string`)：업데이트할 Presence 객체의 필드 이름
* `value` (`unknown`)：설정할 새 값

**예제**

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

### removeLocalState

서버에서 로컬 Presence 객체를 제거하며, 서버는 이를 다른 클라이언트에 브로드캐스트합니다.

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

### subscribe

다른 사용자들의 상태를 구독합니다.

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

**반환값**
`Promise<void>`：구독이 완료되면 resolve되며, `"presence.otherStates"`를 통해 다른 사용자 상태에 접근할 수 있습니다.
**예제**

```typescript
const uiComponent = new xxx.uiComponent(); // UI 컴포넌트로 대체
await presence.subscribe();
uiComponent.showPresences(presence.otherStates); // Presence 표시 함수로 대체
```

### destroy

인스턴스를 파기하고 모든 리소스를 해제합니다.

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

## 이벤트

Presence는 `on`, `once`, `off` 메서드를 사용하여 다음 이벤트를 지원합니다.

| 이벤트 이름 | 설명 | 매개변수 |
| ------ | --- | ---- |
| `add` | 사용자 참여 | `addedPresences: IPresences<P>` |
| `update` | 사용자 Presence 상태 업데이트 | `updatedPresences: IPresences<P>` |
| `remove` | 사용자 퇴장 | `removedPresencesIds: string[]` |

### on

이벤트 리스너를 등록합니다.

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

**매개변수**

* `name (NAME)`：이벤트 이름, IPresenceEvents 인터페이스의 키여야 함
* `f (IPresenceEvents<P>[NAME])`：이벤트 핸들러 함수

**반환값**
`IPresenceEvents<P>[NAME]`：등록된 이벤트 핸들러
**예제**

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

### once

한 번만 실행되는 이벤트 리스너를 등록합니다.

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

**매개변수**

* `name (NAME)`：이벤트 이름, IPresenceEvents 인터페이스의 키여야 함
* `f (IPresenceEvents<P>[NAME])`：이벤트 핸들러 함수

**예제**

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

### off

지정한 이벤트 리스너를 제거합니다.

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

**매개변수**

* `name (NAME)`：이벤트 이름, IPresenceEvents 인터페이스의 키여야 함
* `f (IPresenceEvents<P>[NAME])`：이벤트 핸들러 함수

# 사용 방법

1. npm 패키지 설치

    ```bash
    npm install @mescius/js-collaboration-client @mescius/js-collaboration-presence-client
    ```
2. `Presence` 인스턴스 생성

    ```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. "Presence" 상태 구독

    ```typescript
    const uiComponent = new xxx.uiComponent(); // UI 컴포넌트로 대체
    await presence.subscribe();
    uiComponent.showPresences(presence.otherStates); // Presence 표시 함수로 대체
    ```
4. "Presence" 상태 변경 수신

    ```typescript
    presence.on('add', () => {
        uiComponent.showPresences(presence.otherStates);
    });
    presence.on('update', () => {
        uiComponent.showPresences(presence.otherStates);
    });
    presence.on('remove', () => {
        uiComponent.showPresences(presence.otherStates);
    });
    ```
5. 초기화 시 로컬 "Presence" 상태 제출

    ```typescript
    presence.submitLocalState({ userId: xxx, selection: xxx }); // 실제 사용자 ID와 선택 정보로 대체
    ```
6. UI 컴포넌트 상태 변경 시 "Presence" 상태 제출

    ```typescript
    uiComponent.on('selectionChanges', () => {
        // selection만 부분 업데이트, 실제 선택 정보로 대체
        presence.submitLocalStateField('selection', xxx);
    });
    ```

### 전체 예제

```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(); // UI 컴포넌트로 대체

presence.subscribe().then(() => {
    uiComponent.showPresences(presence.otherStates); // Presence 표시 함수로 대체

    presence.submitLocalState({ userId: xxx, selection: xxx }); // 실제 사용자 ID와 선택 정보로 대체

    uiComponent.on('selectionChanges', () => {
        // selection만 부분 업데이트, 실제 선택 정보로 대체
        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

전체 API 소개는 다음을 참조하십시오:
[js-collaboration-presence-client 인터페이스](/spreadjs/api/v19/collaboration/js-collaboration-presence-client/README#spreadjs-api)