Skip to content

Commit

Permalink
feat(webchat): implement basic webchat (#126)
Browse files Browse the repository at this point in the history
* use latest client version

* ddd

* fix

* add socket.io

* cors

* very basic communication with server

* bump client version

* feat(server); nologo option

* doc

* put back old stuff

* implement events make render structure

* better setup

* test messages

* locale

* ui helpers

* improvement

* ui error handling

* element

* style and textbox

* storage

* client deserialize dates

* deserialize health

* message form

* postMessage

* dont post when empty

* convo details

* seperate debug ui

* save convo

* refact ui

* fix

* remove random lodash

* setup socket.io

* send better messages

* disconnect

* base package

* skin package

* yarn.lock

* move things to skin package

* emitter to base

* fix

* socket request

* some progress

* reorg

* functionning one way

* dirty but it works

* chore(base): implement base package

* remove unused files

* move rewire

* fixes

* remove ts-config-paths

* use yarn workspace script

* remove client from root references

* scroll to bottom on message

* some css

* refactor 1

* refact

* refact

* user events

* cleanup webchat

* rename

* cleanup 2

* dark theme

* lang

* socket package

* socket package ++

* manual connect

* socket package progress

* various fixes

* socket service

* remove socket and web channel

* user sockets schemas

* messages socket schema

* safety improvements

* fix

* cache sockets

* fix

* feat(chat): chat service (#135)

* chat service

* remove dead code

* fix

* refact socket service

* fix

* faster caching

* fix

* refact

* fix

* fix

* better ui

* ENABLE_EXPERIMENTAL_SOCKETS

* sandbox

* undo changes in table

* users.auth validate client exists

* fix keep channel name when only one convmap

* fixes

* fix

* typings for send

* STORAGE_ID
  • Loading branch information
samuelmasse committed Aug 19, 2021
1 parent 1c6e9f4 commit aed8705
Show file tree
Hide file tree
Showing 76 changed files with 1,737 additions and 343 deletions.
2 changes: 2 additions & 0 deletions packages/board/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
"devDependencies": {},
"dependencies": {
"@botpress/webchat": "0.0.1",
"@botpress/webchat-skin": "0.0.1",
"@botpress/messaging-client": "0.0.4",
"axios": "^0.21.1"
}
}
19 changes: 8 additions & 11 deletions packages/board/src/app.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import { BotpressWebchat } from '@botpress/webchat'
import { myFunction } from './script'

// eslint-disable-next-line no-console
console.log('This is the board ui')

void new BotpressWebchat().setup()

document.getElementById('my-div')!.innerText = 'This text was set by a script'

myFunction()
import { BoardLinker } from './linker'

new BoardLinker(
'http://localhost:3100',
document.getElementById('board-linker')!,
document.getElementById('webchat')!,
document.getElementById('board-watcher')!
)
7 changes: 6 additions & 1 deletion packages/board/src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<title>Messaging Board</title>

<link rel="stylesheet" href="https://cdn.simplecss.org/simple.min.css" />
<link rel="stylesheet" href="style.css" />
<script defer src="app.ts"></script>
</head>
<body>
Expand All @@ -22,7 +23,11 @@ <h1>Messaging Board</h1>
</header>

<main>
<p id="my-div"></p>
<p>
<section id="board-linker"></section>
<section id="board-watcher"></section>
<section id="webchat"></section>
</p>
</main>

<footer>
Expand Down
127 changes: 127 additions & 0 deletions packages/board/src/linker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import { MessagingClient } from '@botpress/messaging-client'
import { ConversationEvents, UserEvents, Webchat } from '@botpress/webchat'
import { text, element, WebchatRenderer } from '@botpress/webchat-skin'
import { BoardWatcher } from './watcher'

export class BoardLinker {
private inputClientId!: HTMLInputElement
private inputUserId!: HTMLInputElement
private inputConversationId!: HTMLInputElement

private webchat?: Webchat

constructor(
private url: string,
private parent: HTMLElement,
private webchatElement: HTMLElement,
private watcherElement: HTMLElement
) {
this.make()
this.listen()
void this.create()
}

private make() {
element('h3', this.parent, (title) => {
text('Messaging box', title)
})
element('details', this.parent, (details) => {
element('summary', details, (summary) => {
text('Link', summary)
})
element('form', details, (form) => {
form.autocomplete = 'off'

element('label', form, (label) => {
label.htmlFor = 'bp-clientId-input'
text('clientId', label)
})
element('br', form)
this.inputClientId = element('input', form, (input) => {
input.type = 'text'
input.name = 'bp-clientId-input'
})
element('br', form)
element('label', form, (label) => {
label.htmlFor = 'bp-userId-input'
text('userId', label)
})
element('br', form)
this.inputUserId = element('input', form, (input) => {
input.type = 'text'
input.name = 'bp-userId-input'
})
element('br', form)
element('label', form, (label) => {
label.htmlFor = 'bp-conversationId-input'
text('conversationId', label)
})
element('br', form)
this.inputConversationId = element('input', form, (input) => {
input.type = 'text'
input.name = 'bp-conversationId-input'
})
element('br', form)
element('button', form, (button) => {
text('Link', button)
})

form.onsubmit = () => {
void this.create()
return false
}
})
})
}

private listen() {}

private async create() {
this.webchat?.destroy()

let clientId = this.inputClientId.value
if (!clientId?.length) {
clientId = localStorage.getItem('bp-board-client')!
}
if (!clientId?.length) {
const client = new MessagingClient({ url: this.url })
const res = await client.syncs.sync({})
clientId = res.id
}

while (this.watcherElement.firstChild) {
this.watcherElement.removeChild(this.watcherElement.lastChild!)
}
while (this.webchatElement.firstChild) {
this.webchatElement.removeChild(this.webchatElement.lastChild!)
}

this.webchat = new Webchat(this.url, clientId)
new WebchatRenderer(this.webchatElement, this.webchat)
new BoardWatcher(this.watcherElement, this.webchat)

if (this.inputUserId.value.length) {
this.webchat.user.events.on(UserEvents.Choose, async (e) => {
e.choice = this.inputUserId.value
})
}
if (this.inputConversationId.value.length) {
this.webchat.conversation.events.on(ConversationEvents.Choose, async (e) => {
e.choice = this.inputConversationId.value
})
}

this.inputClientId.placeholder = clientId
this.webchat.user.events.on(UserEvents.Set, async (e) => {
localStorage.setItem('bp-board-client', clientId)
this.inputUserId.placeholder = e.value?.id || ''
this.inputUserId.value = ''
})
this.webchat.conversation.events.on(ConversationEvents.Set, async (e) => {
this.inputConversationId.placeholder = e.value?.id || ''
this.inputConversationId.value = ''
})

void this.webchat.setup()
}
}
4 changes: 0 additions & 4 deletions packages/board/src/script.ts

This file was deleted.

29 changes: 29 additions & 0 deletions packages/board/src/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
.bp-send-button {
margin-left: 5px;
}

.bp-messages-section {
overflow: auto;
height: 400px;
margin-top: 24px;
margin-bottom: 24px;
}

.bp-messages-section table {
margin-top: 0;
margin-bottom: 0;
}

/* Copied from simple css source. Forces dark theme colors */
:root {
--bg: #212121;
--accent-bg: #2b2b2b;
--text: #dcdcdc;
--text-light: #ababab;
--border: #666;
--accent: #ffb300;
--accent-light: #ffecb3;
--code: #f06292;
--preformatted: #ccc;
--disabled: #111;
}
56 changes: 56 additions & 0 deletions packages/board/src/watcher.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { Webchat, ConversationEvents, ConversationSetEvent } from '@botpress/webchat'
import { text, element } from '@botpress/webchat-skin'
import { UserEvents, UserSetEvent } from '@botpress/webchat/src/user/events'

export class BoardWatcher {
private textUserId!: Text
private textConversationId!: Text

constructor(private parent: HTMLElement, private webchat: Webchat) {
this.make()
this.listen()
}

private make() {
element('details', this.parent, (details) => {
details.open = true

element('summary', details, (summary) => {
text('Variables', summary)
})
element('ul', details, (ul) => {
element('li', ul, (li) => {
element('code', li, (code) => {
text('clientId ', code)
})
text(this.webchat.socket.clientId, li)
})
element('li', ul, (li) => {
element('code', li, (code) => {
text('userId ', code)
})
this.textUserId = text('', li)
})
element('li', ul, (li) => {
element('code', li, (code) => {
text('conversationId ', code)
})
this.textConversationId = text('', li)
})
})
})
}

private listen() {
this.webchat.user.events.on(UserEvents.Set, this.handleUserSet.bind(this))
this.webchat.conversation.events.on(ConversationEvents.Set, this.handleConversationSet.bind(this))
}

private async handleUserSet(e: UserSetEvent) {
this.textUserId.textContent = e.value?.id || ''
}

private async handleConversationSet(e: ConversationSetEvent) {
this.textConversationId.textContent = e.value?.id || ''
}
}
6 changes: 6 additions & 0 deletions packages/board/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
"references": [
{
"path": "../chat"
},
{
"path": "../skin"
},
{
"path": "../client"
}
],

Expand Down
3 changes: 1 addition & 2 deletions packages/chat/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
],
"devDependencies": {},
"dependencies": {
"@botpress/messaging-client": "0.0.1",
"axios": "^0.21.1"
"@botpress/messaging-socket": "0.0.1"
}
}
3 changes: 3 additions & 0 deletions packages/chat/src/base/system.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export class WebchatSystem {
async setup() {}
}
41 changes: 41 additions & 0 deletions packages/chat/src/chat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { MessagingSocket } from '@botpress/messaging-socket'
import { WebchatConversation } from './conversation/system'
import { WebchatLang } from './lang/system'
import { WebchateLocale } from './locale/system'
import { WebchatMessages } from './messages/system'
import { WebchatStorage } from './storage/system'
import { WebchatUser } from './user/system'

