Skip to content
This repository has been archived by the owner on Jan 5, 2023. It is now read-only.

[feature] Private mode #34

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ node_modules
dist
types
.rpt2_cache
.DS_Store
shwarcu marked this conversation as resolved.
Show resolved Hide resolved
52 changes: 52 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,21 @@ interface ICustomerDetailsSectionButtonClick {

The `buttonId` property reflects the `id` specified for the button in the section definition.

#### `private_mode`

Emitted when agent toggles private mode in Chats section. The handler gets the following payload:

```ts
interface IPrivateMode {
threads: {
[key: string]: boolean;
};
source: 'chats';
}
```

_String_ key is thread ID and boolean represents state of private mode. True means enabled private mode, false means disabled private mode.

### Methods

#### `getCustomerProfile(): ICustomerProfile | null`
Expand Down Expand Up @@ -170,6 +185,17 @@ widget.modifySection(section);

The `title` of a given section has to match the one specified in the initial state. Otherwise, the section won't change. Also, the Agent App ignores the commands without valid section definitions. Make sure that the definition you're sending is correct.

#### `getPrivateModeState(): IPrivateMode | null`

Gets threads with private mode recorded most recently. Returns the `IPrivateMode` object, which is identical to the one emitted by the `private_mode` event or `null` (if no profile was registered). It may contain information about multiple threads, for example, when widget was initialized after agent has toggled private mode for some threads.

```ts
{
source: 'chats',
threads: { R80Q1FDEGX: true, R80Q1HDKP4: true }
}
```

## MessageBox widget (`IMessageBoxWidget`)

### Events
Expand All @@ -182,6 +208,21 @@ Emitted after the widget is opened in the MessageBox. The handler will get a `IC

Emitted after the message is sent by the agent. Keep in mind that the message has to be set with [`putMessage`] method in order to be sent.

#### `private_mode`

Emitted when agent toggles private mode in Chats section. The handler gets the following payload:

```ts
interface IPrivateMode {
threads: {
[key: string]: boolean;
};
source: 'chats';
}
```

_String_ key is thread ID and boolean represents state of private mode. True means enabled private mode, false means disabled private mode.

### Methods

#### `putMessage(msg: IRichMessage | string): Promise<void>`
Expand All @@ -206,6 +247,17 @@ widget.putMessage(richMessage);

Gets the customer profile recorded most recently. Returns the `ICustomerProfile` object, which is identical to the one emitted by the `customer_profile` event or `null` (if no profile was registered).

#### `getPrivateModeState(): IPrivateMode | null`

Gets threads with private mode recorded most recently. Returns the `IPrivateMode` object, which is identical to the one emitted by the `private_mode` event or `null` (if no profile was registered). It may contain information about multiple threads, for example, when widget was initialized after agent has toggled private mode for some threads.

```ts
{
source: 'chats',
threads: { R80Q1FDEGX: true, R80Q1HDKP4: true }
}
```

### Rich Message object format

- `custom_id`, `properties` and `elements` are optional
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@livechat/agent-app-sdk",
"version": "1.5.2",
"version": "1.6.0",
"description": "SDK for extending LiveChat's Agent App",
"license": "MIT",
"repository": {
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export * from './widgets/details';
export * from './widgets/messagebox';
export * from './widgets/fullscreen';
export * from './widgets/shared/customer-profile';
export * from './widgets/shared/private-mode';
4 changes: 4 additions & 0 deletions src/utils/types.ts
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
export type Omit<T, K> = Pick<T, Exclude<keyof T, K>>;

export interface KeyMap<T = any> {
[key: string]: T;
}
10 changes: 10 additions & 0 deletions src/widgets/connection/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export enum PluginType {
MessageBox = 'messagebox',
Details = 'details',
Fullscreen = 'fullscreen'
}

export enum PluginMessage {
Inited = 'plugin_inited',
shwarcu marked this conversation as resolved.
Show resolved Hide resolved
Loaded = 'plugin_loaded'
}
12 changes: 9 additions & 3 deletions src/widgets/details/details-widget.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { withAmplitude } from '../shared/amplitude';
import { withCustomerProfile } from '../shared/customer-profile';
import { withRichMessages } from '../shared/rich-messages';
import { withPrivateMode } from '../shared/private-mode';
import { createWidget } from '../shared/widget';
import { IConnection, createConnection } from '../connection';
import assertSection from './custom-sections';
Expand All @@ -9,6 +10,7 @@ import {
IDetailsWidgetApi,
ISection
} from './interfaces';
import { PluginMessage, PluginType } from '../connection/constants';

function DetailsWidget(connection: IConnection<IDetailsWidgetEvents>) {
const base = createWidget<IDetailsWidgetApi, IDetailsWidgetEvents>(
Expand All @@ -21,7 +23,7 @@ function DetailsWidget(connection: IConnection<IDetailsWidgetEvents>) {
return connection.sendMessage('watch_messages');
},
refreshSession(): Promise<void> {
return connection.sendMessage('plugin_loaded');
return connection.sendMessage(PluginMessage.Loaded);
},
modifySection(section: ISection): Promise<void> {
assertSection(section);
Expand All @@ -30,7 +32,9 @@ function DetailsWidget(connection: IConnection<IDetailsWidgetEvents>) {
}
);

const widget = withAmplitude(withRichMessages(withCustomerProfile(base)));
const widget = withAmplitude(
withRichMessages(withCustomerProfile(withPrivateMode(base)))
);

return widget;
}
Expand All @@ -42,7 +46,9 @@ export default function createDetailsWidget(): Promise<IDetailsWidget> {
return createConnection()
.then(connection => {
widget = DetailsWidget(connection);
return connection.sendMessage('plugin_inited');
return connection.sendMessage(PluginMessage.Inited, {
plugin_type: PluginType.Details
});
})
.then(() => widget);
}
13 changes: 10 additions & 3 deletions src/widgets/fullscreen/fullscreen-widget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { createWidget } from '../shared/widget';
import { withAmplitude } from '../shared/amplitude';
import { IConnection, createConnection } from '../connection';
import { IFullscreenWidgetApi, IFullscreenWidgetEvents } from './interfaces';
import { PluginMessage, PluginType } from '../connection/constants';

function FullscreenWidget(connection: IConnection<IFullscreenWidgetEvents>) {
const base = createWidget<IFullscreenWidgetApi, IFullscreenWidgetEvents>(
Expand All @@ -22,7 +23,13 @@ export interface IFullscreenWidget
extends ReturnType<typeof FullscreenWidget> {}

export default function createFullscreenWidget(): Promise<IFullscreenWidget> {
return createConnection<IFullscreenWidgetEvents>().then(connection =>
FullscreenWidget(connection)
);
let widget: IFullscreenWidget;
return createConnection<IFullscreenWidgetEvents>()
.then(connection => {
widget = FullscreenWidget(connection);
connection.sendMessage(PluginMessage.Inited, {
plugin_type: PluginType.Fullscreen
});
})
.then(() => widget);
shwarcu marked this conversation as resolved.
Show resolved Hide resolved
}
18 changes: 14 additions & 4 deletions src/widgets/messagebox/messagebox-widget.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { createWidget } from '../shared/widget';
import { withAmplitude } from '../shared/amplitude';
import { withCustomerProfile } from '../shared/customer-profile';
import { withPrivateMode } from '../shared/private-mode';
import { withRichMessages } from '../shared/rich-messages';
import { IConnection, createConnection } from '../connection';
import {
IMessageBoxWidgetApi,
IMessageBoxWidgetEvents,
IRichMessage
} from './interfaces';
import { PluginType, PluginMessage } from '../connection/constants';

function MessageBoxWidget(connection: IConnection<IMessageBoxWidgetEvents>) {
const base = createWidget<IMessageBoxWidgetApi, IMessageBoxWidgetEvents>(
Expand All @@ -25,7 +27,9 @@ function MessageBoxWidget(connection: IConnection<IMessageBoxWidgetEvents>) {
}
);

const widget = withAmplitude(withRichMessages(withCustomerProfile(base)));
const widget = withAmplitude(
withRichMessages(withCustomerProfile(withPrivateMode(base)))
);

return widget;
}
Expand All @@ -34,7 +38,13 @@ export interface IMessageBoxWidget
extends ReturnType<typeof MessageBoxWidget> {}

export default function createMessageBoxWidget(): Promise<IMessageBoxWidget> {
return createConnection<IMessageBoxWidgetEvents>().then(connection =>
MessageBoxWidget(connection)
);
let widget: IMessageBoxWidget;
return createConnection<IMessageBoxWidgetEvents>().then(connection => {
widget = MessageBoxWidget(connection);
return connection
.sendMessage(PluginMessage.Inited, {
plugin_type: PluginType.MessageBox
})
.then(() => widget);
});
}
shwarcu marked this conversation as resolved.
Show resolved Hide resolved
35 changes: 35 additions & 0 deletions src/widgets/shared/private-mode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { KeyMap } from '../../utils/types';
import { WidgetMixin, Widget, AnyWidgetApi } from './widget';

export interface IPrivateMode {
shwarcu marked this conversation as resolved.
Show resolved Hide resolved
threads: KeyMap<boolean>;
source: 'chats';
}

export interface IPrivateModeApi {
getPrivateModeState(): IPrivateMode | null;
}

export interface IPrivateModeEvents {
private_mode: IPrivateMode;
}

export const withPrivateMode: WidgetMixin<
IPrivateModeApi,
IPrivateModeEvents
> = widget => {
let threads = null;

function onPrivateMode(privateMode: IPrivateMode) {
threads = { ...threads, ...privateMode.threads };
}

widget.on('private_mode', onPrivateMode);
shwarcu marked this conversation as resolved.
Show resolved Hide resolved

return {
...widget,
getPrivateModeState(): IPrivateMode | null {
return { source: 'chats', threads };
}
};
};