Integration

The page explains how to include the Sana into your own web application

Enabling Sana features on the Establishment web application, requires html integration with the prepackaged all-in-one Sana Javascript library. The library itself includes all the specifics for creation & running of the Sana component, user experience and integration with the chat backend.

In order to use the Sana, the Establishment is required to integrate the library according to the following description.

Include Javascript library

In order to integrate the Sana into the HTML page, Establishment is required to include the file into the HTML page where the Sana frontend component is needed. Establishment is also required to use Rofim's CDN and shall not deploy any copies of the file independently. This ensures that the component remains up-to-date, secure, and compatible with the latest standards.

<!DOCTYPE html>
<html ...>
  <head>
    ...
    <title>...</title>
    <script defer src='https://chat.staging.rofimoncloud.com/assets/main.js'></script>
    <!-- additional script tags -->
	</head>
	<body>
  	...
	</body>
</html>

Usage of the Sana Web Component

The next step is the creation and positioning of the Sana component. Based on your logic, the Sana component can be placed on any desired location on the host page. In order to create the component on a specific location, the sana-widget tag should be placed on the corresponding place on the HTML page source. After the page is loaded, the Sana component will be ready to be used. The Sana component is fully responsive and would fit into any reasonable-sized parent container. If no sizing constraints are given, the component will bootstrap into its built-in, default size.

To display the Sana component, the show() function should be called.

<!DOCTYPE html>
<html ...>
<body>
  <div id="chat">
    <sana-widget
      locale="en-GB"
      displayMode="LIGHTBOX"
    />
  </div>
</body>

Web Component Configuration

The full list of configuration is described in the SDK Configuration Guide.

Dynamic updating of the Sana Web Component

The Sana component is able to react to any changes of its properties. That means the Establishment can programmatically set/update its properties, and the component will update itself accordingly.

document.addEventListener('DOMContentLoaded', () => {
  const sanaWidget = document.getElementByTagName('sana-widget')[0];
  sanaWidget.setAttribute('displayMode', 'EMBEDDED');
});

Registration of event listeners

The Sana component will fire a component status event whenever there is an update that affects the status of the chat. The event contains data indicating the current state of the chat and also specific information regarding the currently fired event.

The next sample shows how to listen to fired event

const sanaWidget = document.getElementByTagName('sana-widget')[0];
sanaWidget.addEventListener('m.rofim.message', (e) => {
  // handle status events.
});

The structure of the event Object and event description are described here : XXXXX

Multiple instantiation of the Sana

In some cases, the Sana could be displayed more than once inside the Establishment. This can happen when the full chat is displayed and an act requires Contextualized Discussion. In this case the Sana is instancied twice.

METTRE UN SCHEMA EXEMPLE

In this case, it is essential to maintain references to each instance within the HTML tags. Additionally, it is crucial to manage events and API calls separately for each instance to ensure proper functionality and avoid conflicts. You may set an id to the html tag to differenciate the instances.

<!DOCTYPE html>
<html ...>
<body>
  <div id="chat">
    <sana-widget
      id="widget-1"
      locale="en-GB"
      displayMode="LIGHTBOX"
    />
    <sana-widget
      id="widget-2"
      locale="en-GB"
      displayMode="EMBEDDED"
    />
    <script>
      const sanaWidget1 = document.querySelector('sana-widget#widget-1');
      const sanaWidget2 = document.querySelector('sana-widget#widget-2');
      sanaWidget1.addEventListener('m.rofim.message', (e) => {
        const widgetId = event.target.id;
        // handle status events according widgetId.
      });
      ...
    </script>
  </div>
</body>

Custom file upload

You can add custom button behavior using JavaScript to upload files from a specific location. Use the property uploadcallbackconfig and add it to your Sana Element.

Integration Modes

This feature offers two modes of integration for defining your custom upload logic:

  • Passing a callback function object (function reference, anonymous function, etc.).
  • Passing a callback function name (so that when we call window['yourFunctionName'], your callback is executed).

Custom Upload Workflow

When the user clicks the custom upload button in the chat, your provided callback, will be immediately triggered. You are then responsible for the entire upload logic:

  1. File Selection : Within your callback, you must develop the user interface mechanism that allows the user to select the desired file.
  2. File Submission (Using the JS API): Once the user has selected a file, you must call the sendFileMessage API function to submit the file, along with the securityToken.

The securityToken, which is passed as an input parameter to your callback, must be included when calling sendFileMessage. This token is mandatory for authentication and security during the upload operation.

Security Token Management

The securityToken is a temporary, in-memory credential with a 10-minute timeout. It is important to note the following limitations regarding this token:

  • Session Dependency: The token is stored in the browser's memory and will be lost if the user navigates away from the Single-Page Web Application (SPWA). In Non-SPWA environments, the token will be lost upon any page change, requiring the user to regenerate it.
  • Room-Specific: Each securityToken is unique and directly tied to the specific chat room where the file upload was initiated. This ensures that the token can only be used for uploads within that designated room.

Function object example

