This repository has been archived by the owner on Feb 5, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 101
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: new voiceflow chat - initial commit (#176)
- Loading branch information
Showing
200 changed files
with
7,733 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"presets": ["@babel/preset-env", "@babel/preset-react", "@babel/preset-typescript"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import { createConfig } from '@voiceflow/dependency-cruiser-config'; | ||
|
||
export default createConfig({ allowTypeCycles: true }); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
/test-results/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# Change Log | ||
|
||
All notable changes to this project will be documented in this file. | ||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# chat | ||
|
||
## 🚧 WIP - Under Construction 🚧 | ||
|
||
This is going to be a totally redesigned and renewed version of the `react-chat` package. | ||
It is definitely not ready to be used for any use-case. | ||
Do not use this. | ||
|
||
More details will come... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { vi } from 'vitest'; | ||
|
||
export const createStitches = vi.fn().mockReturnValue({ | ||
styled: vi.fn().mockImplementation((el) => el), | ||
keyframes: vi.fn(), | ||
}); | ||
|
||
export const keyframes = vi.fn(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"outputDir": "./storybook-static" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import '@testing-library/jest-dom/vitest'; | ||
|
||
import { vi } from 'vitest'; | ||
|
||
vi.mock('@voiceflow/stitches-react'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
<!doctype html> | ||
<html> | ||
<head> | ||
<title>Embedded Mode</title> | ||
<style> | ||
body { | ||
background-color: #f9f9f9; | ||
} | ||
|
||
#flat-chat { | ||
width: 100vw; | ||
height: 100vh; | ||
position: absolute; | ||
top: 0; | ||
left: 0; | ||
} | ||
</style> | ||
</head> | ||
|
||
<body> | ||
<div id="flat-chat"></div> | ||
|
||
<script type="text/javascript"> | ||
(function (d, t) { | ||
var v = d.createElement(t), | ||
s = d.getElementsByTagName(t)[0]; | ||
v.onload = function () { | ||
window.voiceflow.chat.load({ | ||
verify: { projectID: 'projectID' }, | ||
render: { | ||
mode: 'embedded', | ||
target: document.getElementById('flat-chat'), | ||
}, | ||
}); | ||
}; | ||
v.src = '../dist/bundle.mjs'; | ||
v.type = 'text/javascript'; | ||
s.parentNode.insertBefore(v, s); | ||
})(document, 'script'); | ||
</script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { expect, test } from '@playwright/test'; | ||
|
||
test('renders embedded webchat and starts automatically', async ({ page }) => { | ||
await page.goto('embedded'); | ||
|
||
const chat = page.locator('.vfrc-chat'); | ||
await chat.waitFor({ state: 'visible' }); | ||
expect(chat).toBeInViewport(); | ||
page.locator('.vfrc-footer .vfrc-button').click(); | ||
|
||
await page.locator('.vfrc-chat-input').waitFor({ state: 'visible' }); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
<!doctype html> | ||
<html> | ||
<head> | ||
<title>Embedded Mode</title> | ||
<style> | ||
body { | ||
background-color: #f9f9f9; | ||
} | ||
|
||
#voiceflow-chat-frame { | ||
width: 100vw; | ||
height: 100vh; | ||
position: fixed; | ||
top: 0; | ||
left: 0; | ||
} | ||
|
||
#order-status { | ||
position: absolute; | ||
visibility: hidden; | ||
left: 50%; | ||
top: 8px; | ||
transform: translateX(-50%); | ||
padding: 8px; | ||
border-radius: 10px; | ||
background-color: orangered; | ||
z-index: 10; | ||
|
||
font-family: 'Open Sans', sans-serif; | ||
font-size: 20px; | ||
font-weight: 400; | ||
} | ||
</style> | ||
</head> | ||
|
||
<body> | ||
<span id="order-status" data-testid="status"></span> | ||
<div id="voiceflow-chat-frame"></div> | ||
<template id="complex-form"> | ||
<form> | ||
<input name="name" placeholder="What is your name?" /> | ||
<fieldset> | ||
<legend>What kind of hair do you have?</legend> | ||
<div> | ||
<input type="radio" name="hair" id="straight" value="straight" checked /><label for="straight" | ||
>Straight</label | ||
> | ||
</div> | ||
<div><input type="radio" name="hair" id="curly" value="curly" /><label for="curly">Curly</label></div> | ||
<div><input type="radio" name="hair" id="wavy" value="wavy" /><label for="wavy">Wavy</label></div> | ||
</fieldset> | ||
<button>submit</button> | ||
</form> | ||
</template> | ||
|
||
<script type="text/javascript"> | ||
(function (d, t) { | ||
var v = d.createElement(t), | ||
s = d.getElementsByTagName(t)[0]; | ||
v.onload = () => { | ||
window.voiceflow.chat.load({ | ||
verify: { projectID: 'projectID' }, | ||
render: { mode: 'embedded' }, | ||
autostart: true, | ||
assistant: { | ||
extensions: [ | ||
{ | ||
name: 'order_tracker', | ||
type: 'effect', | ||
match: ({ trace }) => trace.type === 'update_order_status', | ||
effect({ trace }) { | ||
const element = document.getElementById('order-status'); | ||
const status = trace.payload; | ||
|
||
element.style.visibility = 'visible'; | ||
element.innerText = status; | ||
}, | ||
}, | ||
{ | ||
name: 'onboarding_form', | ||
type: 'response', | ||
match: ({ trace }) => trace.type === 'onboarding', | ||
render({ trace, element }) { | ||
const template = document.getElementById('complex-form').content.cloneNode(true); | ||
const id = 'onboarding-form-' + Date.now(); | ||
template.firstElementChild.id = id; | ||
|
||
element.appendChild(template); | ||
|
||
const form = element.querySelector(`#${id}`); | ||
form.addEventListener('submit', async (event) => { | ||
event.preventDefault(); | ||
|
||
await window.voiceflow.chat.interact({ | ||
type: 'submit', | ||
payload: { | ||
name: form.elements.name.value, | ||
hair: form.elements.hair.value, | ||
}, | ||
}); | ||
while (form.firstChild) { | ||
form.removeChild(form.firstChild); | ||
} | ||
|
||
const confirmation = document.createElement('em'); | ||
confirmation.innerText = `submitted ✅`; | ||
|
||
form.appendChild(confirmation); | ||
}); | ||
}, | ||
}, | ||
], | ||
}, | ||
}); | ||
}; | ||
v.src = '../dist/bundle.mjs'; | ||
v.type = 'text/javascript'; | ||
s.parentNode.insertBefore(v, s); | ||
})(document, 'script'); | ||
</script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
import { expect, test } from '@playwright/test'; | ||
|
||
import { slateMessage } from './utils'; | ||
|
||
const RUNTIME_URL = 'https://general-runtime.voiceflow.com/public/projectID/state/user/*/interact'; | ||
|
||
test('trigger effect extension on incoming trace', async ({ page }) => { | ||
const systemMessages = [ | ||
'Welcome to the pizza palace!', | ||
'What kind of pizza do you want?', | ||
'One cheese pizza coming right up', | ||
]; | ||
const userMessages = ['I want to order a pizza', 'Cheese please']; | ||
const traceType = 'update_order_status'; | ||
let count = 0; | ||
|
||
// eslint-disable-next-line consistent-return | ||
await page.route(RUNTIME_URL, async (route) => { | ||
count++; | ||
|
||
switch (count) { | ||
case 1: | ||
return route.fulfill({ | ||
json: { | ||
trace: [{ type: traceType, payload: 'idle' }, slateMessage(systemMessages[0])], | ||
}, | ||
}); | ||
|
||
case 2: | ||
return route.fulfill({ | ||
json: { | ||
trace: [{ type: traceType, payload: 'in progress' }, slateMessage(systemMessages[1])], | ||
}, | ||
}); | ||
|
||
case 3: | ||
return route.fulfill({ | ||
json: { | ||
trace: [{ type: traceType, payload: 'ordered' }, slateMessage(systemMessages[2])], | ||
}, | ||
}); | ||
|
||
default: | ||
} | ||
}); | ||
|
||
await page.goto('extensions'); | ||
|
||
const chat = page.locator('.vfrc-chat'); | ||
await chat.waitFor({ state: 'visible' }); | ||
expect(chat).toBeInViewport(); | ||
|
||
await page.locator('[data-testid="status"]', { hasText: 'idle' }).waitFor({ state: 'visible' }); | ||
await page.locator('.vfrc-message', { hasText: systemMessages[0] }).waitFor({ state: 'visible' }); | ||
|
||
const input = page.locator('.vfrc-chat-input textarea'); | ||
await input.waitFor({ state: 'visible' }); | ||
await input.fill(userMessages[0]); | ||
|
||
const submit = page.locator('.vfrc-chat-input .vfrc-bubble'); | ||
await submit.click(); | ||
|
||
await page.locator('.vfrc-message', { hasText: userMessages[0] }).waitFor({ state: 'visible' }); | ||
await page.locator('.vfrc-message', { hasText: systemMessages[1] }).waitFor({ state: 'visible' }); | ||
await page.locator('[data-testid="status"]', { hasText: 'in progress' }).waitFor({ state: 'visible' }); | ||
|
||
await input.fill(userMessages[1]); | ||
await submit.click(); | ||
|
||
await page.locator('.vfrc-message', { hasText: userMessages[1] }).waitFor({ state: 'visible' }); | ||
await page.locator('.vfrc-message', { hasText: systemMessages[2] }).waitFor({ state: 'visible' }); | ||
await page.locator('[data-testid="status"]', { hasText: 'ordered' }).waitFor({ state: 'visible' }); | ||
}); | ||
|
||
test('render response extension from incoming trace', async ({ page }) => { | ||
let count = 0; | ||
|
||
await page.route(RUNTIME_URL, (route) => { | ||
count++; | ||
|
||
switch (count) { | ||
case 1: | ||
return route.fulfill({ | ||
json: { | ||
trace: [slateMessage("Welcome to Sal's Salon! Tell me about yourself."), { type: 'onboarding' }], | ||
}, | ||
}); | ||
case 2: | ||
default: | ||
expect(route.request().postDataJSON()).toEqual({ | ||
action: { | ||
type: 'submit', | ||
payload: { name: 'Alex', hair: 'curly' }, | ||
}, | ||
}); | ||
|
||
return route.fulfill({ json: { trace: [] } }); | ||
} | ||
}); | ||
|
||
await page.goto('extensions'); | ||
|
||
const chat = page.locator('.vfrc-chat'); | ||
await chat.waitFor({ state: 'visible' }); | ||
expect(chat).toBeInViewport(); | ||
|
||
await page.locator('.vfrc-message').waitFor({ state: 'visible' }); | ||
|
||
const extensionMessage = page.locator('.vfrc-message--extension-onboarding_form'); | ||
await extensionMessage.waitFor({ state: 'visible' }); | ||
|
||
await extensionMessage.locator('[name="name"]').fill('Alex'); | ||
await extensionMessage.locator('[name="hair"][id="curly"]').click(); | ||
await extensionMessage.getByRole('button').click(); | ||
await page | ||
.locator('.vfrc-message--extension-onboarding_form', { hasText: 'submitted ✅' }) | ||
.waitFor({ state: 'visible' }); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
<!doctype html> | ||
<html> | ||
<head> | ||
<title>Overlay mode</title> | ||
<style> | ||
body { | ||
background-color: #f9f9f9; | ||
} | ||
</style> | ||
</head> | ||
|
||
<body> | ||
<script type="text/javascript"> | ||
(function (d, t) { | ||
var v = d.createElement(t), | ||
s = d.getElementsByTagName(t)[0]; | ||
v.onload = function () { | ||
window.voiceflow.chat.load({ | ||
verify: { projectID: 'projectID' }, | ||
render: { mode: 'overlay' }, | ||
}); | ||
}; | ||
v.src = '../dist/bundle.mjs'; | ||
v.type = 'text/javascript'; | ||
s.parentNode.insertBefore(v, s); | ||
})(document, 'script'); | ||
</script> | ||
</body> | ||
</html> |
Oops, something went wrong.