# Tutorial: Use Presence

## Content

This tutorial builds on the "[Real-Time Collaborative Workbook](/spreadjs/docs/v18/spreadjs-collaboration-server/spreadjs-sheets-collaboration/tutorial-real-time-collaborative-spreadjs-designer)" tutorial to configure Presence.

## Prerequisites

* Complete the [Real-Time Collaborative Workbook](/spreadjs/docs/v18/spreadjs-collaboration-server/spreadjs-sheets-collaboration/tutorial-real-time-collaborative-spreadjs-designer)
* Foundational knowledge of [Presence](/spreadjs/docs/v18/spreadjs-collaboration-server/spreadjs-sheets-collaboration/user/presence)

## Effect

![use-presence](https://cdn.mescius.io/document-site-files/images/7719ad0a-f083-46d7-aff6-f63e2e187c15/use-presence.dca6cc.png)

## Specific Steps

### Step 1: Install Dependencies

```bash
npm install sqlite3 @mescius/js-collaboration-ot-sqlite
npm install @mescius/js-collaboration-presence-client @mescius/js-collaboration-presence
```

### Step 2: Modify server.js

Replace the code from the basic tutorial with the following content:

```javascript
import express from 'express';
import http from 'http';
import { Server } from '@mescius/js-collaboration';
import * as OT from '@mescius/js-collaboration-ot';
import { type } from '@mescius/spread-sheets-collaboration';
import { presenceFeature } from '@mescius/js-collaboration-presence';

const mockUsers = [
    // allow edit
    {id: '0', name: "editUser", color: "#0000ff", mode: 'edit'},
    // viewer
    {id: '1', name: "viewerUser", color: '008000', mode: 'viewer'},
    // viewer
    {id: '2', name: "viewerUser", color: '9900cc', mode: 'viewer'},
];

// Register the type
OT.TypesManager.register(type);

const app = express();
const httpServer = http.createServer(app);
const server = new Server({ httpServer });
const port = 8080;

// Initialize OT document services
const documentServices = new OT.DocumentServices();
server.useFeature(OT.documentFeature(documentServices));
server.useFeature(presenceFeature());

// Initialize OT document services
app.use(express.static('public'));

// Authentication middleware
server.use("connect", async (context, next) => {
    const token = context.connection.auth?.token;
    if (!token) return await next("No token provided");
    try {
        const user = mockUsers.find(u => u.id === token);
        if (!user) return await next("User does not exist");
        context.connection.tags.set("user", { id: user.id, username: user.name, mode: user.mode });
        await next();
    } catch {
      await next("Invalid token");
    }
});

// Validate submission permissions for ops
documentServices.use('submit', async (context, next) => {
    console.log('Received message User ID:', context.connection.auth?.token);
    const userInfo = context.connection.tags.get('user');
    if (!userInfo) {
        console.error('User information does not exist');
        await next('User information does not exist');
    }
    if (userInfo.mode === 'viewer') {
        console.error('Read-only users cannot edit');
        await next('Read-only users cannot edit');
    }
    await next();
});

// Start the server
httpServer.listen(port, () => {
    console.log(`Server listening on port ${port}`);
    console.log(`<http://127.0.0.1:${port}/index.html`);
});
```

### Step 3: Modify client.js

Replace the code from the basic tutorial with the following content:

```javascript
import * as GC from '@mescius/spread-sheets'
import '@mescius/spread-sheets-collaboration-addon';
import {Client} from "@mescius/js-collaboration-client";
import * as OT from "@mescius/js-collaboration-ot-client";
import { type, bind, bindPresence} from '@mescius/spread-sheets-collaboration-client';
import "@mescius/spread-sheets/styles/gc.spread.sheets.excel2013white.css";
import {Presence} from "@mescius/js-collaboration-presence-client";

const BrowsingMode = GC.Spread.Sheets.Collaboration.BrowsingMode;
const mockUsers = [
    // allow edit
    {id: '0', name: "editUser", color: "#0000ff", mode: 'edit'},
    // viewer
    {id: '1', name: "viewerUser", color: '008000', mode: 'viewer'},
    // viewer
    {id: '2', name: "viewerUser", color: '9900cc', mode: 'viewer'},
];

function getUser (id) {
    const user = mockUsers.find(u => u.id === id);
    return {
        ...user,
        permission: {
            mode: user.mode === 'edit' ? BrowsingMode.edit : BrowsingMode.view,
        }
    }
}

// Register the type
OT.TypesManager.register(type);
window.onload = async function(){
    const workbook = new GC.Spread.Sheets.Workbook('ss');
    // mock user
    const randomUserId = Math.floor(Math.random() * mockUsers.length);
    const user = getUser(`${randomUserId }`);
    // Connect to the server and join a room and add auth with user id
    const conn = new Client().connect('room1', { auth: { token: user.id } });
    const doc = new OT.SharedDoc(conn);
    // create presence
    const presence = new Presence(conn);
    // bind presence
    await bindPresence(workbook, presence, user);
    // bind user
    workbook.collaboration.setUser(user);
    doc.on('error', (err) => {
        // Handle errors can refresh the page or show a message to the user
        console.error('error:', err);
    });
    await doc.fetch();
    // Initialize content if the document doesn't exist
    if (!doc.type) {
        workbook.getActiveSheet().getCell(0, 0).value("default content");
        await doc.create(workbook.collaboration.toSnapshot(), type.uri, {});
        await bind(workbook, doc);
    } else {
        await bind(workbook, doc);
    }
}
```

### Step 4: Build and Run

1. Build the Client Code

    ```bash
    npm run build
    ```
2. Start the Server

    ```bash
    npm run start
    ```

## Next Steps

Configure specific operational permissions to different users: [Tutorial: Use Permissions](/spreadjs/docs/v18/spreadjs-collaboration-server/spreadjs-sheets-collaboration/tutorial-real-time-collaborative-spreadjs-designer/tutorial-use-permissions).