Zum Inhalt springen

Svelte-Integrationsleitfaden

Dieser Leitfaden behandelt Muster zur Integration des Univerx Client SDK in Svelte-Anwendungen, einschließlich reaktivem Status mit Svelte Stores und SvelteKit SSR-Überlegungen.

Verwenden Sie onMount, um das Widget zu initialisieren, und onDestroy, um aufzuräumen. Beide Lifecycle-Funktionen werden garantiert nur im Browser ausgeführt.

<script lang="ts">
import { onMount, onDestroy } from 'svelte';
import { WidgetClient } from '@univerx/client-sdk';
let widget: WidgetClient | null = null;
onMount(() => {
widget = new WidgetClient({
widgetKey: 'your-widget-key',
onAgentAssigned: (agent) => console.log(`Agent: ${agent.name}`),
onCallEnded: () => widget?.destroy(),
});
widget.init();
});
onDestroy(() => {
widget?.destroy();
widget = null;
});
</script>
<!-- SDK renders its own UI; no markup needed -->

Verwenden Sie Sveltes eingebaute writable Stores, um den Widget-Status für Ihr Template und andere Komponenten verfügbar zu machen:

<script lang="ts">
import { onMount, onDestroy } from 'svelte';
import { writable } from 'svelte/store';
import { WidgetClient } from '@univerx/client-sdk';
import type { WidgetState, Agent } from '@univerx/client-sdk';
const state = writable<WidgetState>('idle');
const queuePosition = writable<number | null>(null);
const currentAgent = writable<Agent | null>(null);
let widget: WidgetClient | null = null;
onMount(() => {
widget = new WidgetClient({
widgetKey: 'your-widget-key',
onReady: () => state.set('ready'),
onCallStarted: () => state.set('in_call'),
onCallEnded: () => state.set('ended'),
});
widget.on('queue:update', (pos) => queuePosition.set(pos));
widget.on('queue:left', () => queuePosition.set(null));
widget.on('agent:assigned', (agent) => currentAgent.set(agent));
widget.init();
});
onDestroy(() => {
widget?.destroy();
widget = null;
});
async function joinQueue() {
await widget?.joinQueue({ terms: true });
state.set('queued');
}
async function endCall() {
await widget?.endSession();
}
</script>
{#if $state === 'ready'}
<button on:click={joinQueue}>Get support</button>
{/if}
{#if $state === 'queued'}
<p>Queue position: {$queuePosition}</p>
{/if}
{#if $state === 'in_call'}
<button on:click={endCall}>End call</button>
{/if}

Um die Widget-Instanz über mehrere Komponenten hinweg zu teilen, exportieren Sie einen Store und eine init-Funktion aus einem dedizierten Modul:

lib/widget.ts
import { writable, get } from 'svelte/store';
import { WidgetClient } from '@univerx/client-sdk';
import type { WidgetConfig, WidgetState, Agent } from '@univerx/client-sdk';
export const widgetState = writable<WidgetState>('idle');
export const queuePosition = writable<number | null>(null);
export const currentAgent = writable<Agent | null>(null);
let instance: WidgetClient | null = null;
export function initWidget(config: WidgetConfig): void {
if (instance) return; // already initialised
instance = new WidgetClient({
...config,
onReady: () => widgetState.set('ready'),
onCallStarted: () => widgetState.set('in_call'),
onCallEnded: () => widgetState.set('ended'),
});
instance.on('queue:update', (pos) => queuePosition.set(pos));
instance.on('queue:left', () => queuePosition.set(null));
instance.on('agent:assigned', (agent) => currentAgent.set(agent));
instance.init();
}
export function destroyWidget(): void {
instance?.destroy();
instance = null;
}
export function getWidget(): WidgetClient | null {
return instance;
}

Verwenden Sie es in Ihrer Root-Layout-Komponente:

<script lang="ts">
import { onMount, onDestroy } from 'svelte';
import { initWidget, destroyWidget } from '$lib/widget';
onMount(() => {
initWidget({ widgetKey: 'your-widget-key' });
});
onDestroy(() => {
destroyWidget();
});
</script>
<slot />

Lauschen Sie auf cobrowse:consent:required und binden Sie die Handler an lokalen Status, um Ihre Zustimmungs-UI zu steuern:

<script lang="ts">
import { onMount, onDestroy } from 'svelte';
import { WidgetClient } from '@univerx/client-sdk';
let widget: WidgetClient | null = null;
let consentHandlers: { accept: () => void; decline: () => void } | null = null;
onMount(() => {
widget = new WidgetClient({ widgetKey: 'your-widget-key' });
widget.on('cobrowse:consent:required', (handlers) => {
consentHandlers = handlers;
});
widget.init();
});
onDestroy(() => {
widget?.destroy();
});
</script>
{#if consentHandlers}
<div class="consent-dialog">
<p>The agent is requesting screen access. Do you allow cobrowsing?</p>
<button on:click={() => { consentHandlers?.accept(); consentHandlers = null; }}>
Allow
</button>
<button on:click={() => { consentHandlers?.decline(); consentHandlers = null; }}>
Decline
</button>
</div>
{/if}

SvelteKit rendert Seiten standardmäßig auf dem Server. Da onMount nur im Browser ausgeführt wird, ist die Initialisierung darin bereits sicher. Wenn Sie jedoch auf Modul-Ebene in einer +page.server.ts oder in reinem Server-Code auf das SDK verweisen, wird ein Fehler ausgelöst.

Für dynamische Imports in Randfällen:

<script lang="ts">
import { onMount } from 'svelte';
import type { WidgetClient } from '@univerx/client-sdk';
let widget: WidgetClient | null = null;
onMount(async () => {
// Dynamically import to ensure the module is never evaluated on the server
const { WidgetClient } = await import('@univerx/client-sdk');
widget = new WidgetClient({ widgetKey: 'your-widget-key' });
widget.init();
});
</script>