export class Webchat {
public readonly storage: WebchatStorage
public readonly locale: WebchateLocale
public readonly lang: WebchatLang
public readonly socket: MessagingSocket
public readonly user: WebchatUser
public readonly conversation: WebchatConversation
public readonly messages: WebchatMessages

constructor(url: string, clientId: string) {
this.storage = new WebchatStorage()
this.locale = new WebchateLocale()
this.lang = new WebchatLang(this.locale)
this.socket = new MessagingSocket({ url, clientId, manualConnect: true })
this.user = new WebchatUser(this.storage, this.socket)
this.conversation = new WebchatConversation(this.storage, this.socket)
this.messages = new WebchatMessages(this.socket, this.conversation)
}

public async setup() {
await this.storage.setup()
await this.locale.setup()
await this.lang.setup()
await this.socket.com.connect()
await this.user.setup()
await this.conversation.setup()
await this.messages.setup()
}

public async destroy() {
this.socket.com.disconnect()
}
}
22 changes: 22 additions & 0 deletions packages/chat/src/conversation/events.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Conversation, Emitter, uuid } from '@botpress/messaging-base'

export enum ConversationEvents {
Choose = 'choose',
Set = 'set'
}

export interface ConversationSetEvent {
previous: Conversation | undefined
value: Conversation | undefined
}

export interface ConversationChooseEvent {
choice: uuid | undefined
}

export class ConversationEmitter extends Emitter<{
[ConversationEvents.Set]: ConversationSetEvent
[ConversationEvents.Choose]: ConversationChooseEvent
}> {}

export type ConversationWatcher = Omit<ConversationEmitter, 'emit'>
Loading

0 comments on commit aed8705

Please sign in to comment.