Skip to content

Commit

Permalink
feat(webchat): port webchat injection (#239)
Browse files Browse the repository at this point in the history
* user token start

* tests

* refactor auth

* caching

* api

* fix test

* comment

* expiry

* batching

* remove user token implementation

* Revert "remove user token implementation"

This reverts commit 1e1dd78.

* refact auth

* remove file

* fix

* refact client auth function

* refact function

* refact

* fix

* remove file

* end turn route

* responses

* return message also

* use cache for collectors

* hintRespondingTo

* incomingId

* bump messaging client

* turn id

* collect flag

* fix ui

* backend validate user token is correct

* schema

* socket auth

* update testing ui

* bring changes

* remove user token api

* remove user token api

* revert

* remove correct user token api

* bring changes

* extract constant

* verifyToken

* fix tests

* users.get

* socket prevent lost requests

* conversations socket

* some refact and changes

* refact schema validation

* refact user rights check

* remove nonsense

* socket refact

* move socket code at of api start

* socket root class

* remove private

* refact schema

* fix

* fix

* dont server client

* move api routes to functions

* different collect route

* better api route names

* refact schema validation

* refact messages

* refact conversations

* refact users

* remove ui from changes

* update ui

* custom timeout

* fix

* better socket

* better socket

* bring changes

* fix

* fix

* tests start

* fix

* more tests

* tests

* pr comments

* fix

* fix

* comments

* fixes and tests

* adjust api.rest

* better tests

* fix delete message

* webchat -> chat for test packages

* init package

* ctrl+c ctrl+v

* fix prettier

* fix decorators

* enable jsx

* add dep to components package

* fix deps

* fix strict

* comment out some code to compile

* .d.ts -> .ts

* dont use components package for now

* fix

* run in board

* don't import css yet

* show something

* stop ui crash

* display something

* remove test message

* todos

* text communication

* fix styling

* fix receive own message

* load creds

* fix switching conversation

* fix create conversation

* little fix

* fix typing indicators

* fixes

* remove css imports

* fix css

* fullscreen prop

* comment old stuff

* fullscreen

* fixes

* fix merge

* remove tsconfig change

* remove dep on components package

* fix compile errors

* fix merge

* fix

* inject package

* fix

* parcel v2

* Revert "parcel v2"

This reverts commit 1c273c1.

* pr comments

* revert some changes

* fix

* remove console.log

* fix config

* fix

* fix

* url -> messagingUrl

* fix

* fix

* v0.0.2
  • Loading branch information
samuelmasse authored Nov 12, 2021
1 parent 057a71a commit 1edb476
Show file tree
Hide file tree
Showing 7 changed files with 269 additions and 0 deletions.
19 changes: 19 additions & 0 deletions packages/inject/example.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="utf-8" />
</head>
<body>
<h1>Example website</h1>
<p>This website integrates the botpress webchat!</p>
</body>

<script src="http://localhost:8080/inject.js"></script>
<script>
window.botpressWebChat.init({
hostUrl: 'http://localhost:8080',
messagingUrl: 'http://localhost:3100',
clientId: '8b6b25ae-e47d-455e-8057-356dae07fff2'
})
</script>
</html>
20 changes: 20 additions & 0 deletions packages/inject/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "@botpress/webchat-inject",
"version": "0.0.2",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"source": "src/index.tsx",
"license": "AGPL-3.0",
"scripts": {
"build": "yarn --silent && parcel build src/index.html src/inject.js",
"watch": "yarn --silent && parcel watch src/index.html src/inject.js",
"dev": "yarn --silent && parcel src/index.html src/inject.js"
},
"files": [
"dist"
],
"dependencies": {
"@botpress/webchat": "0.0.1"
},
"devDependencies": {}
}
16 changes: 16 additions & 0 deletions packages/inject/src/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="utf-8" />

<link rel="stylesheet" href="../../components/.storybook/botpress-default.css" />
<link rel="stylesheet" href="../../../node_modules/@blueprintjs/core/lib/css/blueprint.css" />
<link rel="stylesheet" href="../../components/src/renderer/Carousel/css/slick-theme.css" />
<link rel="stylesheet" href="../../components/src/renderer/Carousel/css/slick.css" />

<script defer src="index.tsx"></script>
</head>
<body>
<div id="app"></div>
</body>
</html>
6 changes: 6 additions & 0 deletions packages/inject/src/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import 'regenerator-runtime/runtime'
import { ExposedWebChat } from '@botpress/webchat'
import React from 'react'
import ReactDOM from 'react-dom'

ReactDOM.render(<ExposedWebChat fullscreen={false} />, document.getElementById('app'))
59 changes: 59 additions & 0 deletions packages/inject/src/inject.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
.bp-widget-web {
border: none;
display: block;
position: fixed;
visibility: none;
z-index: 20;
max-height: 100vh;
max-width: 100vw;
transition: none;
background: none transparent;
opacity: 1;
font-size: 16px;
letter-spacing: 0;
-webkit-font-smoothing: antialiased;
padding: 0;
}

.bp-widget-widget {
top: auto;
left: auto;
bottom: 24px;
right: 36px;
width: 76px !important;
height: 76px !important;
}

