Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ The component uses a `PostMessageHandler` utility class that:

The React component (`CortiEmbeddedReact`) is available as an additional export and provides:

- **Hook-based API access**: `useCortiEmbeddedApi(ref)` exposes instance-bound methods (`auth`, `navigate`, `createInteraction`, etc.)
- **Hook-based API access**: `useCortiEmbeddedApi(ref)` exposes instance-bound methods (`auth`, `navigate`, `createInteraction`, `showDeviceLinkQR`, etc.)
- **Generic event stream**: `onEvent` receives the wrapper's `event` `CustomEvent`, with `event.detail` shaped as `{ name, payload }`
- **Status hook**: `useCortiEmbeddedStatus(ref)` keeps latest status/reactive state
- **Multi-instance safety**: API methods are scoped to the ref you pass
Expand Down
34 changes: 34 additions & 0 deletions demo/demo.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,37 @@ window.testAuthentication = async () => {
}
};

window.showDeviceLinkQR = async () => {
if (component?.showDeviceLinkQR) {
try {
const payloadText = document.getElementById(
"device-link-qr-payload",
).value;
let payload;
try {
payload = JSON.parse(payloadText);
} catch (jsonError) {
window.addLogEntry(
`Invalid JSON in payload: ${jsonError.message}`,
"error",
);
return;
}

window.addLogEntry("Showing device-link QR", "info");
const response = await component.showDeviceLinkQR(payload);
window.addLogEntry(
`Device-link QR finished with status: ${response.status}`,
"success",
);
} catch (error) {
window.addLogEntry(`Device-link QR failed: ${error.message}`, "error");
}
} else {
window.addLogEntry("Component not ready for showDeviceLinkQR", "error");
}
};

