@inploi/plugin-chatbot 2.0.0 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cdn/index.js +56 -0
- package/{public → cdn}/mockServiceWorker.js +4 -9
- package/package.json +25 -5
- package/.env +0 -3
- package/.env.example +0 -3
- package/.eslintrc.cjs +0 -10
- package/CHANGELOG.md +0 -85
- package/bunfig.toml +0 -2
- package/happydom.ts +0 -10
- package/index.html +0 -28
- package/postcss.config.cjs +0 -7
- package/src/chatbot.api.ts +0 -46
- package/src/chatbot.constants.ts +0 -9
- package/src/chatbot.css +0 -107
- package/src/chatbot.dom.ts +0 -17
- package/src/chatbot.idb.ts +0 -17
- package/src/chatbot.state.ts +0 -89
- package/src/chatbot.ts +0 -54
- package/src/chatbot.utils.ts +0 -50
- package/src/index.cdn.ts +0 -12
- package/src/index.dev.ts +0 -36
- package/src/index.ts +0 -1
- package/src/interpreter/interpreter.test.ts +0 -69
- package/src/interpreter/interpreter.ts +0 -241
- package/src/mocks/browser.ts +0 -5
- package/src/mocks/example.flows.ts +0 -763
- package/src/mocks/handlers.ts +0 -28
- package/src/ui/chat-bubble.tsx +0 -52
- package/src/ui/chat-input/chat-input.boolean.tsx +0 -62
- package/src/ui/chat-input/chat-input.file.tsx +0 -213
- package/src/ui/chat-input/chat-input.multiple-choice.tsx +0 -117
- package/src/ui/chat-input/chat-input.text.tsx +0 -111
- package/src/ui/chat-input/chat-input.tsx +0 -81
- package/src/ui/chatbot-header.tsx +0 -98
- package/src/ui/chatbot.tsx +0 -105
- package/src/ui/input-error.tsx +0 -33
- package/src/ui/job-application-content.tsx +0 -145
- package/src/ui/job-application-messages.tsx +0 -64
- package/src/ui/loading-indicator.tsx +0 -37
- package/src/ui/send-button.tsx +0 -27
- package/src/ui/transition.tsx +0 -1
- package/src/ui/typing-indicator.tsx +0 -12
- package/src/ui/useChatService.ts +0 -75
- package/src/ui/useFocus.ts +0 -10
- package/src/vite-env.d.ts +0 -1
- package/tailwind.config.ts +0 -119
- package/tsconfig.json +0 -33
- package/tsconfig.node.json +0 -10
- package/types.d.ts +0 -2
- package/vite.config.ts +0 -18
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
/* tslint:disable */
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* Mock Service Worker (2.0.
|
|
5
|
+
* Mock Service Worker (2.0.10).
|
|
6
6
|
* @see https://github.com/mswjs/msw
|
|
7
7
|
* - Please do NOT modify this file.
|
|
8
8
|
* - Please do NOT serve this file on production.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
const INTEGRITY_CHECKSUM = '
|
|
11
|
+
const INTEGRITY_CHECKSUM = 'c5f7f8e188b673ea4e677df7ea3c5a39'
|
|
12
12
|
const IS_MOCKED_RESPONSE = Symbol('isMockedResponse')
|
|
13
13
|
const activeClientIds = new Set()
|
|
14
14
|
|
|
@@ -121,11 +121,6 @@ async function handleRequest(event, requestId) {
|
|
|
121
121
|
if (client && activeClientIds.has(client.id)) {
|
|
122
122
|
;(async function () {
|
|
123
123
|
const responseClone = response.clone()
|
|
124
|
-
// When performing original requests, response body will
|
|
125
|
-
// always be a ReadableStream, even for 204 responses.
|
|
126
|
-
// But when creating a new Response instance on the client,
|
|
127
|
-
// the body for a 204 response must be null.
|
|
128
|
-
const responseBody = response.status === 204 ? null : responseClone.body
|
|
129
124
|
|
|
130
125
|
sendToClient(
|
|
131
126
|
client,
|
|
@@ -137,11 +132,11 @@ async function handleRequest(event, requestId) {
|
|
|
137
132
|
type: responseClone.type,
|
|
138
133
|
status: responseClone.status,
|
|
139
134
|
statusText: responseClone.statusText,
|
|
140
|
-
body:
|
|
135
|
+
body: responseClone.body,
|
|
141
136
|
headers: Object.fromEntries(responseClone.headers.entries()),
|
|
142
137
|
},
|
|
143
138
|
},
|
|
144
|
-
[
|
|
139
|
+
[responseClone.body],
|
|
145
140
|
)
|
|
146
141
|
})()
|
|
147
142
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inploi/plugin-chatbot",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"type": "module",
|
|
5
|
+
"files": [
|
|
6
|
+
"/dist",
|
|
7
|
+
"/cdn"
|
|
8
|
+
],
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"require": "./dist/index.js",
|
|
12
|
+
"import": "./dist/index.mjs",
|
|
13
|
+
"types": "./dist/index.d.ts"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
5
16
|
"dependencies": {
|
|
6
17
|
"@hookform/resolvers": "^3.3.2",
|
|
7
18
|
"@preact/signals": "^1.2.2",
|
|
@@ -11,6 +22,7 @@
|
|
|
11
22
|
"@radix-ui/react-slot": "^1.0.2",
|
|
12
23
|
"class-variance-authority": "^0.7.0",
|
|
13
24
|
"clsx": "^2.0.0",
|
|
25
|
+
"culori": "^3.3.0",
|
|
14
26
|
"framer-motion": "^10.16.5",
|
|
15
27
|
"idb-keyval": "^6.2.1",
|
|
16
28
|
"preact": "^10.16.0",
|
|
@@ -30,14 +42,19 @@
|
|
|
30
42
|
},
|
|
31
43
|
"devDependencies": {
|
|
32
44
|
"@happy-dom/global-registrator": "^12.6.0",
|
|
45
|
+
"@playwright/test": "^1.40.1",
|
|
33
46
|
"@preact/preset-vite": "^2.5.0",
|
|
34
47
|
"@total-typescript/ts-reset": "^0.5.1",
|
|
48
|
+
"@types/culori": "^2.0.4",
|
|
49
|
+
"@types/node": "^20.10.0",
|
|
35
50
|
"@types/react-transition-group": "^4.4.9",
|
|
36
51
|
"autoprefixer": "^10.4.16",
|
|
52
|
+
"dotenv": "^16.3.1",
|
|
37
53
|
"eslint": "^7.32.0",
|
|
38
54
|
"eslint-plugin-react-hooks": "^4.6.0",
|
|
39
55
|
"happy-dom": "^12.6.0",
|
|
40
|
-
"msw": "^2.0.
|
|
56
|
+
"msw": "^2.0.10",
|
|
57
|
+
"playwright-msw": "^3.0.0",
|
|
41
58
|
"postcss": "^8.4.31",
|
|
42
59
|
"postcss-nesting": "^12.0.1",
|
|
43
60
|
"rollup-plugin-visualizer": "^5.9.2",
|
|
@@ -46,9 +63,9 @@
|
|
|
46
63
|
"typescript": "^5.3.2",
|
|
47
64
|
"vite": "^4.4.5",
|
|
48
65
|
"vite-tsconfig-paths": "^4.2.1",
|
|
49
|
-
"@inploi/sdk": "1.5.
|
|
50
|
-
"
|
|
51
|
-
"
|
|
66
|
+
"@inploi/sdk": "1.5.1",
|
|
67
|
+
"tsconfig": "0.1.0",
|
|
68
|
+
"eslint-config-custom": "0.1.0"
|
|
52
69
|
},
|
|
53
70
|
"msw": {
|
|
54
71
|
"workerDirectory": "public"
|
|
@@ -58,6 +75,9 @@
|
|
|
58
75
|
"build": "tsc && vite build",
|
|
59
76
|
"setup-local": "cp -n .env.example .env || true",
|
|
60
77
|
"check": "eslint src --fix --max-warnings 0 && tsc",
|
|
78
|
+
"test:unit": "bun test",
|
|
79
|
+
"test:int": "playwright test",
|
|
80
|
+
"test:ui": "playwright test --ui",
|
|
61
81
|
"preview": "vite preview"
|
|
62
82
|
}
|
|
63
83
|
}
|
package/.env
DELETED
package/.env.example
DELETED
package/.eslintrc.cjs
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/*eslint-env node */
|
|
2
|
-
/** @type {import('eslint').Linter.Config} */
|
|
3
|
-
module.exports = {
|
|
4
|
-
root: true,
|
|
5
|
-
// This tells ESLint to load the config from the package `eslint-config-custom`
|
|
6
|
-
extends: ['custom', 'plugin:react-hooks/recommended'],
|
|
7
|
-
plugins: ['react-hooks'],
|
|
8
|
-
env: { browser: true, es2020: true },
|
|
9
|
-
parserOptions: { project: ['./tsconfig.json'], tsconfigRootDir: __dirname },
|
|
10
|
-
};
|
package/CHANGELOG.md
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
# @inploi/plugin-chatbot
|
|
2
|
-
|
|
3
|
-
## 2.0.0
|
|
4
|
-
|
|
5
|
-
### Patch Changes
|
|
6
|
-
|
|
7
|
-
- 2975c09: Replace `zustand` with `idb-keyval` and `@preact/signals` to better utilise indexeddb and reduce bundle size
|
|
8
|
-
- cc46781: Track started applications via the new `analytics` service exposed by sdk
|
|
9
|
-
- Updated dependencies [d8dc36f]
|
|
10
|
-
- Updated dependencies [d8dc36f]
|
|
11
|
-
- @inploi/sdk@1.5.0
|
|
12
|
-
- @inploi/core@1.5.6
|
|
13
|
-
|
|
14
|
-
## 1.0.7
|
|
15
|
-
|
|
16
|
-
### Patch Changes
|
|
17
|
-
|
|
18
|
-
- Updated dependencies
|
|
19
|
-
- @inploi/core@1.5.5
|
|
20
|
-
- @inploi/sdk@1.4.6
|
|
21
|
-
|
|
22
|
-
## 1.0.6
|
|
23
|
-
|
|
24
|
-
### Patch Changes
|
|
25
|
-
|
|
26
|
-
- Updated dependencies [3cbdf6b]
|
|
27
|
-
- @inploi/core@1.5.4
|
|
28
|
-
- @inploi/sdk@1.4.5
|
|
29
|
-
|
|
30
|
-
## 1.0.5
|
|
31
|
-
|
|
32
|
-
### Patch Changes
|
|
33
|
-
|
|
34
|
-
- Implement map of node types
|
|
35
|
-
- Updated dependencies
|
|
36
|
-
- @inploi/core@1.5.3
|
|
37
|
-
- @inploi/sdk@1.4.4
|
|
38
|
-
|
|
39
|
-
## 1.0.4
|
|
40
|
-
|
|
41
|
-
### Patch Changes
|
|
42
|
-
|
|
43
|
-
- Updated dependencies
|
|
44
|
-
- @inploi/core@1.5.2
|
|
45
|
-
- @inploi/sdk@1.4.3
|
|
46
|
-
|
|
47
|
-
## 1.0.3
|
|
48
|
-
|
|
49
|
-
### Patch Changes
|
|
50
|
-
|
|
51
|
-
- Updated dependencies
|
|
52
|
-
- @inploi/core@1.5.1
|
|
53
|
-
- @inploi/sdk@1.4.2
|
|
54
|
-
|
|
55
|
-
## 1.0.2
|
|
56
|
-
|
|
57
|
-
### Patch Changes
|
|
58
|
-
|
|
59
|
-
- Updated dependencies [ba05115]
|
|
60
|
-
- @inploi/core@1.5.0
|
|
61
|
-
- @inploi/sdk@1.4.1
|
|
62
|
-
|
|
63
|
-
## 1.0.1
|
|
64
|
-
|
|
65
|
-
### Patch Changes
|
|
66
|
-
|
|
67
|
-
- e9c1677: (Following 1.0) rewrite exports to new plugin format
|
|
68
|
-
- Updated dependencies [d0f1d33]
|
|
69
|
-
- @inploi/sdk@1.0.1
|
|
70
|
-
|
|
71
|
-
## 1.0.0
|
|
72
|
-
|
|
73
|
-
### Patch Changes
|
|
74
|
-
|
|
75
|
-
- d8a904e: Split SDK plugins into their own packages
|
|
76
|
-
- Updated dependencies [5a34b5a]
|
|
77
|
-
- Updated dependencies [5d1e92b]
|
|
78
|
-
- Updated dependencies [5d1e92b]
|
|
79
|
-
- Updated dependencies [df4f06d]
|
|
80
|
-
- Updated dependencies [d5caf7e]
|
|
81
|
-
- Updated dependencies [a582965]
|
|
82
|
-
- Updated dependencies [d8a904e]
|
|
83
|
-
- Updated dependencies [553e630]
|
|
84
|
-
- @inploi/core@1.4.0
|
|
85
|
-
- @inploi/sdk@1.0.0
|
package/bunfig.toml
DELETED
package/happydom.ts
DELETED
package/index.html
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8" />
|
|
5
|
-
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
6
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
-
<title>Vite + Preact + TS</title>
|
|
8
|
-
</head>
|
|
9
|
-
<body
|
|
10
|
-
style="
|
|
11
|
-
font-family: 'Courier New', Courier, monospace;
|
|
12
|
-
height: 100vh;
|
|
13
|
-
display: flex;
|
|
14
|
-
align-items: center;
|
|
15
|
-
justify-content: center;
|
|
16
|
-
"
|
|
17
|
-
>
|
|
18
|
-
<div>
|
|
19
|
-
<h1 style="font-size: 2rem; letter-spacing: -0.02em; text-align: center">Super legit careers hub</h1>
|
|
20
|
-
<p>Welcome, start applying by clicking on one of the buttons below</p>
|
|
21
|
-
|
|
22
|
-
<button onclick="chatbot.startApplication({ jobId: '1' })">Apply for Wagamama job</button>
|
|
23
|
-
<button onclick="chatbot.startApplication({ jobId: '2' })">Apply for job Test flow</button>
|
|
24
|
-
</div>
|
|
25
|
-
|
|
26
|
-
<script type="module" src="/src/index.dev.ts"></script>
|
|
27
|
-
</body>
|
|
28
|
-
</html>
|
package/postcss.config.cjs
DELETED
package/src/chatbot.api.ts
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { FlowNode } from '@inploi/core/flows';
|
|
2
|
-
import { ApiClient } from '@inploi/sdk';
|
|
3
|
-
import { any, array, coerce, number, object, optional, parse, string } from 'valibot';
|
|
4
|
-
|
|
5
|
-
export type JobApplication = {
|
|
6
|
-
job: {
|
|
7
|
-
id: string; // internal inploi job id
|
|
8
|
-
title: string; //job title
|
|
9
|
-
};
|
|
10
|
-
company: {
|
|
11
|
-
name: string; // company name
|
|
12
|
-
logo?: string; // company logo
|
|
13
|
-
};
|
|
14
|
-
flow: {
|
|
15
|
-
id: string; // flow id
|
|
16
|
-
version: number; // hardcode the version as 0 until we have versioning
|
|
17
|
-
nodes: FlowNode[]; // new jsonb flow nodes, no need for the legacy parser to run
|
|
18
|
-
};
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
const ApplicationSchema = object({
|
|
22
|
-
job: object({
|
|
23
|
-
id: coerce(string(), String),
|
|
24
|
-
title: string(),
|
|
25
|
-
}),
|
|
26
|
-
company: object({
|
|
27
|
-
name: string(),
|
|
28
|
-
logo: optional(string()),
|
|
29
|
-
}),
|
|
30
|
-
flow: object({
|
|
31
|
-
id: coerce(string(), String),
|
|
32
|
-
nodes: array(any()),
|
|
33
|
-
version: number(),
|
|
34
|
-
}),
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
export async function getApplicationData({
|
|
38
|
-
jobId,
|
|
39
|
-
apiClient,
|
|
40
|
-
}: {
|
|
41
|
-
jobId: string;
|
|
42
|
-
apiClient: ApiClient;
|
|
43
|
-
}): Promise<JobApplication> {
|
|
44
|
-
const rawData = await apiClient.fetch(`/flow/job/${jobId}`);
|
|
45
|
-
return parse(ApplicationSchema, rawData);
|
|
46
|
-
}
|
package/src/chatbot.constants.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
export const CHATBOT_ELEMENT_ID = 'isdk';
|
|
2
|
-
|
|
3
|
-
export const HEADER_HEIGHT = 44;
|
|
4
|
-
|
|
5
|
-
export const ERROR_MESSAGES = {
|
|
6
|
-
not_in_local_storage: 'Application not found in local storage',
|
|
7
|
-
invalid_end_node: 'Unexpected node type to finish flow',
|
|
8
|
-
no_submissions: 'Application ended without any fields submitted',
|
|
9
|
-
};
|
package/src/chatbot.css
DELETED
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
#isdk {
|
|
2
|
-
font-size: 16px;
|
|
3
|
-
font-family: sans-serif;
|
|
4
|
-
|
|
5
|
-
/* Lowest colour */
|
|
6
|
-
--i-lowest: 0 0% 100%;
|
|
7
|
-
|
|
8
|
-
/* Neutral colors */
|
|
9
|
-
--i-n-1: 206 30% 98.8%;
|
|
10
|
-
--i-n-2: 210 16.7% 97.6%;
|
|
11
|
-
--i-n-3: 209 13.3% 95.3%;
|
|
12
|
-
--i-n-4: 209 12.2% 93.2%;
|
|
13
|
-
--i-n-5: 208 11.7% 91.1%;
|
|
14
|
-
--i-n-6: 208 11.3% 88.9%;
|
|
15
|
-
--i-n-7: 207 11.1% 85.9%;
|
|
16
|
-
--i-n-8: 205 10.7% 78%;
|
|
17
|
-
--i-n-9: 206 6% 56.1%;
|
|
18
|
-
--i-n-10: 206 5.8% 52.3%;
|
|
19
|
-
--i-n-11: 206 6% 43.5%;
|
|
20
|
-
--i-n-12: 206 24% 9%;
|
|
21
|
-
|
|
22
|
-
/* Accent colors */
|
|
23
|
-
--i-a-1: 240 33% 99%;
|
|
24
|
-
--i-a-2: 225 100% 98%;
|
|
25
|
-
--i-a-3: 222 89% 96%;
|
|
26
|
-
--i-a-4: 224 100% 94%;
|
|
27
|
-
--i-a-5: 224 100% 91%;
|
|
28
|
-
--i-a-6: 225 100% 88%;
|
|
29
|
-
--i-a-7: 226 87% 82%;
|
|
30
|
-
--i-a-8: 226 75% 75%;
|
|
31
|
-
--i-a-9: 226 70% 55%;
|
|
32
|
-
--i-a-10: 226 65% 52%;
|
|
33
|
-
--i-a-11: 226 56% 50%;
|
|
34
|
-
--i-a-12: 226 50% 24%;
|
|
35
|
-
|
|
36
|
-
/** Error colours */
|
|
37
|
-
--i-e-1: 340 100% 99%;
|
|
38
|
-
--i-e-2: 353 100% 98%;
|
|
39
|
-
--i-e-3: 351 91% 96%;
|
|
40
|
-
--i-e-4: 351 100% 93%;
|
|
41
|
-
--i-e-5: 350 100% 90%;
|
|
42
|
-
--i-e-6: 351 80% 86%;
|
|
43
|
-
--i-e-7: 349 68% 81%;
|
|
44
|
-
--i-e-8: 348 61% 74%;
|
|
45
|
-
--i-e-9: 348 75% 59%;
|
|
46
|
-
--i-e-10: 347 70% 55%;
|
|
47
|
-
--i-e-11: 345 70% 47%;
|
|
48
|
-
--i-e-12: 344 63% 24%;
|
|
49
|
-
|
|
50
|
-
@tailwind base;
|
|
51
|
-
@tailwind components;
|
|
52
|
-
@tailwind utilities;
|
|
53
|
-
@tailwind variants;
|
|
54
|
-
|
|
55
|
-
@layer base {
|
|
56
|
-
--tw-content: '';
|
|
57
|
-
font-family:
|
|
58
|
-
system-ui,
|
|
59
|
-
-apple-system,
|
|
60
|
-
BlinkMacSystemFont,
|
|
61
|
-
Segoe UI,
|
|
62
|
-
Roboto,
|
|
63
|
-
Oxygen,
|
|
64
|
-
Ubuntu,
|
|
65
|
-
Cantarell,
|
|
66
|
-
Open Sans,
|
|
67
|
-
Helvetica Neue,
|
|
68
|
-
sans-serif;
|
|
69
|
-
|
|
70
|
-
* {
|
|
71
|
-
box-sizing: border-box;
|
|
72
|
-
border-style: solid;
|
|
73
|
-
border-width: 0;
|
|
74
|
-
-webkit-tap-highlight-color: transparent;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
::before,
|
|
78
|
-
::after {
|
|
79
|
-
box-sizing: border-box;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
:is(ul, ol) {
|
|
83
|
-
list-style: none;
|
|
84
|
-
padding: 0;
|
|
85
|
-
margin: 0;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
:is(p) {
|
|
89
|
-
margin: 0;
|
|
90
|
-
padding: 0;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
:is(li) {
|
|
94
|
-
margin: 0;
|
|
95
|
-
padding: 0;
|
|
96
|
-
list-style: none;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
:is(button) {
|
|
100
|
-
margin: 0;
|
|
101
|
-
padding: 0;
|
|
102
|
-
border: unset;
|
|
103
|
-
background: unset;
|
|
104
|
-
text-align: unset;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}
|
package/src/chatbot.dom.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { CHATBOT_ELEMENT_ID } from './chatbot.constants';
|
|
2
|
-
|
|
3
|
-
export const createChatbotDomManager = () => {
|
|
4
|
-
let chatbotElement: HTMLDivElement | null = null;
|
|
5
|
-
return {
|
|
6
|
-
getOrCreateChatbotElement: () => {
|
|
7
|
-
if (chatbotElement) return chatbotElement;
|
|
8
|
-
|
|
9
|
-
const newElement = document.createElement('div');
|
|
10
|
-
document.body.appendChild(newElement);
|
|
11
|
-
newElement.id = CHATBOT_ELEMENT_ID;
|
|
12
|
-
chatbotElement = newElement;
|
|
13
|
-
return newElement;
|
|
14
|
-
},
|
|
15
|
-
};
|
|
16
|
-
};
|
|
17
|
-
export type ChatbotDomManager = ReturnType<typeof createChatbotDomManager>;
|
package/src/chatbot.idb.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { createStore, get, set } from 'idb-keyval';
|
|
2
|
-
|
|
3
|
-
import { JobApplication } from './chatbot.api';
|
|
4
|
-
import { ApplicationData, getCacheKey } from './chatbot.state';
|
|
5
|
-
|
|
6
|
-
const store = createStore('inploi', 'applications');
|
|
7
|
-
|
|
8
|
-
export const idb = {
|
|
9
|
-
getApplicationData: async (application: JobApplication) => {
|
|
10
|
-
const key = getCacheKey(application);
|
|
11
|
-
return await get<ApplicationData>(key, store);
|
|
12
|
-
},
|
|
13
|
-
setApplicationData: async (params: { application: JobApplication; data: ApplicationData }) => {
|
|
14
|
-
const key = getCacheKey(params.application);
|
|
15
|
-
return await set(key, params.data, store);
|
|
16
|
-
},
|
|
17
|
-
};
|
package/src/chatbot.state.ts
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import { invariant } from '@inploi/core/common';
|
|
2
|
-
import { Signal, batch, signal } from '@preact/signals';
|
|
3
|
-
|
|
4
|
-
import { JobApplication } from './chatbot.api';
|
|
5
|
-
import { idb } from './chatbot.idb';
|
|
6
|
-
import { DistributivePick, getHeadOrThrow } from './chatbot.utils';
|
|
7
|
-
import { ChatInput } from './ui/chat-input/chat-input';
|
|
8
|
-
import { ChatbotInput } from './ui/chat-input/chat-input';
|
|
9
|
-
|
|
10
|
-
export const getCacheKey = (application: JobApplication) =>
|
|
11
|
-
[application.job.id, application.flow.id, application.flow.version].join('/');
|
|
12
|
-
|
|
13
|
-
export type ViewState = 'maximised' | 'minimised';
|
|
14
|
-
export const viewState = signal<ViewState>('maximised');
|
|
15
|
-
|
|
16
|
-
export const inputHeight = signal(0);
|
|
17
|
-
|
|
18
|
-
export type StartedJobApplication = JobApplication & { data: ApplicationData };
|
|
19
|
-
const currentApplication: Signal<StartedJobApplication | null> = signal<StartedJobApplication | null>(null);
|
|
20
|
-
export const cancelCurrentApplication = () => {
|
|
21
|
-
currentApplication.value = null;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
const updateApplicationData = async (updateFn: (data: ApplicationData) => ApplicationData) => {
|
|
25
|
-
const application = currentApplication.value;
|
|
26
|
-
invariant(application, 'No application to update');
|
|
27
|
-
const newData = updateFn(application.data);
|
|
28
|
-
currentApplication.value = { ...application, data: newData };
|
|
29
|
-
await idb.setApplicationData({ application, data: newData });
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
export const application = {
|
|
33
|
-
current$: currentApplication,
|
|
34
|
-
start: async (application: JobApplication) => {
|
|
35
|
-
const data = (await idb.getApplicationData(application)) ?? createNewApplicationData(application);
|
|
36
|
-
batch(() => {
|
|
37
|
-
viewState.value = 'maximised';
|
|
38
|
-
currentApplication.value = { ...application, data };
|
|
39
|
-
});
|
|
40
|
-
data.isFinished = false;
|
|
41
|
-
idb.setApplicationData({ application, data });
|
|
42
|
-
},
|
|
43
|
-
markAsFinished: () => updateApplicationData(data => ({ ...data, isFinished: true })),
|
|
44
|
-
setCurrentNodeId: (currentNodeId: string) => updateApplicationData(data => ({ ...data, currentNodeId })),
|
|
45
|
-
restart: () => {
|
|
46
|
-
const application = currentApplication.value;
|
|
47
|
-
invariant(application, 'No application to restart');
|
|
48
|
-
const data = createNewApplicationData(application);
|
|
49
|
-
currentApplication.value = { ...application, data };
|
|
50
|
-
idb.setApplicationData({ application, data });
|
|
51
|
-
},
|
|
52
|
-
addMessage: (message: ChatMessage) =>
|
|
53
|
-
updateApplicationData(data => ({ ...data, messages: [...data.messages, message] })),
|
|
54
|
-
setSubmission: (fieldKey: string, submission: ApplicationSubmission) =>
|
|
55
|
-
updateApplicationData(data => ({ ...data, submissions: { ...data.submissions, [fieldKey]: submission } })),
|
|
56
|
-
setInput: (input: ChatInput | undefined) => updateApplicationData(data => ({ ...data, currentInput: input })),
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
export type MessageAuthor = 'bot' | 'user';
|
|
60
|
-
|
|
61
|
-
type SystemMessage = { type: 'system'; text: string; variant: 'info' | 'warning' | 'error' | 'success' };
|
|
62
|
-
type TextMessage = { author: MessageAuthor; type: 'text'; text: string };
|
|
63
|
-
type ImageMessage = { author: MessageAuthor; type: 'image'; url: string; width: number; height: number };
|
|
64
|
-
type FileMessage = { author: MessageAuthor; type: 'file'; fileName: string; fileSizeKb: number };
|
|
65
|
-
export type ChatMessage = TextMessage | ImageMessage | SystemMessage | FileMessage;
|
|
66
|
-
|
|
67
|
-
export type ApplicationSubmission = DistributivePick<ChatbotInput, 'type' | 'value'>;
|
|
68
|
-
|
|
69
|
-
export type KeyToSubmissionMap = {
|
|
70
|
-
[key: string]: ApplicationSubmission;
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
/** Dynamic part of an application */
|
|
74
|
-
export type ApplicationData = {
|
|
75
|
-
/** History of messages left in the chat */
|
|
76
|
-
messages: ChatMessage[];
|
|
77
|
-
submissions: KeyToSubmissionMap;
|
|
78
|
-
currentNodeId: string;
|
|
79
|
-
/** Needs to be separate because a node can have many inputs */
|
|
80
|
-
currentInput?: ChatInput;
|
|
81
|
-
isFinished: boolean;
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
const createNewApplicationData = (application: JobApplication): ApplicationData => ({
|
|
85
|
-
messages: [],
|
|
86
|
-
submissions: {},
|
|
87
|
-
currentNodeId: getHeadOrThrow(application.flow.nodes).id,
|
|
88
|
-
isFinished: false,
|
|
89
|
-
});
|
package/src/chatbot.ts
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { createPlugin } from '@inploi/sdk';
|
|
2
|
-
import { h, render } from 'preact';
|
|
3
|
-
import { Chatbot } from '~/ui/chatbot';
|
|
4
|
-
|
|
5
|
-
import { getApplicationData } from './chatbot.api';
|
|
6
|
-
import './chatbot.css';
|
|
7
|
-
import { ChatbotDomManager, createChatbotDomManager } from './chatbot.dom';
|
|
8
|
-
import { application, cancelCurrentApplication } from './chatbot.state';
|
|
9
|
-
|
|
10
|
-
export const chatbotPlugin = ({
|
|
11
|
-
_internal_domManager: dom = createChatbotDomManager(),
|
|
12
|
-
}: {
|
|
13
|
-
geolocationApiKey?: string;
|
|
14
|
-
_internal_domManager?: ChatbotDomManager;
|
|
15
|
-
}) =>
|
|
16
|
-
createPlugin(({ apiClient, logger, analytics }) => {
|
|
17
|
-
let prepared = false;
|
|
18
|
-
const renderAndPrepare = () => {
|
|
19
|
-
const chatbotElement = dom.getOrCreateChatbotElement();
|
|
20
|
-
render(h(Chatbot, { apiClient, logger, analytics }), chatbotElement);
|
|
21
|
-
prepared = true;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
return {
|
|
25
|
-
/** Optionally eagerly renders the interface ahead of application requests. */
|
|
26
|
-
prepare: async () => {
|
|
27
|
-
try {
|
|
28
|
-
if (prepared) return;
|
|
29
|
-
renderAndPrepare();
|
|
30
|
-
logger.info('Chatbot plugin prepared');
|
|
31
|
-
} catch (error) {
|
|
32
|
-
console.error(error);
|
|
33
|
-
logger.error('Error preparing chatbot plugin', error);
|
|
34
|
-
}
|
|
35
|
-
},
|
|
36
|
-
startApplication: async ({ jobId }: { jobId: string }) => {
|
|
37
|
-
try {
|
|
38
|
-
cancelCurrentApplication();
|
|
39
|
-
const applicationData = await getApplicationData({ jobId, apiClient });
|
|
40
|
-
|
|
41
|
-
await application.start(applicationData);
|
|
42
|
-
|
|
43
|
-
if (!prepared) renderAndPrepare();
|
|
44
|
-
} catch (error) {
|
|
45
|
-
console.error(error);
|
|
46
|
-
logger.error('Error starting application', error);
|
|
47
|
-
}
|
|
48
|
-
},
|
|
49
|
-
closeApplication: async () => {
|
|
50
|
-
logger.info('Closing application from an external source');
|
|
51
|
-
cancelCurrentApplication();
|
|
52
|
-
},
|
|
53
|
-
};
|
|
54
|
-
});
|
package/src/chatbot.utils.ts
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { FlowNode } from '@inploi/core/flows';
|
|
2
|
-
|
|
3
|
-
import { ApplicationSubmission, KeyToSubmissionMap, StartedJobApplication } from './chatbot.state';
|
|
4
|
-
|
|
5
|
-
export type DistributivePick<T, K extends keyof T> = T extends unknown ? Pick<T, K> : never;
|
|
6
|
-
|
|
7
|
-
export const getHeadOrThrow = (nodes: FlowNode[]) => {
|
|
8
|
-
const head = nodes.find(n => n.isHead);
|
|
9
|
-
if (!head) throw new Error('No head node found');
|
|
10
|
-
return head;
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
export const submissionsToPayload = ({
|
|
14
|
-
application,
|
|
15
|
-
submissions,
|
|
16
|
-
}: {
|
|
17
|
-
application: StartedJobApplication;
|
|
18
|
-
submissions: KeyToSubmissionMap;
|
|
19
|
-
}) => {
|
|
20
|
-
const payload = {
|
|
21
|
-
flowId: application.flow.id,
|
|
22
|
-
jobId: application.job.id,
|
|
23
|
-
submissions: Object.entries(submissions).reduce(
|
|
24
|
-
(acc, [key, submission]) => {
|
|
25
|
-
acc[key] = submission.value;
|
|
26
|
-
return acc;
|
|
27
|
-
},
|
|
28
|
-
{} as Record<string, ApplicationSubmission['value']>,
|
|
29
|
-
),
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
return payload;
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
export const isSubmissionOfType =
|
|
36
|
-
<T extends ApplicationSubmission['type']>(type: T) =>
|
|
37
|
-
(submission?: ApplicationSubmission): submission is Extract<ApplicationSubmission, { type: T }> => {
|
|
38
|
-
if (!submission) return false;
|
|
39
|
-
return submission.type === type;
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
export function gzip(string: string) {
|
|
43
|
-
if (!('CompressionStream' in window)) return string;
|
|
44
|
-
const byteArray = new TextEncoder().encode(string);
|
|
45
|
-
const cs = new CompressionStream('gzip');
|
|
46
|
-
const writer = cs.writable.getWriter();
|
|
47
|
-
writer.write(byteArray);
|
|
48
|
-
writer.close();
|
|
49
|
-
return new Response(cs.readable).text();
|
|
50
|
-
}
|
package/src/index.cdn.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { chatbotPlugin } from './chatbot';
|
|
2
|
-
|
|
3
|
-
declare global {
|
|
4
|
-
interface Window {
|
|
5
|
-
inploi?: {
|
|
6
|
-
chatbotPlugin?: typeof chatbotPlugin;
|
|
7
|
-
};
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
if (!window.inploi) throw new Error('Please insert the SDK script tag above the plugins.');
|
|
12
|
-
window.inploi.chatbotPlugin = chatbotPlugin;
|