.bp-widget-hidden {
display: none;
}

.bp-widget-convo {
top: auto;
left: auto;
bottom: 24px;
right: 36px;
width: 420px !important;
min-height: 382px !important;
max-height: 500px !important;
}

.bp-widget-side {
top: 0px;
left: auto;
bottom: 0px;
right: 0px;
width: 480px;
height: 100% !important;
}

.bp-widget-side.emulator {
height: calc(100% - 78px) !important;
top: 50px;
}

@media only screen and (max-device-width: 768px) {
.bp-widget-side {
width: 100%;
}
}
123 changes: 123 additions & 0 deletions packages/inject/src/inject.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
require('./inject.css')

// full backward compatibility
const DEFAULT_CHAT_ID = 'bp-web-widget'
const DEFAULT_IFRAME_ID = 'bp-widget'
const DEFAULT_IFRAME_CLASS = 'bp-widget-web'

function _getContainerId(chatId) {
return chatId ? chatId + '-container' : DEFAULT_CHAT_ID
}

function _getIframeId(chatId) {
return chatId || DEFAULT_IFRAME_ID
}

function _injectDOMElement(tagName, selector, options) {
const element = document.createElement(tagName)
if (options) {
Object.keys(options).forEach(function (key) {
element[key] = options[key]
})
}
document.querySelector(selector).appendChild(element)
return element
}

function _generateIFrameHTML(host, config) {
const options = encodeURIComponent(JSON.stringify({ config: config }))
const title = config.botConvoDescription || config.botName || config.botId
const iframeSrc = host + '/index.html?options=' + options
const iframeId = _getIframeId(config.chatId)
return (
'<iframe id="' +
iframeId +
'" title="' +
encodeURIComponent(title) +
'" frameborder="0" src="' +
iframeSrc +
'" class="' +
DEFAULT_IFRAME_CLASS +
'"/>'
)
}

const chatRefs = {}

// provides proper chat reference
function _getChatRef(chatId) {
chatId = chatId || DEFAULT_CHAT_ID
const fakeChatRef = {
postMessage: function () {
console.warn(
'No webchat with id ' + chatId + ' has not been initialized, \n please use window.botpressWebChat.init first.'
)
}
}

return chatRefs[chatId] || fakeChatRef
}

function configure(payload, chatId) {
const chatWindow = _getChatRef(chatId)
chatWindow.postMessage({ action: 'configure', payload: payload }, '*')
}
function sendEvent(payload, chatId) {
const chatWindow = _getChatRef(chatId)
chatWindow.postMessage({ action: 'event', payload: payload }, '*')
}
function sendPayload(payload, chatId) {
const chatWindow = _getChatRef(chatId)
chatWindow.postMessage({ action: 'sendPayload', payload: payload }, '*')
}
function mergeConfig(payload, chatId) {
const chatWindow = _getChatRef(chatId)
chatWindow.postMessage({ action: 'mergeConfig', payload: payload }, '*')
}

/**
*
* @param {object} config Configuration object you want to apply to your webchat instance
* @param {string} targetSelector css selector under which you want your webchat to be rendered
*/
function init(config, targetSelector) {
targetSelector = targetSelector || 'body'
const chatId = config.chatId || DEFAULT_CHAT_ID
const host = config.hostUrl || window.ROOT_PATH || ''

const cssHref = host + '/inject.css'
_injectDOMElement('link', 'head', { rel: 'stylesheet', href: cssHref })

const iframeHTML = _generateIFrameHTML(host, config)

const containerId = _getContainerId(config.chatId)
const iframeId = _getIframeId(config.chatId)
_injectDOMElement('div', targetSelector, { id: containerId, innerHTML: iframeHTML })

const iframeRef = document.querySelector('#' + containerId + ' #' + iframeId).contentWindow
chatRefs[chatId] = iframeRef
}

window.botpressWebChat = {
init: init,
configure: configure,
sendEvent: sendEvent,
mergeConfig: mergeConfig,
sendPayload: sendPayload
}

window.addEventListener('message', function (payload) {
const data = payload.data
if (!data || !data.type) {
return
}

const iframeSelector = '#' + _getIframeId(data.chatId)
if (data.type === 'setClass') {
document.querySelector(iframeSelector).setAttribute('class', data.value)
} else if (data.type === 'setWidth') {
const width = typeof data.value === 'number' ? data.value + 'px' : data.value

document.querySelector(iframeSelector).style.width = width
}
})
26 changes: 26 additions & 0 deletions packages/inject/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
// Manage references here
"references": [
{
"path": "../webchat"
}
],

// Defaults (don't change this)
"extends": "../../tsconfig.packages.json",
"compilerOptions": {
"rootDir": "src",
"outDir": "dist",
"tsBuildInfoFile": "dist/.tsbuildinfo",

// Specific settings for npm package
"target": "es6",
"declaration": true,
"sourceMap": false,

// We use react
"jsx": "react"
},
"include": ["src", "src/**/*.json"],
"exclude": ["dist", "node_modules"]
}

0 comments on commit 1edb476

Please sign in to comment.