window.configureApp = async () => {
if (component?.configureApp) {
try {
Expand Down Expand Up @@ -384,6 +415,9 @@ document.addEventListener("DOMContentLoaded", () => {
document
.getElementById("auth-btn")
.addEventListener("click", window.testAuthentication);
document
.getElementById("device-link-qr-btn")
.addEventListener("click", window.showDeviceLinkQR);
document
.getElementById("clear-log-btn")
.addEventListener("click", window.clearLog);
Expand Down
40 changes: 40 additions & 0 deletions demo/demo.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type {
ConfigureApplicationPayload,
ConfigurePayload,
DeviceLinkTokenResponse,
Fact,
InteractionDetails,
CreateInteractionPayload,
Expand Down Expand Up @@ -114,6 +115,40 @@ export const testAuthentication = async (): Promise<void> => {
}
};

export const showDeviceLinkQR = async (): Promise<void> => {
if (component?.showDeviceLinkQR) {
try {
const payloadElement = document.getElementById(
"device-link-qr-payload",
) as HTMLTextAreaElement;
const payloadText = payloadElement.value;
let payload: DeviceLinkTokenResponse;

try {
payload = JSON.parse(payloadText) as DeviceLinkTokenResponse;
} catch (jsonError) {
const errorMessage =
jsonError instanceof Error ? jsonError.message : "Unknown JSON error";
addLogEntry(`Invalid JSON in payload: ${errorMessage}`, "error");
return;
}

addLogEntry("Showing device-link QR", "info");
const response = await component.showDeviceLinkQR(payload);
addLogEntry(
`Device-link QR finished with status: ${response.status}`,
"success",
);
} catch (error) {
const errorMessage =
error instanceof Error ? error.message : "Unknown error";
console.error(`Device-link QR failed: ${errorMessage}`);
}
} else {
addLogEntry("Component not ready for showDeviceLinkQR", "error");
}
};

export const setInteractionOptions = async (): Promise<void> => {
if (component?.setInteractionOptions) {
try {
Expand Down Expand Up @@ -482,6 +517,7 @@ declare global {
showCorti: typeof showCorti;
hideCorti: typeof hideCorti;
testAuthentication: typeof testAuthentication;
showDeviceLinkQR: typeof showDeviceLinkQR;
setInteractionOptions: typeof setInteractionOptions;
addFacts: typeof addFacts;
navigate: typeof navigate;
Expand All @@ -504,6 +540,7 @@ Object.assign(window, {
showCorti,
hideCorti,
testAuthentication,
showDeviceLinkQR,
setInteractionOptions,
addFacts,
navigate,
Expand Down Expand Up @@ -551,6 +588,9 @@ document.addEventListener("DOMContentLoaded", () => {
document
.getElementById("auth-btn")
?.addEventListener("click", testAuthentication);
document
.getElementById("device-link-qr-btn")
?.addEventListener("click", showDeviceLinkQR);
document.getElementById("clear-log-btn")?.addEventListener("click", clearLog);
document
.getElementById("create-interaction-btn")
Expand Down
99 changes: 97 additions & 2 deletions demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,28 @@ <h1>Corti Embedded Web Component Demo</h1>
</div>
</div>

<div class="method-box">
<div class="demo-title">Device Link QR</div>
<div class="section-row">
<details class="auth-payload-section">
<summary>⚙️ Settings</summary>
<label for="device-link-qr-payload">Payload:</label>
<textarea
id="device-link-qr-payload"
placeholder='{"access_token": "your-token", "token_type": "Bearer", "refresh_token": "your-refresh-token"}'
>
{
"access_token": "demo-device-link-token",
"token_type": "Bearer",
"expires_in": 300,
"refresh_token": "demo-device-link-refresh-token"
}</textarea
>
</details>
<button class="postmessage-btn" id="device-link-qr-btn">Send</button>
</div>
</div>

<div class="method-box">
<div class="demo-title">Configure App</div>
<div class="section-row">
Expand All @@ -55,7 +77,28 @@ <h1>Corti Embedded Web Component Demo</h1>
id="configure-app-payload"
placeholder='{"ui": {"aiChat": false}}'
>
{"ui": {"aiChat": false, "navigation": true}}</textarea
{
"debug": false,
"appearance": {
"primaryColor": "#0066cc"
},
"ui": {
"interactionTitle": true,
"aiChat": true,
"documentFeedback": true,
"navigation": true
},
"companionApp": {
"enabled": true
},
"locale": {
"interfaceLanguage": "en",
"dictationLanguage": "en",
"overrides": {
"assistant.header.title": "Embedded Assistant"
}
}
}</textarea
>
</details>
<button class="postmessage-btn" id="configure-app-btn">
Expand All @@ -74,7 +117,59 @@ <h1>Corti Embedded Web Component Demo</h1>
id="interaction-options-payload"
placeholder='{"mode": {"fallback": "virtual", "options": ["in-person", "virtual"]}}'
>
{"mode": {"fallback": "virtual", "options": ["in-person", "virtual"]}, "spokenLanguage": {"fallback": "en"}}</textarea
{
"mode": {
"fallback": "virtual",
"options": ["in-person", "virtual"]
},
"spokenLanguage": {
"fallback": "en",
"options": ["en", "da"]
},
"templates": {
"sources": {
"personal": {
"enabled": true,
"sectionFields": {
"heading": {"editable": true},
"description": {"editable": true},
"contentPrompt": {"visible": true, "editable": true},
"writingStylePrompt": {"visible": true, "editable": true},
"miscPrompt": {"visible": true, "editable": true},
"outputSchema": {"visible": true, "editable": false}
}
},
"standard": {
"enabled": true,
"include": {
"regions": ["en"],
"families": ["soap"]
}
},
"project": {
"enabled": true,
"exclude": {
"ids": ["deprecated-template"]
}
}
},
"defaultTemplate": {
"behaviour": "fallback",
"template": {
"source": "standard",
"id": "soap_note-en"
},
"allowUserSelection": true
}
},
"documents": {
"actions": {
"sync": true
},
"allowedLanguages": ["en"],
"maxGenerated": "unlimited"
}
}</textarea
>
</details>
<button class="postmessage-btn" id="set-interaction-options-btn">
Expand Down
Loading
Loading