<!DOCTYPE html>
<html ...>
<body>
  <div id="chat">
    <sana-widget
      id="widget-1"
      locale="en-GB"
      displayMode="LIGHTBOX"
    />
    <script>
      const sanaWidget = document.querySelector('sana-widget#widget-1');
      sanaWidget.uploadcallbackconfig = {
				callbacks: [
          {
            key: 'url-uploader',
            buttonLabel: 'Custom upload',
            title: 'Upload les fichiers à partir d\'une URL',
            icon: 'pi pi-link',
            callbackRef: {
              type: 'FUNCTION_OBJECT',
							// this is where you should pass a reference to your callback
              value: (context) => {
								// this is where you should implement your callback logic
								console.log(`we received a security token: ${context.securityToken}`);
							},
            },
          },
      	],
			}
      ...
    </script>
  </div>
</body>

Function name example

<!DOCTYPE html>
<html ...>
<body>
  <div id="chat">
    <sana-widget
      id="widget-1"
      locale="en-GB"
      displayMode="LIGHTBOX"
    />
    <script>
      const sanaWidget = document.querySelector('sana-widget#widget-1');
      sanaWidget.uploadcallbackconfig = {
				callbacks: [
          {
            key: 'url-uploader',
            buttonLabel: 'Custom upload',
            title: 'Upload les fichiers à partir d\'une URL',
            icon: 'pi pi-link',
            callbackRef: {
              type: 'FUNCTION_NAME',
							// this is where you should pass a your global function name
              value: 'aliasUploadUrl',
            },
          },
      	],
			}
      ...
      // And somewhere else in your DOM, you must declare the callback function
      function aliasUploadUrl(context) {
			// fetch some file url 
      const uploadFileUrlInput = document.getElementById('upload-file-url');
      let urlValue = uploadFileUrlInput.value;
      let sanaWidget = document.querySelector('#widget-1');
			// send the file url to the component along with the security token
      sanaWidget.sendFileMessage(context.securityToken, {
              type: 'file',
              securityToken: context.securityToken,
              uploadFile: {
                  type: 'URL',
                  url: publicUrlImageFile,
              },
          })
          .then(() => {
              console.log('success')
          })
          .catch((error) => {
              console.error('# CALLBACK ALIAS : Error during sendFileMessage:', error);
          });
  	}

    </script>
  </div>
</body>

Supported File Upload Methods The Custom File Upload API supports two methods for submitting files:

  1. URL-based Upload This method accepts a direct URL to the file. The chat component handles the file upload by fetching the content from the provided URL.

  2. Blob-based Upload This method is used for uploading a file directly from the user's browser. It requires two parameters: a file content blob and a filename. The chat component then processes and uploads the file.

Contextualized Room

To ensure a user can only interact with a specific chat room, you must configure the chat widget for a SINGLE_ROOM operation mode. This mode forces the component to restrict all user actions to a pre-selected room.

How to Configure Single-Room Mode

  • Create a room associated to an act
  • Set the widget's operationMode property to SINGLE_ROOM.
  • Set the singleRoomId property to the actId used when creating the room via the API.

By following these steps, the widget will only display the content of the designated room, preventing users from creating new rooms or accessing others. The sana will only propagate events from the active room. This is an effective way to embed the chat component within a specific workflow or context.

// select the sanaWidget component
const sanaWidget = document.getElementsByTagName('sana-widget')[0];

// create the room with the room creation api, tied to an act
sanaWidget.createRoom({
    roomName: 'some act',
    membersToInvite: ['[email protected]', '[email protected]'],
    act: {
        actType: 'te',
        actId: 'act_001',
        actUrl: 'https://staging.rofimoncloud.com/secure/teleexpertise/list'
    },
}).then(result => console.log(result)).catch(error => console.error(error));

// set the singleroomid to the component using previously defined actId
sanaWidget.singleroomid='act_001'
// change the component operationmode
sanaWidget.operationmode='SINGLE_ROOM'

When the Sana is loaded in SINGLE_ROOM mode, the ready event will contain the room's real ID within the singleroomid property. You can then use this ID to send files or messages to the room via the API.

You can also send a contextual message, such as a patient message. Unlike standard messages, contextual messages are not displayed in the chat stream; instead, their content appears in the room's header.

// select the sanaWidget component
const sanaWidget = document.getElementsByTagName('sana-widget')[0];

// Build a patient message
const patientMessage = {
  type: 'patient',
  lastName: 'Doe',
  firstName: 'John',
  maidenName: 'Smith',
  age: 42,
  birthdate: new Date('1990-12-20'),
  sex: 'M',
  nss: '123456789012345',
  ins: 'INS1234567890',
  patientId: 'PAT001',
  establishmentPatientId: 'ESTPAT001',
  establishmentPatientUrl: 'https://example.com/patient/pat001',
  establishmentPatientStayId: 'STAY001',
  twinRank: 1,
  email: '[email protected]',
  mobilePhone: '+33612345678',
  body: 'Some body.',
  formattedBody: '<b>Information</b> Some formatted body.'
}

// Send the message using the room id from the ready event 
sanaWidget.sendMessage('!mTaFfAMYvWCjFoopfQ:staging.rofimoncloud.com', patientMessage).then(() => console.log('success'));