@skippr/live-agent-sdk 0.33.0 → 0.35.0
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/README.md +53 -25
- package/dist/esm/lib-exports.js +1047 -293
- package/dist/skippr-sdk.css +1 -1
- package/dist/skippr-sdk.js +144 -144
- package/dist/types/components/LiveAgent.d.ts +1 -1
- package/dist/types/components/MeetingControls.d.ts +5 -1
- package/dist/types/components/ModuleSelector.d.ts +1 -0
- package/dist/types/components/StartSessionPrompt.d.ts +10 -2
- package/dist/types/context/LiveAgentContext.d.ts +35 -1
- package/dist/types/hooks/useAvailableModules.d.ts +13 -0
- package/dist/types/hooks/useLiveAgent.d.ts +1 -0
- package/dist/types/hooks/useSession.d.ts +26 -4
- package/dist/types/lib/react-compat.d.ts +26 -0
- package/dist/types/lib-exports.d.ts +1 -0
- package/package.json +1 -1
package/dist/esm/lib-exports.js
CHANGED
|
@@ -8,7 +8,7 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
8
8
|
|
|
9
9
|
// src/components/LiveAgent.tsx
|
|
10
10
|
import { LiveKitRoom, RoomAudioRenderer } from "@livekit/components-react";
|
|
11
|
-
import { useCallback as
|
|
11
|
+
import { useCallback as useCallback8, useMemo as useMemo6, useRef as useRef10, useState as useState11 } from "react";
|
|
12
12
|
|
|
13
13
|
// src/context/LiveAgentContext.tsx
|
|
14
14
|
import { createContext } from "react";
|
|
@@ -155,11 +155,91 @@ function useAuth({ appKey }) {
|
|
|
155
155
|
};
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
-
// src/hooks/
|
|
158
|
+
// src/hooks/useAvailableModules.ts
|
|
159
159
|
import { useCallback as useCallback2, useEffect as useEffect2, useState as useState2 } from "react";
|
|
160
160
|
var API_URL2 = "https://specialist.skippr.ai/api";
|
|
161
|
+
function useAvailableModules({
|
|
162
|
+
enabled,
|
|
163
|
+
bearerToken
|
|
164
|
+
}) {
|
|
165
|
+
const [modules, setModules] = useState2([]);
|
|
166
|
+
const [isLoading, setIsLoading] = useState2(false);
|
|
167
|
+
const [error, setError] = useState2(null);
|
|
168
|
+
const fetchModules = useCallback2(async () => {
|
|
169
|
+
if (!bearerToken) {
|
|
170
|
+
setError("No auth token available");
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
setIsLoading(true);
|
|
174
|
+
setError(null);
|
|
175
|
+
try {
|
|
176
|
+
const resp = await fetch(`${API_URL2}/v1/modules/available`, {
|
|
177
|
+
credentials: "omit",
|
|
178
|
+
headers: { Authorization: `Bearer ${bearerToken}` }
|
|
179
|
+
});
|
|
180
|
+
if (!resp.ok) {
|
|
181
|
+
const body = await resp.json().catch(() => null);
|
|
182
|
+
throw new Error(body?.detail || `Failed to load modules: ${resp.status}`);
|
|
183
|
+
}
|
|
184
|
+
const data = await resp.json();
|
|
185
|
+
setModules(Array.isArray(data?.modules) ? data.modules : []);
|
|
186
|
+
} catch (e) {
|
|
187
|
+
setError(e instanceof Error ? e.message : "Failed to load modules");
|
|
188
|
+
} finally {
|
|
189
|
+
setIsLoading(false);
|
|
190
|
+
}
|
|
191
|
+
}, [bearerToken]);
|
|
192
|
+
useEffect2(() => {
|
|
193
|
+
if (!enabled || !bearerToken)
|
|
194
|
+
return;
|
|
195
|
+
fetchModules();
|
|
196
|
+
}, [enabled, bearerToken, fetchModules]);
|
|
197
|
+
return {
|
|
198
|
+
modules,
|
|
199
|
+
isLoading,
|
|
200
|
+
error,
|
|
201
|
+
refetch: fetchModules
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// src/hooks/useSession.ts
|
|
206
|
+
import { useCallback as useCallback3, useEffect as useEffect3, useRef, useState as useState3 } from "react";
|
|
207
|
+
var API_URL3 = "https://specialist.skippr.ai/api";
|
|
208
|
+
async function fetchSessionMessages(sessionId, bearerToken) {
|
|
209
|
+
try {
|
|
210
|
+
const resp = await fetch(`${API_URL3}/v1/sessions/${sessionId}/messages`, {
|
|
211
|
+
credentials: "omit",
|
|
212
|
+
headers: { Authorization: `Bearer ${bearerToken}` }
|
|
213
|
+
});
|
|
214
|
+
if (!resp.ok)
|
|
215
|
+
return [];
|
|
216
|
+
const { messages } = await resp.json();
|
|
217
|
+
return messages.filter((message) => message.role !== "system").map((message) => ({
|
|
218
|
+
id: message.id,
|
|
219
|
+
role: message.role === "user" ? "user" : "assistant",
|
|
220
|
+
content: message.content,
|
|
221
|
+
source: "chat",
|
|
222
|
+
timestamp: new Date(message.createdAt).getTime()
|
|
223
|
+
}));
|
|
224
|
+
} catch {
|
|
225
|
+
return [];
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
async function requestScreenShare() {
|
|
229
|
+
try {
|
|
230
|
+
return await navigator.mediaDevices.getDisplayMedia({ video: { displaySurface: "browser" } });
|
|
231
|
+
} catch {
|
|
232
|
+
return null;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
function stopStream(stream) {
|
|
236
|
+
if (!stream)
|
|
237
|
+
return;
|
|
238
|
+
for (const track of stream.getTracks())
|
|
239
|
+
track.stop();
|
|
240
|
+
}
|
|
161
241
|
async function exchangeForBearerToken(appKey, userToken) {
|
|
162
|
-
const resp = await fetch(`${
|
|
242
|
+
const resp = await fetch(`${API_URL3}/v1/auth/token-exchange`, {
|
|
163
243
|
method: "POST",
|
|
164
244
|
credentials: "omit",
|
|
165
245
|
headers: {
|
|
@@ -174,22 +254,28 @@ async function exchangeForBearerToken(appKey, userToken) {
|
|
|
174
254
|
return token;
|
|
175
255
|
}
|
|
176
256
|
function useSession({
|
|
177
|
-
agentId,
|
|
178
257
|
captureMode = "screenshare",
|
|
179
|
-
agentControls,
|
|
180
258
|
authToken,
|
|
181
259
|
appKey,
|
|
182
|
-
userToken
|
|
260
|
+
userToken,
|
|
261
|
+
onStart,
|
|
262
|
+
onStartError,
|
|
263
|
+
onDisconnect
|
|
183
264
|
}) {
|
|
184
|
-
const [connection, setConnection] =
|
|
185
|
-
const [shouldConnect, setShouldConnect] =
|
|
186
|
-
const [isStarting, setIsStarting] =
|
|
187
|
-
const [
|
|
188
|
-
const [
|
|
189
|
-
const [
|
|
190
|
-
const [
|
|
191
|
-
const [
|
|
192
|
-
|
|
265
|
+
const [connection, setConnection] = useState3(null);
|
|
266
|
+
const [shouldConnect, setShouldConnect] = useState3(false);
|
|
267
|
+
const [isStarting, setIsStarting] = useState3(false);
|
|
268
|
+
const [isDisconnecting, setIsDisconnecting] = useState3(false);
|
|
269
|
+
const [error, setError] = useState3("");
|
|
270
|
+
const [errorCode, setErrorCode] = useState3(null);
|
|
271
|
+
const [sessionId, setSessionId] = useState3(null);
|
|
272
|
+
const [bearerToken, setBearerToken] = useState3(authToken ?? null);
|
|
273
|
+
const [pendingScreenStream, setPendingScreenStream] = useState3(null);
|
|
274
|
+
const [isPaused, setIsPaused] = useState3(false);
|
|
275
|
+
const [isPausing, setIsPausing] = useState3(false);
|
|
276
|
+
const [resumableSessions, setResumableSessions] = useState3([]);
|
|
277
|
+
const [historyMessages, setHistoryMessages] = useState3([]);
|
|
278
|
+
useEffect3(() => {
|
|
193
279
|
let stale = false;
|
|
194
280
|
if (authToken) {
|
|
195
281
|
setBearerToken(authToken);
|
|
@@ -208,29 +294,67 @@ function useSession({
|
|
|
208
294
|
stale = true;
|
|
209
295
|
};
|
|
210
296
|
}, [authToken, appKey, userToken]);
|
|
211
|
-
const
|
|
212
|
-
|
|
297
|
+
const refetchResumable = useCallback3(async () => {
|
|
298
|
+
if (!bearerToken) {
|
|
299
|
+
setResumableSessions([]);
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
try {
|
|
303
|
+
const resp = await fetch(`${API_URL3}/v1/sessions/resumable`, {
|
|
304
|
+
credentials: "omit",
|
|
305
|
+
headers: { Authorization: `Bearer ${bearerToken}` }
|
|
306
|
+
});
|
|
307
|
+
if (!resp.ok) {
|
|
308
|
+
setResumableSessions([]);
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
const { sessions } = await resp.json();
|
|
312
|
+
setResumableSessions(sessions);
|
|
313
|
+
} catch {
|
|
314
|
+
setResumableSessions([]);
|
|
315
|
+
}
|
|
316
|
+
}, [bearerToken]);
|
|
317
|
+
useEffect3(() => {
|
|
318
|
+
refetchResumable();
|
|
319
|
+
}, [refetchResumable]);
|
|
320
|
+
const pauseOnUnloadRef = useRef(null);
|
|
321
|
+
pauseOnUnloadRef.current = connection !== null && !isPaused && sessionId && bearerToken ? { sessionId, bearerToken } : null;
|
|
322
|
+
useEffect3(() => {
|
|
323
|
+
const onPageHide = () => {
|
|
324
|
+
const pending = pauseOnUnloadRef.current;
|
|
325
|
+
if (!pending)
|
|
326
|
+
return;
|
|
327
|
+
fetch(`${API_URL3}/v1/sessions/${pending.sessionId}/pause`, {
|
|
328
|
+
method: "POST",
|
|
329
|
+
credentials: "omit",
|
|
330
|
+
keepalive: true,
|
|
331
|
+
headers: { Authorization: `Bearer ${pending.bearerToken}` }
|
|
332
|
+
}).catch(() => {});
|
|
333
|
+
};
|
|
334
|
+
window.addEventListener("pagehide", onPageHide);
|
|
335
|
+
return () => window.removeEventListener("pagehide", onPageHide);
|
|
336
|
+
}, []);
|
|
337
|
+
const startSession = useCallback3(async ({ agentId, agentControls }) => {
|
|
213
338
|
if (!bearerToken) {
|
|
214
339
|
setError("No auth token available");
|
|
215
340
|
return;
|
|
216
341
|
}
|
|
342
|
+
if (!agentId) {
|
|
343
|
+
setError("No agent selected");
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
217
346
|
setIsStarting(true);
|
|
218
347
|
setError("");
|
|
219
348
|
setErrorCode(null);
|
|
349
|
+
onStart?.();
|
|
220
350
|
let screenStream = null;
|
|
221
351
|
if (captureMode === "screenshare") {
|
|
222
|
-
|
|
223
|
-
screenStream = await navigator.mediaDevices.getDisplayMedia({
|
|
224
|
-
video: { displaySurface: "browser" }
|
|
225
|
-
});
|
|
226
|
-
} catch {
|
|
227
|
-
screenStream = null;
|
|
228
|
-
}
|
|
352
|
+
screenStream = await requestScreenShare();
|
|
229
353
|
}
|
|
230
|
-
const requestAgentControls =
|
|
354
|
+
const requestAgentControls = agentControls?.highlight === true ? { highlight: true } : undefined;
|
|
231
355
|
const headers = { Authorization: `Bearer ${bearerToken}` };
|
|
232
356
|
try {
|
|
233
|
-
const createResp = await fetch(`${
|
|
357
|
+
const createResp = await fetch(`${API_URL3}/v1/sessions`, {
|
|
234
358
|
method: "POST",
|
|
235
359
|
credentials: "omit",
|
|
236
360
|
headers: { "Content-Type": "application/json", ...headers },
|
|
@@ -246,7 +370,7 @@ function useSession({
|
|
|
246
370
|
throw new Error(body?.detail || `Failed to create session: ${createResp.status}`);
|
|
247
371
|
}
|
|
248
372
|
const { session } = await createResp.json();
|
|
249
|
-
const startResp = await fetch(`${
|
|
373
|
+
const startResp = await fetch(`${API_URL3}/v1/sessions/${session.id}/start`, {
|
|
250
374
|
method: "POST",
|
|
251
375
|
credentials: "omit",
|
|
252
376
|
headers
|
|
@@ -258,52 +382,142 @@ function useSession({
|
|
|
258
382
|
}
|
|
259
383
|
const { connection: conn } = await startResp.json();
|
|
260
384
|
setSessionId(session.id);
|
|
385
|
+
setHistoryMessages([]);
|
|
261
386
|
setConnection({
|
|
262
387
|
livekitUrl: conn.livekitUrl,
|
|
263
388
|
token: conn.token
|
|
264
389
|
});
|
|
265
390
|
setPendingScreenStream(screenStream);
|
|
266
391
|
setShouldConnect(true);
|
|
392
|
+
setIsPaused(false);
|
|
267
393
|
} catch (e) {
|
|
268
|
-
|
|
269
|
-
for (const track of screenStream.getTracks())
|
|
270
|
-
track.stop();
|
|
271
|
-
}
|
|
394
|
+
stopStream(screenStream);
|
|
272
395
|
setError(e instanceof Error ? e.message : "Failed to start session");
|
|
396
|
+
onStartError?.();
|
|
273
397
|
} finally {
|
|
274
398
|
setIsStarting(false);
|
|
275
399
|
}
|
|
276
|
-
}, [
|
|
277
|
-
const
|
|
278
|
-
if (sessionId
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
400
|
+
}, [captureMode, bearerToken, onStart, onStartError]);
|
|
401
|
+
const pauseSession = useCallback3(async () => {
|
|
402
|
+
if (!sessionId || !bearerToken)
|
|
403
|
+
return;
|
|
404
|
+
setIsPausing(true);
|
|
405
|
+
try {
|
|
406
|
+
const resp = await fetch(`${API_URL3}/v1/sessions/${sessionId}/pause`, {
|
|
407
|
+
method: "POST",
|
|
408
|
+
credentials: "omit",
|
|
409
|
+
headers: { Authorization: `Bearer ${bearerToken}` }
|
|
410
|
+
});
|
|
411
|
+
if (!resp.ok) {
|
|
412
|
+
const body = await resp.json().catch(() => null);
|
|
413
|
+
throw new Error(body?.detail || `Failed to pause: ${resp.status}`);
|
|
414
|
+
}
|
|
415
|
+
} catch (e) {
|
|
416
|
+
setError(e instanceof Error ? e.message : "Failed to pause session");
|
|
417
|
+
setIsPausing(false);
|
|
418
|
+
return;
|
|
291
419
|
}
|
|
292
|
-
|
|
420
|
+
const history2 = await fetchSessionMessages(sessionId, bearerToken);
|
|
421
|
+
stopStream(pendingScreenStream);
|
|
422
|
+
setPendingScreenStream(null);
|
|
293
423
|
setShouldConnect(false);
|
|
294
424
|
setConnection(null);
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
425
|
+
setHistoryMessages(history2);
|
|
426
|
+
setIsPaused(true);
|
|
427
|
+
setIsPausing(false);
|
|
428
|
+
await refetchResumable();
|
|
429
|
+
}, [sessionId, bearerToken, pendingScreenStream, refetchResumable]);
|
|
430
|
+
const resumeSession = useCallback3(async ({
|
|
431
|
+
sessionId: resumeId,
|
|
432
|
+
agentControls
|
|
433
|
+
}) => {
|
|
434
|
+
if (!bearerToken) {
|
|
435
|
+
setError("No auth token available");
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
setIsStarting(true);
|
|
439
|
+
setError("");
|
|
440
|
+
setErrorCode(null);
|
|
441
|
+
onStart?.();
|
|
442
|
+
let screenStream = null;
|
|
443
|
+
if (captureMode === "screenshare") {
|
|
444
|
+
screenStream = await requestScreenShare();
|
|
445
|
+
}
|
|
446
|
+
const requestAgentControls = agentControls?.highlight === true ? { highlight: true } : undefined;
|
|
447
|
+
try {
|
|
448
|
+
const resp = await fetch(`${API_URL3}/v1/sessions/${resumeId}/resume`, {
|
|
449
|
+
method: "POST",
|
|
450
|
+
credentials: "omit",
|
|
451
|
+
headers: { "Content-Type": "application/json", Authorization: `Bearer ${bearerToken}` },
|
|
452
|
+
body: JSON.stringify({ captureMode, agentControls: requestAgentControls })
|
|
453
|
+
});
|
|
454
|
+
if (!resp.ok) {
|
|
455
|
+
const body = await resp.json().catch(() => null);
|
|
456
|
+
setErrorCode(resp.status);
|
|
457
|
+
throw new Error(body?.detail || `Failed to resume: ${resp.status}`);
|
|
458
|
+
}
|
|
459
|
+
const { session, connection: conn } = await resp.json();
|
|
460
|
+
const history2 = await fetchSessionMessages(session.id, bearerToken);
|
|
461
|
+
setSessionId(session.id);
|
|
462
|
+
setConnection({ livekitUrl: conn.livekitUrl, token: conn.token });
|
|
463
|
+
setPendingScreenStream(screenStream);
|
|
464
|
+
setHistoryMessages(history2);
|
|
465
|
+
setShouldConnect(true);
|
|
466
|
+
setIsPaused(false);
|
|
467
|
+
setResumableSessions((prev) => prev.filter((s) => s.id !== resumeId));
|
|
468
|
+
} catch (e) {
|
|
469
|
+
stopStream(screenStream);
|
|
470
|
+
setError(e instanceof Error ? e.message : "Failed to resume session");
|
|
471
|
+
onStartError?.();
|
|
472
|
+
} finally {
|
|
473
|
+
setIsStarting(false);
|
|
474
|
+
}
|
|
475
|
+
}, [captureMode, bearerToken, onStart, onStartError]);
|
|
476
|
+
const disconnect = useCallback3(async () => {
|
|
477
|
+
setIsDisconnecting(true);
|
|
478
|
+
try {
|
|
479
|
+
if (sessionId && bearerToken) {
|
|
480
|
+
try {
|
|
481
|
+
await fetch(`${API_URL3}/v1/sessions/${sessionId}/complete`, {
|
|
482
|
+
method: "POST",
|
|
483
|
+
credentials: "omit",
|
|
484
|
+
headers: { "Content-Type": "application/json", Authorization: `Bearer ${bearerToken}` },
|
|
485
|
+
body: JSON.stringify({})
|
|
486
|
+
});
|
|
487
|
+
} catch {}
|
|
488
|
+
}
|
|
489
|
+
stopStream(pendingScreenStream);
|
|
490
|
+
setError("");
|
|
491
|
+
setShouldConnect(false);
|
|
492
|
+
setConnection(null);
|
|
493
|
+
setSessionId(null);
|
|
494
|
+
setPendingScreenStream(null);
|
|
495
|
+
setHistoryMessages([]);
|
|
496
|
+
setIsPaused(false);
|
|
497
|
+
onDisconnect?.();
|
|
498
|
+
await refetchResumable();
|
|
499
|
+
} finally {
|
|
500
|
+
setIsDisconnecting(false);
|
|
501
|
+
}
|
|
502
|
+
}, [sessionId, bearerToken, pendingScreenStream, onDisconnect, refetchResumable]);
|
|
298
503
|
return {
|
|
299
504
|
connection,
|
|
300
505
|
shouldConnect,
|
|
301
506
|
isStarting,
|
|
507
|
+
isDisconnecting,
|
|
302
508
|
error,
|
|
303
509
|
errorCode,
|
|
304
510
|
startSession,
|
|
511
|
+
pauseSession,
|
|
512
|
+
resumeSession,
|
|
305
513
|
disconnect,
|
|
306
|
-
|
|
514
|
+
isPaused,
|
|
515
|
+
isPausing,
|
|
516
|
+
resumableSessions,
|
|
517
|
+
historyMessages,
|
|
518
|
+
refetchResumable,
|
|
519
|
+
pendingScreenStream,
|
|
520
|
+
bearerToken
|
|
307
521
|
};
|
|
308
522
|
}
|
|
309
523
|
|
|
@@ -320,12 +534,12 @@ var NAME_MAX_CHARS = 80;
|
|
|
320
534
|
// src/components/AutoStartMedia.tsx
|
|
321
535
|
import { useConnectionState, useLocalParticipant } from "@livekit/components-react/hooks";
|
|
322
536
|
import { ConnectionState, Track } from "livekit-client";
|
|
323
|
-
import { useEffect as
|
|
537
|
+
import { useEffect as useEffect4, useRef as useRef2 } from "react";
|
|
324
538
|
function AutoStartMedia({ pendingScreenStream }) {
|
|
325
539
|
const { localParticipant } = useLocalParticipant();
|
|
326
540
|
const connectionState = useConnectionState();
|
|
327
|
-
const didStartRef =
|
|
328
|
-
|
|
541
|
+
const didStartRef = useRef2(false);
|
|
542
|
+
useEffect4(() => {
|
|
329
543
|
if (didStartRef.current)
|
|
330
544
|
return;
|
|
331
545
|
if (connectionState !== ConnectionState.Connected)
|
|
@@ -350,7 +564,7 @@ function AutoStartMedia({ pendingScreenStream }) {
|
|
|
350
564
|
// src/components/DomCapture.tsx
|
|
351
565
|
import { useConnectionState as useConnectionState2, useLocalParticipant as useLocalParticipant2 } from "@livekit/components-react/hooks";
|
|
352
566
|
import { ConnectionState as ConnectionState2, ScreenSharePresets, Track as Track2 } from "livekit-client";
|
|
353
|
-
import { useEffect as
|
|
567
|
+
import { useEffect as useEffect5, useRef as useRef3 } from "react";
|
|
354
568
|
|
|
355
569
|
// src/capture/a11yUtils.ts
|
|
356
570
|
var ROLE_BY_TAG = {
|
|
@@ -1097,8 +1311,8 @@ async function unpublishAndStopTrack(localParticipant, videoTrack) {
|
|
|
1097
1311
|
function DomCapture() {
|
|
1098
1312
|
const { localParticipant } = useLocalParticipant2();
|
|
1099
1313
|
const connectionState = useConnectionState2();
|
|
1100
|
-
const didStartRef =
|
|
1101
|
-
|
|
1314
|
+
const didStartRef = useRef3(false);
|
|
1315
|
+
useEffect5(() => {
|
|
1102
1316
|
if (didStartRef.current)
|
|
1103
1317
|
return;
|
|
1104
1318
|
if (connectionState !== ConnectionState2.Connected)
|
|
@@ -1308,28 +1522,63 @@ var __iconNode3 = [
|
|
|
1308
1522
|
["circle", { cx: "4", cy: "20", r: "2", key: "6kqj1y" }]
|
|
1309
1523
|
];
|
|
1310
1524
|
var Sparkles = createLucideIcon("sparkles", __iconNode3);
|
|
1311
|
-
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/
|
|
1525
|
+
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/bot.js
|
|
1312
1526
|
var __iconNode4 = [
|
|
1527
|
+
["path", { d: "M12 8V4H8", key: "hb8ula" }],
|
|
1528
|
+
["rect", { width: "16", height: "12", x: "4", y: "8", rx: "2", key: "enze0r" }],
|
|
1529
|
+
["path", { d: "M2 14h2", key: "vft8re" }],
|
|
1530
|
+
["path", { d: "M20 14h2", key: "4cs60a" }],
|
|
1531
|
+
["path", { d: "M15 13v2", key: "1xurst" }],
|
|
1532
|
+
["path", { d: "M9 13v2", key: "rq6x2g" }]
|
|
1533
|
+
];
|
|
1534
|
+
var Bot = createLucideIcon("bot", __iconNode4);
|
|
1535
|
+
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/calendar.js
|
|
1536
|
+
var __iconNode5 = [
|
|
1313
1537
|
["path", { d: "M8 2v4", key: "1cmpym" }],
|
|
1314
1538
|
["path", { d: "M16 2v4", key: "4m81vk" }],
|
|
1315
1539
|
["rect", { width: "18", height: "18", x: "3", y: "4", rx: "2", key: "1hopcy" }],
|
|
1316
1540
|
["path", { d: "M3 10h18", key: "8toen8" }]
|
|
1317
1541
|
];
|
|
1318
|
-
var Calendar = createLucideIcon("calendar",
|
|
1542
|
+
var Calendar = createLucideIcon("calendar", __iconNode5);
|
|
1319
1543
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/chevron-down.js
|
|
1320
|
-
var
|
|
1321
|
-
var ChevronDown = createLucideIcon("chevron-down",
|
|
1544
|
+
var __iconNode6 = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
|
|
1545
|
+
var ChevronDown = createLucideIcon("chevron-down", __iconNode6);
|
|
1322
1546
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/circle.js
|
|
1323
|
-
var
|
|
1324
|
-
var Circle = createLucideIcon("circle",
|
|
1547
|
+
var __iconNode7 = [["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }]];
|
|
1548
|
+
var Circle = createLucideIcon("circle", __iconNode7);
|
|
1549
|
+
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/graduation-cap.js
|
|
1550
|
+
var __iconNode8 = [
|
|
1551
|
+
[
|
|
1552
|
+
"path",
|
|
1553
|
+
{
|
|
1554
|
+
d: "M21.42 10.922a1 1 0 0 0-.019-1.838L12.83 5.18a2 2 0 0 0-1.66 0L2.6 9.08a1 1 0 0 0 0 1.832l8.57 3.908a2 2 0 0 0 1.66 0z",
|
|
1555
|
+
key: "j76jl0"
|
|
1556
|
+
}
|
|
1557
|
+
],
|
|
1558
|
+
["path", { d: "M22 10v6", key: "1lu8f3" }],
|
|
1559
|
+
["path", { d: "M6 12.5V16a6 3 0 0 0 12 0v-3.5", key: "1r8lef" }]
|
|
1560
|
+
];
|
|
1561
|
+
var GraduationCap = createLucideIcon("graduation-cap", __iconNode8);
|
|
1562
|
+
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/headset.js
|
|
1563
|
+
var __iconNode9 = [
|
|
1564
|
+
[
|
|
1565
|
+
"path",
|
|
1566
|
+
{
|
|
1567
|
+
d: "M3 11h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-5Zm0 0a9 9 0 1 1 18 0m0 0v5a2 2 0 0 1-2 2h-1a2 2 0 0 1-2-2v-3a2 2 0 0 1 2-2h3Z",
|
|
1568
|
+
key: "12oyoe"
|
|
1569
|
+
}
|
|
1570
|
+
],
|
|
1571
|
+
["path", { d: "M21 16v2a4 4 0 0 1-4 4h-5", key: "1x7m43" }]
|
|
1572
|
+
];
|
|
1573
|
+
var Headset = createLucideIcon("headset", __iconNode9);
|
|
1325
1574
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/mail.js
|
|
1326
|
-
var
|
|
1575
|
+
var __iconNode10 = [
|
|
1327
1576
|
["path", { d: "m22 7-8.991 5.727a2 2 0 0 1-2.009 0L2 7", key: "132q7q" }],
|
|
1328
1577
|
["rect", { x: "2", y: "4", width: "20", height: "16", rx: "2", key: "izxlao" }]
|
|
1329
1578
|
];
|
|
1330
|
-
var Mail = createLucideIcon("mail",
|
|
1579
|
+
var Mail = createLucideIcon("mail", __iconNode10);
|
|
1331
1580
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/message-circle.js
|
|
1332
|
-
var
|
|
1581
|
+
var __iconNode11 = [
|
|
1333
1582
|
[
|
|
1334
1583
|
"path",
|
|
1335
1584
|
{
|
|
@@ -1338,9 +1587,9 @@ var __iconNode8 = [
|
|
|
1338
1587
|
}
|
|
1339
1588
|
]
|
|
1340
1589
|
];
|
|
1341
|
-
var MessageCircle = createLucideIcon("message-circle",
|
|
1590
|
+
var MessageCircle = createLucideIcon("message-circle", __iconNode11);
|
|
1342
1591
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/message-square.js
|
|
1343
|
-
var
|
|
1592
|
+
var __iconNode12 = [
|
|
1344
1593
|
[
|
|
1345
1594
|
"path",
|
|
1346
1595
|
{
|
|
@@ -1349,9 +1598,9 @@ var __iconNode9 = [
|
|
|
1349
1598
|
}
|
|
1350
1599
|
]
|
|
1351
1600
|
];
|
|
1352
|
-
var MessageSquare = createLucideIcon("message-square",
|
|
1601
|
+
var MessageSquare = createLucideIcon("message-square", __iconNode12);
|
|
1353
1602
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/mic-off.js
|
|
1354
|
-
var
|
|
1603
|
+
var __iconNode13 = [
|
|
1355
1604
|
["path", { d: "M12 19v3", key: "npa21l" }],
|
|
1356
1605
|
["path", { d: "M15 9.34V5a3 3 0 0 0-5.68-1.33", key: "1gzdoj" }],
|
|
1357
1606
|
["path", { d: "M16.95 16.95A7 7 0 0 1 5 12v-2", key: "cqa7eg" }],
|
|
@@ -1359,40 +1608,40 @@ var __iconNode10 = [
|
|
|
1359
1608
|
["path", { d: "m2 2 20 20", key: "1ooewy" }],
|
|
1360
1609
|
["path", { d: "M9 9v3a3 3 0 0 0 5.12 2.12", key: "r2i35w" }]
|
|
1361
1610
|
];
|
|
1362
|
-
var MicOff = createLucideIcon("mic-off",
|
|
1611
|
+
var MicOff = createLucideIcon("mic-off", __iconNode13);
|
|
1363
1612
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/mic.js
|
|
1364
|
-
var
|
|
1613
|
+
var __iconNode14 = [
|
|
1365
1614
|
["path", { d: "M12 19v3", key: "npa21l" }],
|
|
1366
1615
|
["path", { d: "M19 10v2a7 7 0 0 1-14 0v-2", key: "1vc78b" }],
|
|
1367
1616
|
["rect", { x: "9", y: "2", width: "6", height: "13", rx: "3", key: "s6n7sd" }]
|
|
1368
1617
|
];
|
|
1369
|
-
var Mic = createLucideIcon("mic",
|
|
1618
|
+
var Mic = createLucideIcon("mic", __iconNode14);
|
|
1370
1619
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/minimize-2.js
|
|
1371
|
-
var
|
|
1620
|
+
var __iconNode15 = [
|
|
1372
1621
|
["path", { d: "m14 10 7-7", key: "oa77jy" }],
|
|
1373
1622
|
["path", { d: "M20 10h-6V4", key: "mjg0md" }],
|
|
1374
1623
|
["path", { d: "m3 21 7-7", key: "tjx5ai" }],
|
|
1375
1624
|
["path", { d: "M4 14h6v6", key: "rmj7iw" }]
|
|
1376
1625
|
];
|
|
1377
|
-
var Minimize2 = createLucideIcon("minimize-2",
|
|
1626
|
+
var Minimize2 = createLucideIcon("minimize-2", __iconNode15);
|
|
1378
1627
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/monitor-off.js
|
|
1379
|
-
var
|
|
1628
|
+
var __iconNode16 = [
|
|
1380
1629
|
["path", { d: "M12 17v4", key: "1riwvh" }],
|
|
1381
1630
|
["path", { d: "M17 17H4a2 2 0 0 1-2-2V5a2 2 0 0 1 1.184-1.826", key: "cv7jms" }],
|
|
1382
1631
|
["path", { d: "m2 2 20 20", key: "1ooewy" }],
|
|
1383
1632
|
["path", { d: "M8 21h8", key: "1ev6f3" }],
|
|
1384
1633
|
["path", { d: "M8.656 3H20a2 2 0 0 1 2 2v10a2 2 0 0 1-.293 1.042", key: "z8ni2w" }]
|
|
1385
1634
|
];
|
|
1386
|
-
var MonitorOff = createLucideIcon("monitor-off",
|
|
1635
|
+
var MonitorOff = createLucideIcon("monitor-off", __iconNode16);
|
|
1387
1636
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/monitor.js
|
|
1388
|
-
var
|
|
1637
|
+
var __iconNode17 = [
|
|
1389
1638
|
["rect", { width: "20", height: "14", x: "2", y: "3", rx: "2", key: "48i651" }],
|
|
1390
1639
|
["line", { x1: "8", x2: "16", y1: "21", y2: "21", key: "1svkeh" }],
|
|
1391
1640
|
["line", { x1: "12", x2: "12", y1: "17", y2: "21", key: "vw1qmm" }]
|
|
1392
1641
|
];
|
|
1393
|
-
var Monitor = createLucideIcon("monitor",
|
|
1642
|
+
var Monitor = createLucideIcon("monitor", __iconNode17);
|
|
1394
1643
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/mouse-pointer-2.js
|
|
1395
|
-
var
|
|
1644
|
+
var __iconNode18 = [
|
|
1396
1645
|
[
|
|
1397
1646
|
"path",
|
|
1398
1647
|
{
|
|
@@ -1401,9 +1650,15 @@ var __iconNode15 = [
|
|
|
1401
1650
|
}
|
|
1402
1651
|
]
|
|
1403
1652
|
];
|
|
1404
|
-
var MousePointer2 = createLucideIcon("mouse-pointer-2",
|
|
1653
|
+
var MousePointer2 = createLucideIcon("mouse-pointer-2", __iconNode18);
|
|
1654
|
+
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/pause.js
|
|
1655
|
+
var __iconNode19 = [
|
|
1656
|
+
["rect", { x: "14", y: "3", width: "5", height: "18", rx: "1", key: "kaeet6" }],
|
|
1657
|
+
["rect", { x: "5", y: "3", width: "5", height: "18", rx: "1", key: "1wsw3u" }]
|
|
1658
|
+
];
|
|
1659
|
+
var Pause = createLucideIcon("pause", __iconNode19);
|
|
1405
1660
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/phone-off.js
|
|
1406
|
-
var
|
|
1661
|
+
var __iconNode20 = [
|
|
1407
1662
|
[
|
|
1408
1663
|
"path",
|
|
1409
1664
|
{
|
|
@@ -1420,9 +1675,40 @@ var __iconNode16 = [
|
|
|
1420
1675
|
}
|
|
1421
1676
|
]
|
|
1422
1677
|
];
|
|
1423
|
-
var PhoneOff = createLucideIcon("phone-off",
|
|
1678
|
+
var PhoneOff = createLucideIcon("phone-off", __iconNode20);
|
|
1679
|
+
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/play.js
|
|
1680
|
+
var __iconNode21 = [
|
|
1681
|
+
[
|
|
1682
|
+
"path",
|
|
1683
|
+
{
|
|
1684
|
+
d: "M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z",
|
|
1685
|
+
key: "10ikf1"
|
|
1686
|
+
}
|
|
1687
|
+
]
|
|
1688
|
+
];
|
|
1689
|
+
var Play = createLucideIcon("play", __iconNode21);
|
|
1690
|
+
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/rocket.js
|
|
1691
|
+
var __iconNode22 = [
|
|
1692
|
+
["path", { d: "M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5", key: "qeys4" }],
|
|
1693
|
+
[
|
|
1694
|
+
"path",
|
|
1695
|
+
{
|
|
1696
|
+
d: "M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09",
|
|
1697
|
+
key: "u4xsad"
|
|
1698
|
+
}
|
|
1699
|
+
],
|
|
1700
|
+
[
|
|
1701
|
+
"path",
|
|
1702
|
+
{
|
|
1703
|
+
d: "M9 12a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.4 22.4 0 0 1-4 2z",
|
|
1704
|
+
key: "676m9"
|
|
1705
|
+
}
|
|
1706
|
+
],
|
|
1707
|
+
["path", { d: "M9 12H4s.55-3.03 2-4c1.62-1.08 5 .05 5 .05", key: "92ym6u" }]
|
|
1708
|
+
];
|
|
1709
|
+
var Rocket = createLucideIcon("rocket", __iconNode22);
|
|
1424
1710
|
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/send.js
|
|
1425
|
-
var
|
|
1711
|
+
var __iconNode23 = [
|
|
1426
1712
|
[
|
|
1427
1713
|
"path",
|
|
1428
1714
|
{
|
|
@@ -1432,9 +1718,17 @@ var __iconNode17 = [
|
|
|
1432
1718
|
],
|
|
1433
1719
|
["path", { d: "m21.854 2.147-10.94 10.939", key: "12cjpa" }]
|
|
1434
1720
|
];
|
|
1435
|
-
var Send = createLucideIcon("send",
|
|
1721
|
+
var Send = createLucideIcon("send", __iconNode23);
|
|
1722
|
+
// ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/user-plus.js
|
|
1723
|
+
var __iconNode24 = [
|
|
1724
|
+
["path", { d: "M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2", key: "1yyitq" }],
|
|
1725
|
+
["circle", { cx: "9", cy: "7", r: "4", key: "nufk8" }],
|
|
1726
|
+
["line", { x1: "19", x2: "19", y1: "8", y2: "14", key: "1bvyxn" }],
|
|
1727
|
+
["line", { x1: "22", x2: "16", y1: "11", y2: "11", key: "1shjgl" }]
|
|
1728
|
+
];
|
|
1729
|
+
var UserPlus = createLucideIcon("user-plus", __iconNode24);
|
|
1436
1730
|
// src/components/HighlightOverlay.tsx
|
|
1437
|
-
import { useCallback as
|
|
1731
|
+
import { useCallback as useCallback4, useEffect as useEffect6, useRef as useRef4, useState as useState4 } from "react";
|
|
1438
1732
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
1439
1733
|
var Z_INDEX = 2147483646;
|
|
1440
1734
|
var HIGHLIGHT_PADDING = 6;
|
|
@@ -1538,14 +1832,14 @@ function findScrollableAncestor(el) {
|
|
|
1538
1832
|
return el.ownerDocument?.documentElement ?? document.documentElement;
|
|
1539
1833
|
}
|
|
1540
1834
|
function HighlightOverlay() {
|
|
1541
|
-
const [overlayState, setOverlayState] =
|
|
1542
|
-
const targetElementRef =
|
|
1543
|
-
const pendingFrameRef =
|
|
1544
|
-
const clearOverlay =
|
|
1835
|
+
const [overlayState, setOverlayState] = useState4(null);
|
|
1836
|
+
const targetElementRef = useRef4(null);
|
|
1837
|
+
const pendingFrameRef = useRef4(null);
|
|
1838
|
+
const clearOverlay = useCallback4(() => {
|
|
1545
1839
|
targetElementRef.current = null;
|
|
1546
1840
|
setOverlayState(null);
|
|
1547
1841
|
}, []);
|
|
1548
|
-
const recomputeRect =
|
|
1842
|
+
const recomputeRect = useCallback4(() => {
|
|
1549
1843
|
pendingFrameRef.current = null;
|
|
1550
1844
|
const target = targetElementRef.current;
|
|
1551
1845
|
if (!target)
|
|
@@ -1557,12 +1851,12 @@ function HighlightOverlay() {
|
|
|
1557
1851
|
const rect2 = getRectInTopViewport(target);
|
|
1558
1852
|
setOverlayState((prev) => prev ? { ...prev, rect: rect2 } : prev);
|
|
1559
1853
|
}, [clearOverlay]);
|
|
1560
|
-
const scheduleRecompute =
|
|
1854
|
+
const scheduleRecompute = useCallback4(() => {
|
|
1561
1855
|
if (pendingFrameRef.current !== null)
|
|
1562
1856
|
return;
|
|
1563
1857
|
pendingFrameRef.current = window.requestAnimationFrame(recomputeRect);
|
|
1564
1858
|
}, [recomputeRect]);
|
|
1565
|
-
const onHighlightMessage =
|
|
1859
|
+
const onHighlightMessage = useCallback4((msg) => {
|
|
1566
1860
|
const parsed = parseHighlightMessage(msg.payload);
|
|
1567
1861
|
if (!parsed)
|
|
1568
1862
|
return;
|
|
@@ -1583,7 +1877,7 @@ function HighlightOverlay() {
|
|
|
1583
1877
|
});
|
|
1584
1878
|
}, [clearOverlay]);
|
|
1585
1879
|
useDataChannel(HIGHLIGHT_TOPIC, onHighlightMessage);
|
|
1586
|
-
|
|
1880
|
+
useEffect6(() => {
|
|
1587
1881
|
if (!overlayState)
|
|
1588
1882
|
return;
|
|
1589
1883
|
const target = targetElementRef.current;
|
|
@@ -1665,23 +1959,36 @@ function HighlightOverlay() {
|
|
|
1665
1959
|
}
|
|
1666
1960
|
|
|
1667
1961
|
// src/components/MinimizedBubble.tsx
|
|
1668
|
-
import { useEffect as
|
|
1962
|
+
import { useEffect as useEffect7 } from "react";
|
|
1963
|
+
|
|
1964
|
+
// src/lib/react-compat.ts
|
|
1965
|
+
import * as React from "react";
|
|
1966
|
+
function selectContextHook(use2, useContext3) {
|
|
1967
|
+
return use2 ?? useContext3;
|
|
1968
|
+
}
|
|
1969
|
+
var useContextValue = selectContextHook(React.use, React.useContext);
|
|
1669
1970
|
|
|
1670
1971
|
// src/hooks/useLiveAgent.ts
|
|
1671
|
-
import { use } from "react";
|
|
1672
1972
|
function useLiveAgent() {
|
|
1673
|
-
const ctx =
|
|
1973
|
+
const ctx = useContextValue(LiveAgentContext);
|
|
1674
1974
|
if (!ctx) {
|
|
1675
1975
|
throw new Error("useLiveAgent must be used within a <LiveAgent> provider");
|
|
1676
1976
|
}
|
|
1677
|
-
const {
|
|
1977
|
+
const {
|
|
1978
|
+
connection,
|
|
1979
|
+
shouldConnect,
|
|
1980
|
+
historyMessages,
|
|
1981
|
+
phasesSnapshot,
|
|
1982
|
+
setPhasesSnapshot,
|
|
1983
|
+
...publicValue
|
|
1984
|
+
} = ctx;
|
|
1678
1985
|
return publicValue;
|
|
1679
1986
|
}
|
|
1680
1987
|
|
|
1681
1988
|
// src/hooks/useMediaControls.ts
|
|
1682
1989
|
import { useLocalParticipant as useLocalParticipant3 } from "@livekit/components-react/hooks";
|
|
1683
1990
|
import { ScreenSharePresets as ScreenSharePresets2 } from "livekit-client";
|
|
1684
|
-
import { useCallback as
|
|
1991
|
+
import { useCallback as useCallback5 } from "react";
|
|
1685
1992
|
var SCREEN_SHARE_OPTIONS = {
|
|
1686
1993
|
video: { displaySurface: "browser" },
|
|
1687
1994
|
resolution: ScreenSharePresets2.h720fps30.resolution,
|
|
@@ -1691,14 +1998,14 @@ function useMediaControls() {
|
|
|
1691
1998
|
const { localParticipant } = useLocalParticipant3();
|
|
1692
1999
|
const isMuted = !localParticipant.isMicrophoneEnabled;
|
|
1693
2000
|
const isScreenSharing = localParticipant.isScreenShareEnabled;
|
|
1694
|
-
const toggleMute =
|
|
2001
|
+
const toggleMute = useCallback5(async () => {
|
|
1695
2002
|
try {
|
|
1696
2003
|
await localParticipant.setMicrophoneEnabled(isMuted);
|
|
1697
2004
|
} catch (error) {
|
|
1698
2005
|
console.error("Failed to toggle microphone:", error);
|
|
1699
2006
|
}
|
|
1700
2007
|
}, [localParticipant, isMuted]);
|
|
1701
|
-
const toggleScreenShare =
|
|
2008
|
+
const toggleScreenShare = useCallback5(async () => {
|
|
1702
2009
|
try {
|
|
1703
2010
|
await localParticipant.setScreenShareEnabled(!isScreenSharing, SCREEN_SHARE_OPTIONS);
|
|
1704
2011
|
} catch (error) {
|
|
@@ -1736,25 +2043,50 @@ function pillStatusFromAgent(state, canSeePage) {
|
|
|
1736
2043
|
return canSeePage ? "observing" : "connected";
|
|
1737
2044
|
}
|
|
1738
2045
|
function LauncherStatusPill() {
|
|
1739
|
-
const { isConnected, expandPanel, setSidebarTab, position, captureMode } = useLiveAgent();
|
|
2046
|
+
const { isConnected, isStarting, isPaused, expandPanel, setSidebarTab, position, captureMode } = useLiveAgent();
|
|
1740
2047
|
const { state } = useAgentVoiceState();
|
|
1741
2048
|
const { isScreenSharing } = useMediaControls();
|
|
1742
|
-
|
|
2049
|
+
const isStandingBy = isStarting && !isConnected;
|
|
2050
|
+
if (!isConnected && !isStandingBy && !isPaused)
|
|
1743
2051
|
return null;
|
|
1744
2052
|
const canSeePage = captureMode === "auto" || isScreenSharing;
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
2053
|
+
let status;
|
|
2054
|
+
if (isPaused) {
|
|
2055
|
+
status = "paused";
|
|
2056
|
+
} else if (isStandingBy) {
|
|
2057
|
+
status = "standing-by";
|
|
2058
|
+
} else {
|
|
2059
|
+
status = pillStatusFromAgent(state, canSeePage);
|
|
2060
|
+
}
|
|
2061
|
+
let ariaLabel;
|
|
2062
|
+
if (isStandingBy) {
|
|
2063
|
+
ariaLabel = "Skippr is standing by — click to open";
|
|
2064
|
+
} else if (isPaused) {
|
|
2065
|
+
ariaLabel = "Session paused — click to open";
|
|
2066
|
+
} else {
|
|
2067
|
+
ariaLabel = `Skippr is ${status} — click to open chat`;
|
|
2068
|
+
}
|
|
2069
|
+
const handleClick = () => {
|
|
2070
|
+
if (!isStandingBy)
|
|
2071
|
+
setSidebarTab("chat");
|
|
1748
2072
|
expandPanel();
|
|
1749
2073
|
};
|
|
1750
2074
|
return /* @__PURE__ */ jsx2("button", {
|
|
1751
2075
|
type: "button",
|
|
1752
|
-
onClick:
|
|
2076
|
+
onClick: handleClick,
|
|
1753
2077
|
className: cn("skippr:fixed skippr:bottom-20 skippr:z-[9999]", "skippr:flex skippr:items-center skippr:gap-2", "skippr:rounded-full skippr:bg-bubble/95 skippr:backdrop-blur-sm", "skippr:px-3 skippr:py-1.5", "skippr:text-xs skippr:font-medium skippr:text-white", "skippr:shadow-[0_8px_24px_rgba(45,43,61,0.35)]", "skippr:cursor-pointer skippr:transition-colors skippr:hover:bg-bubble", "skippr:animate-[skippr-bubble-in_0.28s_ease-out]", position === "right" ? "skippr:right-6" : "skippr:left-6"),
|
|
1754
|
-
"aria-label":
|
|
2078
|
+
"aria-label": ariaLabel,
|
|
1755
2079
|
children: /* @__PURE__ */ jsxs2("span", {
|
|
1756
2080
|
className: "skippr:flex skippr:items-center skippr:gap-2 skippr:animate-[skippr-pill-content_0.22s_ease-out]",
|
|
1757
2081
|
children: [
|
|
2082
|
+
status === "standing-by" && /* @__PURE__ */ jsxs2(Fragment, {
|
|
2083
|
+
children: [
|
|
2084
|
+
/* @__PURE__ */ jsx2("span", {
|
|
2085
|
+
children: "Standing by"
|
|
2086
|
+
}),
|
|
2087
|
+
/* @__PURE__ */ jsx2(ThinkingDots, {})
|
|
2088
|
+
]
|
|
2089
|
+
}),
|
|
1758
2090
|
status === "observing" && /* @__PURE__ */ jsxs2(Fragment, {
|
|
1759
2091
|
children: [
|
|
1760
2092
|
/* @__PURE__ */ jsx2(ObservingIcon, {}),
|
|
@@ -1786,6 +2118,14 @@ function LauncherStatusPill() {
|
|
|
1786
2118
|
children: "Skippr is thinking"
|
|
1787
2119
|
})
|
|
1788
2120
|
]
|
|
2121
|
+
}),
|
|
2122
|
+
status === "paused" && /* @__PURE__ */ jsxs2(Fragment, {
|
|
2123
|
+
children: [
|
|
2124
|
+
/* @__PURE__ */ jsx2(PausedDot, {}),
|
|
2125
|
+
/* @__PURE__ */ jsx2("span", {
|
|
2126
|
+
children: "Session paused"
|
|
2127
|
+
})
|
|
2128
|
+
]
|
|
1789
2129
|
})
|
|
1790
2130
|
]
|
|
1791
2131
|
}, status)
|
|
@@ -1804,6 +2144,11 @@ function ConnectedDot() {
|
|
|
1804
2144
|
]
|
|
1805
2145
|
});
|
|
1806
2146
|
}
|
|
2147
|
+
function PausedDot() {
|
|
2148
|
+
return /* @__PURE__ */ jsx2("span", {
|
|
2149
|
+
className: "skippr:inline-flex skippr:size-2 skippr:rounded-full skippr:bg-amber-400"
|
|
2150
|
+
});
|
|
2151
|
+
}
|
|
1807
2152
|
function ObservingIcon() {
|
|
1808
2153
|
return /* @__PURE__ */ jsxs2("svg", {
|
|
1809
2154
|
viewBox: "0 0 24 24",
|
|
@@ -1955,34 +2300,60 @@ import { jsx as jsx4, jsxs as jsxs4, Fragment as Fragment2 } from "react/jsx-run
|
|
|
1955
2300
|
var CONTROL_BUTTON = "skippr:flex skippr:size-12 skippr:items-center skippr:justify-center skippr:rounded-[14px] skippr:cursor-pointer skippr:transition-all skippr:hover:-translate-y-0.5 skippr:active:translate-y-0";
|
|
1956
2301
|
var CONTROL_SHADOW = "skippr:shadow-[0_4px_16px_rgba(0,0,0,0.15),0_2px_4px_rgba(0,0,0,0.1)]";
|
|
1957
2302
|
function ConnectedLauncher() {
|
|
1958
|
-
const {
|
|
2303
|
+
const {
|
|
2304
|
+
expandPanel,
|
|
2305
|
+
disconnect,
|
|
2306
|
+
pauseSession,
|
|
2307
|
+
resumeSession,
|
|
2308
|
+
isPaused,
|
|
2309
|
+
isPausing,
|
|
2310
|
+
captureMode,
|
|
2311
|
+
setSidebarTab
|
|
2312
|
+
} = useLiveAgent();
|
|
1959
2313
|
const { isMuted, toggleMute, isScreenSharing, toggleScreenShare } = useMediaControls();
|
|
1960
2314
|
const showScreenShareToggle = captureMode === "screenshare";
|
|
2315
|
+
const showPaused = isPaused || isPausing;
|
|
1961
2316
|
const openChat = () => {
|
|
1962
2317
|
setSidebarTab("chat");
|
|
1963
2318
|
expandPanel();
|
|
1964
2319
|
};
|
|
1965
2320
|
return /* @__PURE__ */ jsxs4(Fragment2, {
|
|
1966
2321
|
children: [
|
|
1967
|
-
/* @__PURE__ */
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
2322
|
+
!showPaused && /* @__PURE__ */ jsxs4(Fragment2, {
|
|
2323
|
+
children: [
|
|
2324
|
+
/* @__PURE__ */ jsx4("button", {
|
|
2325
|
+
type: "button",
|
|
2326
|
+
onClick: toggleMute,
|
|
2327
|
+
"aria-label": isMuted ? "Unmute" : "Mute",
|
|
2328
|
+
className: cn(CONTROL_BUTTON, CONTROL_SHADOW, isMuted ? "skippr:bg-destructive/10 skippr:text-destructive skippr:hover:bg-destructive/20" : "skippr:bg-white skippr:text-foreground skippr:hover:bg-muted"),
|
|
2329
|
+
children: isMuted ? /* @__PURE__ */ jsx4(MicOff, {
|
|
2330
|
+
className: "skippr:size-5"
|
|
2331
|
+
}) : /* @__PURE__ */ jsx4(Mic, {
|
|
2332
|
+
className: "skippr:size-5"
|
|
2333
|
+
})
|
|
2334
|
+
}),
|
|
2335
|
+
showScreenShareToggle && /* @__PURE__ */ jsx4("button", {
|
|
2336
|
+
type: "button",
|
|
2337
|
+
onClick: toggleScreenShare,
|
|
2338
|
+
"aria-label": isScreenSharing ? "Stop sharing screen" : "Share screen",
|
|
2339
|
+
className: cn(CONTROL_BUTTON, CONTROL_SHADOW, isScreenSharing ? "skippr:bg-primary skippr:text-primary-foreground skippr:hover:bg-primary/90" : "skippr:bg-white skippr:text-foreground skippr:hover:bg-muted"),
|
|
2340
|
+
children: isScreenSharing ? /* @__PURE__ */ jsx4(MonitorOff, {
|
|
2341
|
+
className: "skippr:size-5"
|
|
2342
|
+
}) : /* @__PURE__ */ jsx4(Monitor, {
|
|
2343
|
+
className: "skippr:size-5"
|
|
2344
|
+
})
|
|
2345
|
+
})
|
|
2346
|
+
]
|
|
1977
2347
|
}),
|
|
1978
|
-
|
|
2348
|
+
/* @__PURE__ */ jsx4("button", {
|
|
1979
2349
|
type: "button",
|
|
1980
|
-
onClick:
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
2350
|
+
onClick: () => isPaused ? resumeSession() : pauseSession(),
|
|
2351
|
+
disabled: isPausing,
|
|
2352
|
+
"aria-label": showPaused ? "Resume session" : "Pause session",
|
|
2353
|
+
className: cn(CONTROL_BUTTON, CONTROL_SHADOW, "skippr:bg-white skippr:text-foreground skippr:hover:bg-muted skippr:disabled:opacity-60"),
|
|
2354
|
+
children: showPaused ? /* @__PURE__ */ jsx4(Play, {
|
|
1984
2355
|
className: "skippr:size-5"
|
|
1985
|
-
}) : /* @__PURE__ */ jsx4(
|
|
2356
|
+
}) : /* @__PURE__ */ jsx4(Pause, {
|
|
1986
2357
|
className: "skippr:size-5"
|
|
1987
2358
|
})
|
|
1988
2359
|
}),
|
|
@@ -1995,7 +2366,7 @@ function ConnectedLauncher() {
|
|
|
1995
2366
|
className: "skippr:size-5"
|
|
1996
2367
|
})
|
|
1997
2368
|
}),
|
|
1998
|
-
/* @__PURE__ */ jsx4("button", {
|
|
2369
|
+
!showPaused && /* @__PURE__ */ jsx4("button", {
|
|
1999
2370
|
type: "button",
|
|
2000
2371
|
onClick: openChat,
|
|
2001
2372
|
"aria-label": "Open chat",
|
|
@@ -2024,7 +2395,7 @@ function WelcomeBubble({
|
|
|
2024
2395
|
position,
|
|
2025
2396
|
onDismiss
|
|
2026
2397
|
}) {
|
|
2027
|
-
|
|
2398
|
+
useEffect7(() => {
|
|
2028
2399
|
const timer = setTimeout(onDismiss, 5000);
|
|
2029
2400
|
return () => clearTimeout(timer);
|
|
2030
2401
|
}, [onDismiss]);
|
|
@@ -2046,15 +2417,15 @@ function MinimizedBubble({
|
|
|
2046
2417
|
welcomeDismissed,
|
|
2047
2418
|
onDismissWelcome
|
|
2048
2419
|
}) {
|
|
2049
|
-
const { isConnected, isStarting, position } = useLiveAgent();
|
|
2050
|
-
const inSession = isConnected ||
|
|
2420
|
+
const { isConnected, isStarting, isPaused, isPausing, position } = useLiveAgent();
|
|
2421
|
+
const inSession = isConnected || isPaused || isPausing;
|
|
2051
2422
|
return /* @__PURE__ */ jsxs4(Fragment2, {
|
|
2052
2423
|
children: [
|
|
2053
2424
|
/* @__PURE__ */ jsx4(LauncherStatusPill, {}),
|
|
2054
2425
|
/* @__PURE__ */ jsxs4("div", {
|
|
2055
2426
|
className: cn("skippr:fixed skippr:bottom-6 skippr:z-[9999]", "skippr:flex skippr:items-center skippr:gap-2", position === "right" ? "skippr:right-6" : "skippr:left-6"),
|
|
2056
2427
|
children: [
|
|
2057
|
-
welcomeMessage && !
|
|
2428
|
+
welcomeMessage && !isConnected && !isStarting && !welcomeDismissed && /* @__PURE__ */ jsx4(WelcomeBubble, {
|
|
2058
2429
|
message: welcomeMessage,
|
|
2059
2430
|
position,
|
|
2060
2431
|
onDismiss: onDismissWelcome
|
|
@@ -2067,7 +2438,7 @@ function MinimizedBubble({
|
|
|
2067
2438
|
}
|
|
2068
2439
|
|
|
2069
2440
|
// src/components/Sidebar.tsx
|
|
2070
|
-
import { useEffect as
|
|
2441
|
+
import { useEffect as useEffect16 } from "react";
|
|
2071
2442
|
|
|
2072
2443
|
// src/hooks/useCombinedMessages.ts
|
|
2073
2444
|
import { useMemo as useMemo4 } from "react";
|
|
@@ -2138,26 +2509,33 @@ function useCombinedMessages() {
|
|
|
2138
2509
|
const { transcriptMessages } = useStreamingTranscript();
|
|
2139
2510
|
const { chatMessages, sendChatMessage, isSendingChat } = useChatMessages();
|
|
2140
2511
|
const { state: agentState } = useAgentVoiceState();
|
|
2141
|
-
const
|
|
2512
|
+
const historyMessages = useContextValue(LiveAgentContext)?.historyMessages ?? [];
|
|
2513
|
+
const liveMessages = useMemo4(() => {
|
|
2142
2514
|
if (chatMessages.length === 0)
|
|
2143
2515
|
return transcriptMessages;
|
|
2144
2516
|
if (transcriptMessages.length === 0)
|
|
2145
2517
|
return chatMessages;
|
|
2146
2518
|
return mergeChatsIntoTranscripts(transcriptMessages, chatMessages);
|
|
2147
2519
|
}, [transcriptMessages, chatMessages]);
|
|
2520
|
+
const allMessages = useMemo4(() => {
|
|
2521
|
+
if (historyMessages.length === 0)
|
|
2522
|
+
return liveMessages;
|
|
2523
|
+
const seenIds = new Set(liveMessages.map((message) => message.id));
|
|
2524
|
+
return [...historyMessages.filter((message) => !seenIds.has(message.id)), ...liveMessages];
|
|
2525
|
+
}, [historyMessages, liveMessages]);
|
|
2148
2526
|
return { allMessages, agentState, sendChatMessage, isSendingChat };
|
|
2149
2527
|
}
|
|
2150
2528
|
|
|
2151
2529
|
// src/hooks/usePhaseUpdates.ts
|
|
2152
|
-
import { useCallback as
|
|
2530
|
+
import { useCallback as useCallback6, useEffect as useEffect9 } from "react";
|
|
2153
2531
|
|
|
2154
2532
|
// src/hooks/useAgentState.ts
|
|
2155
2533
|
import { useRemoteParticipants } from "@livekit/components-react/hooks";
|
|
2156
|
-
import { useEffect as
|
|
2534
|
+
import { useEffect as useEffect8, useState as useState5 } from "react";
|
|
2157
2535
|
function useAgentState(attributeKey, parse, initial) {
|
|
2158
|
-
const [value, setValue] =
|
|
2536
|
+
const [value, setValue] = useState5(initial);
|
|
2159
2537
|
const remoteParticipants = useRemoteParticipants();
|
|
2160
|
-
|
|
2538
|
+
useEffect8(() => {
|
|
2161
2539
|
const agentParticipant = remoteParticipants.find((p) => p.attributes?.[attributeKey]);
|
|
2162
2540
|
if (agentParticipant) {
|
|
2163
2541
|
const attr = agentParticipant.attributes?.[attributeKey];
|
|
@@ -2203,13 +2581,19 @@ function parsePhases(json) {
|
|
|
2203
2581
|
return null;
|
|
2204
2582
|
}
|
|
2205
2583
|
function usePhaseUpdates() {
|
|
2206
|
-
const parse =
|
|
2207
|
-
const
|
|
2584
|
+
const parse = useCallback6(parsePhases, []);
|
|
2585
|
+
const livePhases = useAgentState("phases", parse, []);
|
|
2586
|
+
const ctx = useContextValue(LiveAgentContext);
|
|
2587
|
+
useEffect9(() => {
|
|
2588
|
+
if (livePhases.length > 0)
|
|
2589
|
+
ctx?.setPhasesSnapshot(livePhases);
|
|
2590
|
+
}, [livePhases, ctx?.setPhasesSnapshot]);
|
|
2591
|
+
const phases = livePhases.length > 0 ? livePhases : ctx?.phasesSnapshot ?? [];
|
|
2208
2592
|
return { phases };
|
|
2209
2593
|
}
|
|
2210
2594
|
|
|
2211
2595
|
// src/hooks/useSessionRemaining.ts
|
|
2212
|
-
import { useEffect as
|
|
2596
|
+
import { useEffect as useEffect10, useRef as useRef5, useState as useState6 } from "react";
|
|
2213
2597
|
|
|
2214
2598
|
// src/lib/format.ts
|
|
2215
2599
|
function formatTime(seconds) {
|
|
@@ -2225,9 +2609,9 @@ function parseNumber(s) {
|
|
|
2225
2609
|
// src/hooks/useSessionRemaining.ts
|
|
2226
2610
|
function useSessionRemaining() {
|
|
2227
2611
|
const maxCallDuration = useAgentState("maxCallDuration", parseNumber, null);
|
|
2228
|
-
const endTimeRef =
|
|
2229
|
-
const [remaining, setRemaining] =
|
|
2230
|
-
|
|
2612
|
+
const endTimeRef = useRef5(null);
|
|
2613
|
+
const [remaining, setRemaining] = useState6(null);
|
|
2614
|
+
useEffect10(() => {
|
|
2231
2615
|
if (maxCallDuration === null || endTimeRef.current !== null)
|
|
2232
2616
|
return;
|
|
2233
2617
|
const endTime = Date.now() + maxCallDuration * 1000;
|
|
@@ -2244,10 +2628,10 @@ function useSessionRemaining() {
|
|
|
2244
2628
|
}
|
|
2245
2629
|
|
|
2246
2630
|
// src/hooks/useElapsedSeconds.ts
|
|
2247
|
-
import { useEffect as
|
|
2631
|
+
import { useEffect as useEffect11, useState as useState7 } from "react";
|
|
2248
2632
|
function useElapsedSeconds(isRunning) {
|
|
2249
|
-
const [elapsed, setElapsed] =
|
|
2250
|
-
|
|
2633
|
+
const [elapsed, setElapsed] = useState7(0);
|
|
2634
|
+
useEffect11(() => {
|
|
2251
2635
|
if (!isRunning) {
|
|
2252
2636
|
setElapsed(0);
|
|
2253
2637
|
return;
|
|
@@ -2345,7 +2729,7 @@ function LoadingDots({ label }) {
|
|
|
2345
2729
|
}
|
|
2346
2730
|
|
|
2347
2731
|
// src/components/LoginFlow.tsx
|
|
2348
|
-
import { useCallback as
|
|
2732
|
+
import { useCallback as useCallback7, useEffect as useEffect12, useRef as useRef6, useState as useState8 } from "react";
|
|
2349
2733
|
|
|
2350
2734
|
// src/components/ui/button.tsx
|
|
2351
2735
|
import { forwardRef as forwardRef3 } from "react";
|
|
@@ -2381,20 +2765,20 @@ import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
|
2381
2765
|
var OTP_LENGTH = 6;
|
|
2382
2766
|
var DIGIT_KEYS = ["d0", "d1", "d2", "d3", "d4", "d5"];
|
|
2383
2767
|
function LoginFlow({ requestOtp, verifyOtp, error, isSubmitting }) {
|
|
2384
|
-
const [step, setStep] =
|
|
2385
|
-
const [email, setEmail] =
|
|
2386
|
-
const handleRequestOtp =
|
|
2768
|
+
const [step, setStep] = useState8("email");
|
|
2769
|
+
const [email, setEmail] = useState8("");
|
|
2770
|
+
const handleRequestOtp = useCallback7(async (emailValue) => {
|
|
2387
2771
|
const success = await requestOtp(emailValue);
|
|
2388
2772
|
if (success)
|
|
2389
2773
|
setStep("otp");
|
|
2390
2774
|
}, [requestOtp]);
|
|
2391
|
-
const handleVerifyOtp =
|
|
2775
|
+
const handleVerifyOtp = useCallback7(async (code) => {
|
|
2392
2776
|
await verifyOtp(email, code);
|
|
2393
2777
|
}, [verifyOtp, email]);
|
|
2394
|
-
const handleBack =
|
|
2778
|
+
const handleBack = useCallback7(() => {
|
|
2395
2779
|
setStep("email");
|
|
2396
2780
|
}, []);
|
|
2397
|
-
const handleResend =
|
|
2781
|
+
const handleResend = useCallback7(async () => {
|
|
2398
2782
|
await requestOtp(email);
|
|
2399
2783
|
}, [requestOtp, email]);
|
|
2400
2784
|
if (step === "otp") {
|
|
@@ -2471,30 +2855,30 @@ function EmailStep({ email, onEmailChange, onSubmit, error, isSubmitting }) {
|
|
|
2471
2855
|
});
|
|
2472
2856
|
}
|
|
2473
2857
|
function OtpStep({ email, onSubmit, onResend, onBack, error, isSubmitting }) {
|
|
2474
|
-
const [digits, setDigits] =
|
|
2475
|
-
const [resendCooldown, setResendCooldown] =
|
|
2476
|
-
const inputRefs =
|
|
2477
|
-
const submittedRef =
|
|
2478
|
-
|
|
2858
|
+
const [digits, setDigits] = useState8(Array(OTP_LENGTH).fill(""));
|
|
2859
|
+
const [resendCooldown, setResendCooldown] = useState8(0);
|
|
2860
|
+
const inputRefs = useRef6([]);
|
|
2861
|
+
const submittedRef = useRef6(false);
|
|
2862
|
+
useEffect12(() => {
|
|
2479
2863
|
inputRefs.current[0]?.focus();
|
|
2480
2864
|
}, []);
|
|
2481
|
-
|
|
2865
|
+
useEffect12(() => {
|
|
2482
2866
|
if (error)
|
|
2483
2867
|
submittedRef.current = false;
|
|
2484
2868
|
}, [error]);
|
|
2485
|
-
|
|
2869
|
+
useEffect12(() => {
|
|
2486
2870
|
if (resendCooldown <= 0)
|
|
2487
2871
|
return;
|
|
2488
2872
|
const timer = setTimeout(() => setResendCooldown((c) => c - 1), 1000);
|
|
2489
2873
|
return () => clearTimeout(timer);
|
|
2490
2874
|
}, [resendCooldown]);
|
|
2491
|
-
const submitCode =
|
|
2875
|
+
const submitCode = useCallback7((code) => {
|
|
2492
2876
|
if (submittedRef.current || isSubmitting)
|
|
2493
2877
|
return;
|
|
2494
2878
|
submittedRef.current = true;
|
|
2495
2879
|
onSubmit(code);
|
|
2496
2880
|
}, [onSubmit, isSubmitting]);
|
|
2497
|
-
const handleDigitChange =
|
|
2881
|
+
const handleDigitChange = useCallback7((index2, value) => {
|
|
2498
2882
|
const digit = value.replace(/\D/g, "").slice(-1);
|
|
2499
2883
|
const newDigits = [...digits];
|
|
2500
2884
|
newDigits[index2] = digit;
|
|
@@ -2508,12 +2892,12 @@ function OtpStep({ email, onSubmit, onResend, onBack, error, isSubmitting }) {
|
|
|
2508
2892
|
submitCode(code);
|
|
2509
2893
|
}
|
|
2510
2894
|
}, [digits, submitCode]);
|
|
2511
|
-
const handleKeyDown =
|
|
2895
|
+
const handleKeyDown = useCallback7((index2, e) => {
|
|
2512
2896
|
if (e.key === "Backspace" && !digits[index2] && index2 > 0) {
|
|
2513
2897
|
inputRefs.current[index2 - 1]?.focus();
|
|
2514
2898
|
}
|
|
2515
2899
|
}, [digits]);
|
|
2516
|
-
const handlePaste =
|
|
2900
|
+
const handlePaste = useCallback7((e) => {
|
|
2517
2901
|
e.preventDefault();
|
|
2518
2902
|
const pasted = e.clipboardData.getData("text").replace(/\D/g, "").slice(0, OTP_LENGTH);
|
|
2519
2903
|
if (pasted.length > 0) {
|
|
@@ -2623,35 +3007,66 @@ function OtpStep({ email, onSubmit, onResend, onBack, error, isSubmitting }) {
|
|
|
2623
3007
|
}
|
|
2624
3008
|
|
|
2625
3009
|
// src/components/MeetingControls.tsx
|
|
2626
|
-
import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
2627
|
-
var CONTROL_BUTTON2 = "skippr:flex skippr:size-11 skippr:cursor-pointer skippr:items-center skippr:justify-center skippr:rounded-full skippr:transition-colors";
|
|
2628
|
-
|
|
3010
|
+
import { jsx as jsx9, jsxs as jsxs8, Fragment as Fragment3 } from "react/jsx-runtime";
|
|
3011
|
+
var CONTROL_BUTTON2 = "skippr:flex skippr:size-11 skippr:cursor-pointer skippr:items-center skippr:justify-center skippr:rounded-full skippr:transition-colors skippr:disabled:cursor-not-allowed skippr:disabled:opacity-60";
|
|
3012
|
+
var MUTED_BUTTON = "skippr:bg-muted skippr:text-foreground skippr:hover:bg-muted/80";
|
|
3013
|
+
function MeetingControls({
|
|
3014
|
+
onHangUp,
|
|
3015
|
+
onPause,
|
|
3016
|
+
onResume,
|
|
3017
|
+
isPaused = false,
|
|
3018
|
+
isPausing = false,
|
|
3019
|
+
showScreenShareToggle = true
|
|
3020
|
+
}) {
|
|
2629
3021
|
const { isMuted, toggleMute, isScreenSharing, toggleScreenShare } = useMediaControls();
|
|
3022
|
+
const showPaused = isPaused || isPausing;
|
|
2630
3023
|
return /* @__PURE__ */ jsxs8("div", {
|
|
2631
3024
|
className: "skippr:shrink-0 skippr:border-t skippr:border-border skippr:bg-background skippr:px-4 skippr:py-4",
|
|
2632
3025
|
children: [
|
|
2633
3026
|
/* @__PURE__ */ jsxs8("div", {
|
|
2634
3027
|
className: "skippr:flex skippr:items-center skippr:justify-center skippr:gap-3",
|
|
2635
3028
|
children: [
|
|
2636
|
-
/* @__PURE__ */
|
|
3029
|
+
!showPaused && /* @__PURE__ */ jsxs8(Fragment3, {
|
|
3030
|
+
children: [
|
|
3031
|
+
/* @__PURE__ */ jsx9("button", {
|
|
3032
|
+
type: "button",
|
|
3033
|
+
onClick: toggleMute,
|
|
3034
|
+
"aria-label": isMuted ? "Unmute" : "Mute",
|
|
3035
|
+
className: cn(CONTROL_BUTTON2, isMuted ? "skippr:bg-destructive/15 skippr:text-destructive skippr:hover:bg-destructive/25" : MUTED_BUTTON),
|
|
3036
|
+
children: isMuted ? /* @__PURE__ */ jsx9(MicOff, {
|
|
3037
|
+
className: "skippr:size-5"
|
|
3038
|
+
}) : /* @__PURE__ */ jsx9(Mic, {
|
|
3039
|
+
className: "skippr:size-5"
|
|
3040
|
+
})
|
|
3041
|
+
}),
|
|
3042
|
+
showScreenShareToggle && /* @__PURE__ */ jsx9("button", {
|
|
3043
|
+
type: "button",
|
|
3044
|
+
onClick: toggleScreenShare,
|
|
3045
|
+
"aria-label": isScreenSharing ? "Stop sharing screen" : "Share screen",
|
|
3046
|
+
className: cn(CONTROL_BUTTON2, isScreenSharing ? "skippr:bg-bubble skippr:text-white skippr:hover:brightness-110" : MUTED_BUTTON),
|
|
3047
|
+
children: isScreenSharing ? /* @__PURE__ */ jsx9(MonitorOff, {
|
|
3048
|
+
className: "skippr:size-5"
|
|
3049
|
+
}) : /* @__PURE__ */ jsx9(Monitor, {
|
|
3050
|
+
className: "skippr:size-5"
|
|
3051
|
+
})
|
|
3052
|
+
})
|
|
3053
|
+
]
|
|
3054
|
+
}),
|
|
3055
|
+
showPaused ? onResume && /* @__PURE__ */ jsx9("button", {
|
|
2637
3056
|
type: "button",
|
|
2638
|
-
onClick:
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
}) : /* @__PURE__ */ jsx9(Mic, {
|
|
3057
|
+
onClick: onResume,
|
|
3058
|
+
disabled: isPausing,
|
|
3059
|
+
"aria-label": "Resume session",
|
|
3060
|
+
className: cn(CONTROL_BUTTON2, MUTED_BUTTON),
|
|
3061
|
+
children: /* @__PURE__ */ jsx9(Play, {
|
|
2644
3062
|
className: "skippr:size-5"
|
|
2645
3063
|
})
|
|
2646
|
-
}),
|
|
2647
|
-
showScreenShareToggle && /* @__PURE__ */ jsx9("button", {
|
|
3064
|
+
}) : onPause && /* @__PURE__ */ jsx9("button", {
|
|
2648
3065
|
type: "button",
|
|
2649
|
-
onClick:
|
|
2650
|
-
"aria-label":
|
|
2651
|
-
className: cn(CONTROL_BUTTON2,
|
|
2652
|
-
children:
|
|
2653
|
-
className: "skippr:size-5"
|
|
2654
|
-
}) : /* @__PURE__ */ jsx9(Monitor, {
|
|
3066
|
+
onClick: onPause,
|
|
3067
|
+
"aria-label": "Pause session",
|
|
3068
|
+
className: cn(CONTROL_BUTTON2, MUTED_BUTTON),
|
|
3069
|
+
children: /* @__PURE__ */ jsx9(Pause, {
|
|
2655
3070
|
className: "skippr:size-5"
|
|
2656
3071
|
})
|
|
2657
3072
|
}),
|
|
@@ -2675,17 +3090,17 @@ function MeetingControls({ onHangUp, showScreenShareToggle = true }) {
|
|
|
2675
3090
|
}
|
|
2676
3091
|
|
|
2677
3092
|
// src/components/MessageList.tsx
|
|
2678
|
-
import { useEffect as
|
|
3093
|
+
import { useEffect as useEffect14, useRef as useRef8 } from "react";
|
|
2679
3094
|
|
|
2680
3095
|
// src/components/ChatInput.tsx
|
|
2681
|
-
import { useEffect as
|
|
3096
|
+
import { useEffect as useEffect13, useRef as useRef7, useState as useState9 } from "react";
|
|
2682
3097
|
import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
2683
3098
|
var MAX_INPUT_HEIGHT = 60;
|
|
2684
3099
|
function ChatInput({ sendChatMessage, isSendingChat, autoFocus = false }) {
|
|
2685
|
-
const [inputText, setInputText] =
|
|
2686
|
-
const textareaRef =
|
|
3100
|
+
const [inputText, setInputText] = useState9("");
|
|
3101
|
+
const textareaRef = useRef7(null);
|
|
2687
3102
|
const canSend = inputText.trim().length > 0 && !isSendingChat;
|
|
2688
|
-
|
|
3103
|
+
useEffect13(() => {
|
|
2689
3104
|
if (autoFocus)
|
|
2690
3105
|
textareaRef.current?.focus();
|
|
2691
3106
|
}, [autoFocus]);
|
|
@@ -2830,9 +3245,9 @@ function MessageList({
|
|
|
2830
3245
|
isSendingChat,
|
|
2831
3246
|
autoFocus = false
|
|
2832
3247
|
}) {
|
|
2833
|
-
const scrollRef =
|
|
3248
|
+
const scrollRef = useRef8(null);
|
|
2834
3249
|
const lastMessage = messages.length > 0 ? messages[messages.length - 1] : undefined;
|
|
2835
|
-
|
|
3250
|
+
useEffect14(() => {
|
|
2836
3251
|
scrollRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
2837
3252
|
}, [messages.length, lastMessage?.content]);
|
|
2838
3253
|
const showTyping = isStreaming && lastMessage?.role === "assistant" && lastMessage.content === "";
|
|
@@ -2863,50 +3278,222 @@ function MessageList({
|
|
|
2863
3278
|
});
|
|
2864
3279
|
}
|
|
2865
3280
|
|
|
2866
|
-
// src/components/
|
|
3281
|
+
// src/components/ModuleSelector.tsx
|
|
3282
|
+
import { useEffect as useEffect15, useMemo as useMemo5, useRef as useRef9, useState as useState10 } from "react";
|
|
2867
3283
|
import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
3284
|
+
var AGENT_TYPE_ICONS = {
|
|
3285
|
+
onboarding: UserPlus,
|
|
3286
|
+
demo: Rocket,
|
|
3287
|
+
training: GraduationCap,
|
|
3288
|
+
support: Headset
|
|
3289
|
+
};
|
|
3290
|
+
function getAgentIcon(type) {
|
|
3291
|
+
return AGENT_TYPE_ICONS[type] ?? Bot;
|
|
3292
|
+
}
|
|
3293
|
+
function ModuleSelector() {
|
|
3294
|
+
const {
|
|
3295
|
+
availableModules,
|
|
3296
|
+
isLoadingModules,
|
|
3297
|
+
modulesError,
|
|
3298
|
+
refetchModules,
|
|
3299
|
+
selectModule,
|
|
3300
|
+
isStarting,
|
|
3301
|
+
isDisconnecting,
|
|
3302
|
+
error,
|
|
3303
|
+
resumableSessions
|
|
3304
|
+
} = useLiveAgent();
|
|
3305
|
+
const isBusy = isStarting || isDisconnecting;
|
|
3306
|
+
const resumableAgentIds = useMemo5(() => new Set(resumableSessions.map((s) => s.agentId)), [resumableSessions]);
|
|
3307
|
+
const scrollRef = useRef9(null);
|
|
3308
|
+
const [showScrollHint, setShowScrollHint] = useState10(false);
|
|
3309
|
+
const [isScrolled, setIsScrolled] = useState10(false);
|
|
3310
|
+
useEffect15(() => {
|
|
3311
|
+
const el = scrollRef.current;
|
|
3312
|
+
if (!el)
|
|
3313
|
+
return;
|
|
3314
|
+
function update() {
|
|
3315
|
+
if (!el)
|
|
3316
|
+
return;
|
|
3317
|
+
const overflows = el.scrollHeight > el.clientHeight + 1;
|
|
3318
|
+
const atBottom = el.scrollHeight - el.scrollTop - el.clientHeight < 4;
|
|
3319
|
+
setShowScrollHint(overflows && !atBottom);
|
|
3320
|
+
setIsScrolled(el.scrollTop > 0);
|
|
3321
|
+
}
|
|
3322
|
+
update();
|
|
3323
|
+
el.addEventListener("scroll", update, { passive: true });
|
|
3324
|
+
const observer = new ResizeObserver(update);
|
|
3325
|
+
observer.observe(el);
|
|
3326
|
+
return () => {
|
|
3327
|
+
el.removeEventListener("scroll", update);
|
|
3328
|
+
observer.disconnect();
|
|
3329
|
+
};
|
|
3330
|
+
}, []);
|
|
3331
|
+
if (isLoadingModules && availableModules.length === 0) {
|
|
3332
|
+
return /* @__PURE__ */ jsx14("div", {
|
|
3333
|
+
className: "skippr:flex skippr:flex-1 skippr:items-center skippr:justify-center skippr:p-6",
|
|
3334
|
+
children: /* @__PURE__ */ jsx14(LoadingDots, {
|
|
3335
|
+
label: "Loading modules..."
|
|
3336
|
+
})
|
|
3337
|
+
});
|
|
3338
|
+
}
|
|
3339
|
+
if (modulesError) {
|
|
3340
|
+
return /* @__PURE__ */ jsxs13("div", {
|
|
3341
|
+
className: "skippr:flex skippr:flex-1 skippr:flex-col skippr:items-center skippr:justify-center skippr:gap-3 skippr:p-6 skippr:text-center",
|
|
3342
|
+
children: [
|
|
3343
|
+
/* @__PURE__ */ jsx14("p", {
|
|
3344
|
+
className: "skippr:text-sm skippr:text-foreground",
|
|
3345
|
+
children: "Couldn't load modules."
|
|
3346
|
+
}),
|
|
3347
|
+
/* @__PURE__ */ jsx14("p", {
|
|
3348
|
+
className: "skippr:text-xs skippr:text-muted-foreground",
|
|
3349
|
+
children: modulesError
|
|
3350
|
+
}),
|
|
3351
|
+
/* @__PURE__ */ jsx14("button", {
|
|
3352
|
+
type: "button",
|
|
3353
|
+
onClick: () => void refetchModules(),
|
|
3354
|
+
className: "skippr:cursor-pointer skippr:rounded-lg skippr:bg-foreground skippr:px-3 skippr:py-1.5 skippr:text-xs skippr:font-medium skippr:text-background",
|
|
3355
|
+
children: "Try again"
|
|
3356
|
+
})
|
|
3357
|
+
]
|
|
3358
|
+
});
|
|
3359
|
+
}
|
|
3360
|
+
if (availableModules.length === 0) {
|
|
3361
|
+
return /* @__PURE__ */ jsx14("div", {
|
|
3362
|
+
className: "skippr:flex skippr:flex-1 skippr:items-center skippr:justify-center skippr:p-6 skippr:text-center",
|
|
3363
|
+
children: /* @__PURE__ */ jsx14("p", {
|
|
3364
|
+
className: "skippr:text-sm skippr:text-muted-foreground",
|
|
3365
|
+
children: "No experts available."
|
|
3366
|
+
})
|
|
3367
|
+
});
|
|
3368
|
+
}
|
|
3369
|
+
return /* @__PURE__ */ jsxs13("div", {
|
|
3370
|
+
className: "skippr:relative skippr:flex skippr:min-h-0 skippr:flex-1 skippr:flex-col",
|
|
3371
|
+
children: [
|
|
3372
|
+
/* @__PURE__ */ jsxs13("div", {
|
|
3373
|
+
ref: scrollRef,
|
|
3374
|
+
className: "skippr-no-scrollbar skippr:flex-1 skippr:overflow-y-auto",
|
|
3375
|
+
children: [
|
|
3376
|
+
/* @__PURE__ */ jsx14("h3", {
|
|
3377
|
+
className: `skippr:sticky skippr:top-0 skippr:z-10 skippr:bg-background skippr:px-4 skippr:py-3 skippr:text-xs skippr:font-medium skippr:uppercase skippr:tracking-wider skippr:text-muted-foreground skippr:transition-shadow ${isScrolled ? "skippr:border-b skippr:border-border" : ""}`,
|
|
3378
|
+
children: "Choose an agent"
|
|
3379
|
+
}),
|
|
3380
|
+
/* @__PURE__ */ jsxs13("div", {
|
|
3381
|
+
className: "skippr:px-4 skippr:pt-3 skippr:pb-5",
|
|
3382
|
+
children: [
|
|
3383
|
+
error && /* @__PURE__ */ jsx14("div", {
|
|
3384
|
+
role: "alert",
|
|
3385
|
+
className: "skippr:mb-3 skippr:rounded-lg skippr:border skippr:border-destructive/20 skippr:bg-destructive/10 skippr:px-3 skippr:py-2 skippr:text-xs skippr:text-destructive",
|
|
3386
|
+
children: error
|
|
3387
|
+
}),
|
|
3388
|
+
/* @__PURE__ */ jsx14("div", {
|
|
3389
|
+
className: "skippr:grid skippr:grid-cols-2 skippr:gap-2.5",
|
|
3390
|
+
children: availableModules.map((module, index2) => {
|
|
3391
|
+
const isFeatured = index2 === 0;
|
|
3392
|
+
const isWide = index2 === availableModules.length - 1 && availableModules.length % 2 === 1;
|
|
3393
|
+
const Icon2 = getAgentIcon(module.type);
|
|
3394
|
+
const canResume = resumableAgentIds.has(module.id);
|
|
3395
|
+
const base = "skippr:group skippr:flex skippr:cursor-pointer skippr:gap-3 skippr:rounded-xl skippr:text-left skippr:transition-colors skippr:disabled:cursor-not-allowed skippr:disabled:opacity-50";
|
|
3396
|
+
const layout = isWide ? "skippr:items-center skippr:p-3.5 skippr:pb-5" : "skippr:flex-col skippr:items-start skippr:p-3.5";
|
|
3397
|
+
const variant = isFeatured ? "skippr:bg-primary skippr:text-primary-foreground skippr:hover:bg-primary/90" : "skippr:bg-background skippr:ring-1 skippr:ring-foreground/10 skippr:hover:bg-muted/50";
|
|
3398
|
+
const span = isWide ? "skippr:col-span-2" : "";
|
|
3399
|
+
return /* @__PURE__ */ jsxs13("button", {
|
|
3400
|
+
type: "button",
|
|
3401
|
+
disabled: isBusy,
|
|
3402
|
+
onClick: () => selectModule(module.id),
|
|
3403
|
+
className: `${base} ${layout} ${variant} ${span}`,
|
|
3404
|
+
children: [
|
|
3405
|
+
/* @__PURE__ */ jsx14("div", {
|
|
3406
|
+
className: isFeatured ? "skippr:flex skippr:h-9 skippr:w-9 skippr:shrink-0 skippr:items-center skippr:justify-center skippr:rounded-lg skippr:bg-primary-foreground/15" : "skippr:flex skippr:h-9 skippr:w-9 skippr:shrink-0 skippr:items-center skippr:justify-center skippr:rounded-lg skippr:bg-muted",
|
|
3407
|
+
children: /* @__PURE__ */ jsx14(Icon2, {
|
|
3408
|
+
className: isFeatured ? "skippr:h-4 skippr:w-4" : "skippr:h-4 skippr:w-4 skippr:text-muted-foreground"
|
|
3409
|
+
})
|
|
3410
|
+
}),
|
|
3411
|
+
/* @__PURE__ */ jsxs13("div", {
|
|
3412
|
+
className: "skippr:min-w-0 skippr:w-full skippr:space-y-0.5",
|
|
3413
|
+
children: [
|
|
3414
|
+
/* @__PURE__ */ jsxs13("div", {
|
|
3415
|
+
className: "skippr:flex skippr:items-center skippr:gap-1.5",
|
|
3416
|
+
children: [
|
|
3417
|
+
/* @__PURE__ */ jsx14("p", {
|
|
3418
|
+
className: "skippr:line-clamp-1 skippr:text-sm skippr:font-semibold",
|
|
3419
|
+
children: module.name
|
|
3420
|
+
}),
|
|
3421
|
+
canResume && /* @__PURE__ */ jsxs13("span", {
|
|
3422
|
+
className: `skippr:inline-flex skippr:shrink-0 skippr:items-center skippr:gap-0.5 skippr:rounded-full skippr:px-1.5 skippr:py-0.5 skippr:text-[9px] skippr:font-medium skippr:uppercase skippr:tracking-wide ${isFeatured ? "skippr:bg-primary-foreground/20 skippr:text-primary-foreground" : "skippr:bg-bubble/15 skippr:text-bubble"}`,
|
|
3423
|
+
children: [
|
|
3424
|
+
/* @__PURE__ */ jsx14(Play, {
|
|
3425
|
+
className: "skippr:size-2.5"
|
|
3426
|
+
}),
|
|
3427
|
+
"Resume"
|
|
3428
|
+
]
|
|
3429
|
+
})
|
|
3430
|
+
]
|
|
3431
|
+
}),
|
|
3432
|
+
module.description && /* @__PURE__ */ jsx14("p", {
|
|
3433
|
+
className: isFeatured ? "skippr:line-clamp-2 skippr:text-[11px] skippr:leading-snug skippr:text-primary-foreground/70" : "skippr:line-clamp-2 skippr:text-[11px] skippr:leading-snug skippr:text-muted-foreground",
|
|
3434
|
+
children: module.description
|
|
3435
|
+
})
|
|
3436
|
+
]
|
|
3437
|
+
})
|
|
3438
|
+
]
|
|
3439
|
+
}, module.id);
|
|
3440
|
+
})
|
|
3441
|
+
})
|
|
3442
|
+
]
|
|
3443
|
+
})
|
|
3444
|
+
]
|
|
3445
|
+
}),
|
|
3446
|
+
showScrollHint && /* @__PURE__ */ jsx14("div", {
|
|
3447
|
+
className: "skippr:pointer-events-none skippr:absolute skippr:bottom-0 skippr:left-0 skippr:right-0 skippr:h-12 skippr:bg-gradient-to-t skippr:from-background skippr:to-transparent"
|
|
3448
|
+
})
|
|
3449
|
+
]
|
|
3450
|
+
});
|
|
3451
|
+
}
|
|
3452
|
+
|
|
3453
|
+
// src/components/SessionAgenda.tsx
|
|
3454
|
+
import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
2868
3455
|
function SessionAgenda({ phases, hasStarted }) {
|
|
2869
3456
|
if (phases.length === 0 || !hasStarted) {
|
|
2870
|
-
return /* @__PURE__ */
|
|
3457
|
+
return /* @__PURE__ */ jsx15("div", {
|
|
2871
3458
|
className: "skippr:flex skippr:flex-1 skippr:items-center skippr:justify-center",
|
|
2872
|
-
children: /* @__PURE__ */
|
|
3459
|
+
children: /* @__PURE__ */ jsx15(LoadingDots, {
|
|
2873
3460
|
label: "Waiting for agenda to load..."
|
|
2874
3461
|
})
|
|
2875
3462
|
});
|
|
2876
3463
|
}
|
|
2877
|
-
return /* @__PURE__ */
|
|
3464
|
+
return /* @__PURE__ */ jsx15("div", {
|
|
2878
3465
|
className: "skippr:flex-1 skippr:overflow-y-auto skippr:px-4 skippr:py-4",
|
|
2879
|
-
children: /* @__PURE__ */
|
|
3466
|
+
children: /* @__PURE__ */ jsx15("div", {
|
|
2880
3467
|
className: "skippr:space-y-1",
|
|
2881
3468
|
children: phases.map((phase) => {
|
|
2882
3469
|
const isActive = phase.status === "active";
|
|
2883
3470
|
const isCompleted = phase.status === "completed";
|
|
2884
|
-
return /* @__PURE__ */
|
|
3471
|
+
return /* @__PURE__ */ jsxs14("div", {
|
|
2885
3472
|
className: cn("skippr:flex skippr:items-start skippr:gap-2.5 skippr:rounded-lg skippr:p-2 skippr:transition-colors", isActive && "skippr:bg-primary/10"),
|
|
2886
3473
|
children: [
|
|
2887
|
-
/* @__PURE__ */
|
|
3474
|
+
/* @__PURE__ */ jsx15("div", {
|
|
2888
3475
|
className: "skippr:mt-0.5",
|
|
2889
|
-
children: isCompleted ? /* @__PURE__ */
|
|
3476
|
+
children: isCompleted ? /* @__PURE__ */ jsx15(CircleCheck, {
|
|
2890
3477
|
className: "skippr:size-4 skippr:text-chart-3"
|
|
2891
|
-
}) : isActive ? /* @__PURE__ */
|
|
3478
|
+
}) : isActive ? /* @__PURE__ */ jsx15(Circle, {
|
|
2892
3479
|
className: "skippr:size-4 skippr:fill-primary/30 skippr:text-primary"
|
|
2893
|
-
}) : /* @__PURE__ */
|
|
3480
|
+
}) : /* @__PURE__ */ jsx15(Circle, {
|
|
2894
3481
|
className: "skippr:size-4 skippr:text-muted-foreground/30"
|
|
2895
3482
|
})
|
|
2896
3483
|
}),
|
|
2897
|
-
/* @__PURE__ */
|
|
3484
|
+
/* @__PURE__ */ jsxs14("div", {
|
|
2898
3485
|
className: "skippr:min-w-0 skippr:flex-1",
|
|
2899
3486
|
children: [
|
|
2900
|
-
/* @__PURE__ */
|
|
3487
|
+
/* @__PURE__ */ jsx15("p", {
|
|
2901
3488
|
className: cn("skippr:text-sm", isCompleted && "skippr:text-muted-foreground skippr:line-through", isActive && "skippr:font-medium skippr:text-foreground", phase.status === "pending" && "skippr:text-muted-foreground"),
|
|
2902
3489
|
children: phase.name
|
|
2903
3490
|
}),
|
|
2904
|
-
phase.highlights.length > 0 && /* @__PURE__ */
|
|
3491
|
+
phase.highlights.length > 0 && /* @__PURE__ */ jsx15("ul", {
|
|
2905
3492
|
className: "skippr:mt-1 skippr:space-y-0.5",
|
|
2906
|
-
children: phase.highlights.map((text) => /* @__PURE__ */
|
|
3493
|
+
children: phase.highlights.map((text) => /* @__PURE__ */ jsxs14("li", {
|
|
2907
3494
|
className: cn("skippr:flex skippr:items-center skippr:gap-1.5 skippr:text-[11px] skippr:leading-tight", isCompleted ? "skippr:text-muted-foreground/40 skippr:line-through" : "skippr:text-muted-foreground/70"),
|
|
2908
3495
|
children: [
|
|
2909
|
-
/* @__PURE__ */
|
|
3496
|
+
/* @__PURE__ */ jsx15("span", {
|
|
2910
3497
|
className: "skippr:size-1 skippr:shrink-0 skippr:rounded-full skippr:bg-current"
|
|
2911
3498
|
}),
|
|
2912
3499
|
text
|
|
@@ -2923,12 +3510,12 @@ function SessionAgenda({ phases, hasStarted }) {
|
|
|
2923
3510
|
}
|
|
2924
3511
|
|
|
2925
3512
|
// src/components/SessionWarningBanner.tsx
|
|
2926
|
-
import { jsx as
|
|
3513
|
+
import { jsx as jsx16 } from "react/jsx-runtime";
|
|
2927
3514
|
var SESSION_WARNING_THRESHOLD_SECS = 60;
|
|
2928
3515
|
function SessionWarningBanner({ remaining }) {
|
|
2929
3516
|
if (remaining === null || remaining <= 0 || remaining > SESSION_WARNING_THRESHOLD_SECS)
|
|
2930
3517
|
return null;
|
|
2931
|
-
return /* @__PURE__ */
|
|
3518
|
+
return /* @__PURE__ */ jsx16("div", {
|
|
2932
3519
|
"data-testid": "session-warning-banner",
|
|
2933
3520
|
className: "skippr:bg-red-50 skippr:px-4 skippr:py-1.5 skippr:text-center skippr:text-xs skippr:font-medium skippr:text-red-700",
|
|
2934
3521
|
children: "Session ending soon"
|
|
@@ -2936,24 +3523,39 @@ function SessionWarningBanner({ remaining }) {
|
|
|
2936
3523
|
}
|
|
2937
3524
|
|
|
2938
3525
|
// src/components/StartSessionPrompt.tsx
|
|
2939
|
-
import { jsx as
|
|
3526
|
+
import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
3527
|
+
var PROMPT_BUTTON = "skippr:cursor-pointer skippr:rounded-xl skippr:bg-primary skippr:px-8 skippr:py-3 skippr:text-sm skippr:font-medium skippr:text-primary-foreground skippr:transition-all skippr:hover:bg-primary/90 skippr:disabled:cursor-not-allowed skippr:disabled:opacity-60";
|
|
2940
3528
|
function StartSessionPrompt({
|
|
2941
3529
|
onStartSession,
|
|
3530
|
+
agentId,
|
|
3531
|
+
agentControls,
|
|
2942
3532
|
isStarting,
|
|
2943
3533
|
error,
|
|
2944
|
-
label = "Talk to Skippr"
|
|
3534
|
+
label = "Talk to Skippr",
|
|
3535
|
+
canResume = false,
|
|
3536
|
+
onResume
|
|
2945
3537
|
}) {
|
|
2946
|
-
return /* @__PURE__ */
|
|
3538
|
+
return /* @__PURE__ */ jsxs15("div", {
|
|
2947
3539
|
className: "skippr:flex skippr:flex-1 skippr:flex-col skippr:items-center skippr:justify-center skippr:gap-3 skippr:px-4",
|
|
2948
3540
|
children: [
|
|
2949
|
-
/* @__PURE__ */
|
|
3541
|
+
canResume && onResume ? /* @__PURE__ */ jsx17("button", {
|
|
2950
3542
|
type: "button",
|
|
2951
|
-
onClick:
|
|
3543
|
+
onClick: onResume,
|
|
2952
3544
|
disabled: isStarting,
|
|
2953
|
-
className:
|
|
3545
|
+
className: PROMPT_BUTTON,
|
|
3546
|
+
children: isStarting ? "Resuming..." : "Resume session"
|
|
3547
|
+
}) : /* @__PURE__ */ jsx17("button", {
|
|
3548
|
+
type: "button",
|
|
3549
|
+
onClick: () => {
|
|
3550
|
+
if (!agentId)
|
|
3551
|
+
return;
|
|
3552
|
+
onStartSession(agentControls ? { agentId, agentControls } : { agentId });
|
|
3553
|
+
},
|
|
3554
|
+
disabled: isStarting || !agentId,
|
|
3555
|
+
className: PROMPT_BUTTON,
|
|
2954
3556
|
children: isStarting ? "Starting..." : label
|
|
2955
3557
|
}),
|
|
2956
|
-
error && /* @__PURE__ */
|
|
3558
|
+
error && /* @__PURE__ */ jsx17("p", {
|
|
2957
3559
|
className: "skippr:text-xs skippr:text-destructive",
|
|
2958
3560
|
children: error
|
|
2959
3561
|
})
|
|
@@ -2962,7 +3564,7 @@ function StartSessionPrompt({
|
|
|
2962
3564
|
}
|
|
2963
3565
|
|
|
2964
3566
|
// src/components/Sidebar.tsx
|
|
2965
|
-
import { jsx as
|
|
3567
|
+
import { jsx as jsx18, jsxs as jsxs16, Fragment as Fragment4 } from "react/jsx-runtime";
|
|
2966
3568
|
function Sidebar({
|
|
2967
3569
|
hideControls = false,
|
|
2968
3570
|
hideHeader = false,
|
|
@@ -2972,8 +3574,14 @@ function Sidebar({
|
|
|
2972
3574
|
variant,
|
|
2973
3575
|
isConnected,
|
|
2974
3576
|
isStarting,
|
|
3577
|
+
isDisconnecting,
|
|
3578
|
+
isPausing,
|
|
3579
|
+
isPaused,
|
|
2975
3580
|
error,
|
|
2976
3581
|
startSession,
|
|
3582
|
+
pauseSession,
|
|
3583
|
+
resumeSession,
|
|
3584
|
+
resumableSession,
|
|
2977
3585
|
disconnect,
|
|
2978
3586
|
isPanelOpen,
|
|
2979
3587
|
position,
|
|
@@ -2986,11 +3594,14 @@ function Sidebar({
|
|
|
2986
3594
|
sidebarTab: activeTab,
|
|
2987
3595
|
setSidebarTab: setActiveTab,
|
|
2988
3596
|
autoFocusChat,
|
|
2989
|
-
captureMode
|
|
3597
|
+
captureMode,
|
|
3598
|
+
hasModuleSelector,
|
|
3599
|
+
agentId,
|
|
3600
|
+
agentControls
|
|
2990
3601
|
} = useLiveAgent();
|
|
2991
3602
|
const isFloating = variant === "floating";
|
|
2992
3603
|
const isSidebar = variant === "sidebar";
|
|
2993
|
-
|
|
3604
|
+
useEffect16(() => {
|
|
2994
3605
|
if (!isSidebar)
|
|
2995
3606
|
return;
|
|
2996
3607
|
const prop = position === "right" ? "marginRight" : "marginLeft";
|
|
@@ -3004,24 +3615,30 @@ function Sidebar({
|
|
|
3004
3615
|
document.body.style.transition = "";
|
|
3005
3616
|
};
|
|
3006
3617
|
}, [isSidebar, isPanelOpen, position]);
|
|
3007
|
-
return /* @__PURE__ */
|
|
3618
|
+
return /* @__PURE__ */ jsxs16("div", {
|
|
3008
3619
|
className: cn("skippr:fixed skippr:z-[9999]", "skippr:bg-card", "skippr:flex skippr:flex-col", "skippr:overflow-hidden", isFloating && "skippr:border skippr:border-border skippr:bottom-[88px] skippr:h-[min(460px,calc(100vh-200px))] skippr:rounded-2xl skippr:shadow-[0_8px_30px_rgba(0,0,0,0.16),0_4px_12px_rgba(0,0,0,0.08)]", isFloating && (position === "right" ? "skippr:right-6" : "skippr:left-6"), isFloating && "skippr:transition-[opacity,transform] skippr:duration-300 skippr:ease-in-out", isFloating && (position === "right" ? "skippr:origin-bottom-right" : "skippr:origin-bottom-left"), isFloating && !isPanelOpen && "skippr:scale-0 skippr:opacity-0 skippr:pointer-events-none", isFloating && isPanelOpen && "skippr:scale-100 skippr:opacity-100", isSidebar && "skippr:top-0 skippr:h-full", isSidebar && "skippr:transition-[width] skippr:duration-300 skippr:ease-in-out", isSidebar && position === "right" && "skippr:right-0 skippr:border-l skippr:border-l-border", isSidebar && position === "left" && "skippr:left-0 skippr:border-r skippr:border-r-border", isSidebar && !isPanelOpen && "skippr:w-0 skippr:border-0"),
|
|
3009
3620
|
style: { width: isPanelOpen ? SIDEBAR_WIDTH : undefined },
|
|
3010
3621
|
children: [
|
|
3011
|
-
!hideHeader && /* @__PURE__ */
|
|
3012
|
-
!isAuthenticated && isValidating ? /* @__PURE__ */
|
|
3622
|
+
!hideHeader && /* @__PURE__ */ jsx18(ChatHeader, {}),
|
|
3623
|
+
!isAuthenticated && isValidating ? /* @__PURE__ */ jsx18("div", {
|
|
3013
3624
|
className: "skippr:flex skippr:flex-1 skippr:items-center skippr:justify-center",
|
|
3014
|
-
children: /* @__PURE__ */
|
|
3625
|
+
children: /* @__PURE__ */ jsx18(LoadingDots, {
|
|
3015
3626
|
label: "Loading..."
|
|
3016
3627
|
})
|
|
3017
|
-
}) : !isAuthenticated ? /* @__PURE__ */
|
|
3628
|
+
}) : !isAuthenticated ? /* @__PURE__ */ jsx18(LoginFlow, {
|
|
3018
3629
|
requestOtp,
|
|
3019
3630
|
verifyOtp,
|
|
3020
3631
|
error: authError,
|
|
3021
3632
|
isSubmitting: isAuthSubmitting
|
|
3022
|
-
}) : /* @__PURE__ */
|
|
3633
|
+
}) : /* @__PURE__ */ jsx18(AuthenticatedContent, {
|
|
3023
3634
|
isConnected,
|
|
3635
|
+
isPaused,
|
|
3636
|
+
isPausing,
|
|
3637
|
+
isDisconnecting,
|
|
3638
|
+
canResume: resumableSession !== null,
|
|
3024
3639
|
onStartSession: startSession,
|
|
3640
|
+
onPause: pauseSession,
|
|
3641
|
+
onResume: resumeSession,
|
|
3025
3642
|
onDisconnect: disconnect,
|
|
3026
3643
|
isStarting,
|
|
3027
3644
|
error,
|
|
@@ -3030,14 +3647,23 @@ function Sidebar({
|
|
|
3030
3647
|
hideControls,
|
|
3031
3648
|
startSessionLabel,
|
|
3032
3649
|
autoFocusChat,
|
|
3033
|
-
showScreenShareToggle: captureMode === "screenshare"
|
|
3650
|
+
showScreenShareToggle: captureMode === "screenshare",
|
|
3651
|
+
hasModuleSelector,
|
|
3652
|
+
agentId,
|
|
3653
|
+
agentControls
|
|
3034
3654
|
})
|
|
3035
3655
|
]
|
|
3036
3656
|
});
|
|
3037
3657
|
}
|
|
3038
3658
|
function AuthenticatedContent({
|
|
3039
3659
|
isConnected,
|
|
3660
|
+
isPaused,
|
|
3661
|
+
isPausing,
|
|
3662
|
+
isDisconnecting,
|
|
3663
|
+
canResume,
|
|
3040
3664
|
onStartSession,
|
|
3665
|
+
onPause,
|
|
3666
|
+
onResume,
|
|
3041
3667
|
onDisconnect,
|
|
3042
3668
|
isStarting,
|
|
3043
3669
|
error,
|
|
@@ -3046,61 +3672,96 @@ function AuthenticatedContent({
|
|
|
3046
3672
|
hideControls,
|
|
3047
3673
|
startSessionLabel,
|
|
3048
3674
|
autoFocusChat,
|
|
3049
|
-
showScreenShareToggle
|
|
3675
|
+
showScreenShareToggle,
|
|
3676
|
+
hasModuleSelector,
|
|
3677
|
+
agentId,
|
|
3678
|
+
agentControls
|
|
3050
3679
|
}) {
|
|
3051
|
-
|
|
3680
|
+
const inSession = isConnected || isStarting || isPaused || isPausing;
|
|
3681
|
+
const showSelectorAsPrompt = hasModuleSelector && !inSession && !isDisconnecting;
|
|
3682
|
+
const showTabBar = !showSelectorAsPrompt;
|
|
3683
|
+
let transitionLabel = null;
|
|
3684
|
+
if (isPausing) {
|
|
3685
|
+
transitionLabel = "Pausing...";
|
|
3686
|
+
} else if (isStarting && !isConnected) {
|
|
3687
|
+
transitionLabel = "Reconnecting...";
|
|
3688
|
+
} else if (isPaused) {
|
|
3689
|
+
transitionLabel = "Paused";
|
|
3690
|
+
}
|
|
3691
|
+
return /* @__PURE__ */ jsxs16(Fragment4, {
|
|
3052
3692
|
children: [
|
|
3053
|
-
isConnected && /* @__PURE__ */
|
|
3054
|
-
/* @__PURE__ */
|
|
3055
|
-
className: "skippr:flex skippr:gap-2 skippr:border-b skippr:border-border skippr:px-3 skippr:py-2",
|
|
3693
|
+
isConnected && /* @__PURE__ */ jsx18(ConnectedBanner, {}),
|
|
3694
|
+
showTabBar && /* @__PURE__ */ jsxs16("div", {
|
|
3695
|
+
className: "skippr:flex skippr:items-center skippr:gap-2 skippr:border-b skippr:border-border skippr:px-3 skippr:py-2",
|
|
3056
3696
|
children: [
|
|
3057
|
-
/* @__PURE__ */
|
|
3697
|
+
/* @__PURE__ */ jsxs16("button", {
|
|
3058
3698
|
type: "button",
|
|
3059
3699
|
className: cn("skippr:relative skippr:inline-flex skippr:cursor-pointer skippr:items-center skippr:gap-1.5 skippr:rounded-lg skippr:px-3 skippr:py-2 skippr:text-sm skippr:font-medium skippr:transition-all", activeTab === "chat" ? "skippr:text-foreground" : "skippr:text-muted-foreground skippr:hover:text-foreground"),
|
|
3060
3700
|
onClick: () => onTabChange("chat"),
|
|
3061
3701
|
children: [
|
|
3062
|
-
/* @__PURE__ */
|
|
3702
|
+
/* @__PURE__ */ jsx18(MessageCircle, {
|
|
3063
3703
|
className: "skippr:size-3.5"
|
|
3064
3704
|
}),
|
|
3065
3705
|
"Chat",
|
|
3066
|
-
activeTab === "chat" && /* @__PURE__ */
|
|
3706
|
+
activeTab === "chat" && /* @__PURE__ */ jsx18("span", {
|
|
3067
3707
|
className: "skippr:absolute skippr:-bottom-2 skippr:left-3 skippr:right-3 skippr:h-0.5 skippr:rounded-full skippr:bg-foreground"
|
|
3068
3708
|
})
|
|
3069
3709
|
]
|
|
3070
3710
|
}),
|
|
3071
|
-
/* @__PURE__ */
|
|
3711
|
+
/* @__PURE__ */ jsxs16("button", {
|
|
3072
3712
|
type: "button",
|
|
3073
3713
|
className: cn("skippr:relative skippr:inline-flex skippr:cursor-pointer skippr:items-center skippr:gap-1.5 skippr:rounded-lg skippr:px-3 skippr:py-2 skippr:text-sm skippr:font-medium skippr:transition-all", activeTab === "agenda" ? "skippr:text-foreground" : "skippr:text-muted-foreground skippr:hover:text-foreground"),
|
|
3074
3714
|
onClick: () => onTabChange("agenda"),
|
|
3075
3715
|
children: [
|
|
3076
|
-
/* @__PURE__ */
|
|
3716
|
+
/* @__PURE__ */ jsx18(Calendar, {
|
|
3077
3717
|
className: "skippr:size-3.5"
|
|
3078
3718
|
}),
|
|
3079
3719
|
"Agenda",
|
|
3080
|
-
activeTab === "agenda" && /* @__PURE__ */
|
|
3720
|
+
activeTab === "agenda" && /* @__PURE__ */ jsx18("span", {
|
|
3081
3721
|
className: "skippr:absolute skippr:-bottom-2 skippr:left-3 skippr:right-3 skippr:h-0.5 skippr:rounded-full skippr:bg-foreground"
|
|
3082
3722
|
})
|
|
3083
3723
|
]
|
|
3084
3724
|
})
|
|
3085
3725
|
]
|
|
3086
3726
|
}),
|
|
3087
|
-
/* @__PURE__ */
|
|
3727
|
+
/* @__PURE__ */ jsx18("div", {
|
|
3088
3728
|
className: "skippr:flex skippr:min-h-0 skippr:flex-1 skippr:flex-col",
|
|
3089
|
-
children:
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3729
|
+
children: isDisconnecting ? /* @__PURE__ */ jsx18("div", {
|
|
3730
|
+
className: "skippr:flex skippr:flex-1 skippr:items-center skippr:justify-center",
|
|
3731
|
+
children: /* @__PURE__ */ jsx18(LoadingDots, {
|
|
3732
|
+
label: "Ending session..."
|
|
3733
|
+
})
|
|
3734
|
+
}) : showSelectorAsPrompt ? /* @__PURE__ */ jsx18(ModuleSelector, {}) : inSession ? /* @__PURE__ */ jsxs16(Fragment4, {
|
|
3735
|
+
children: [
|
|
3736
|
+
transitionLabel && /* @__PURE__ */ jsx18("div", {
|
|
3737
|
+
className: "skippr:shrink-0 skippr:border-b skippr:border-border skippr:bg-muted/50 skippr:px-3 skippr:py-1.5 skippr:text-center skippr:text-xs skippr:text-muted-foreground",
|
|
3738
|
+
children: transitionLabel
|
|
3739
|
+
}),
|
|
3740
|
+
/* @__PURE__ */ jsx18(ConnectedBody, {
|
|
3741
|
+
activeTab,
|
|
3742
|
+
autoFocusChat
|
|
3743
|
+
})
|
|
3744
|
+
]
|
|
3745
|
+
}) : /* @__PURE__ */ jsx18("div", {
|
|
3093
3746
|
className: "skippr:flex skippr:min-h-0 skippr:flex-1 skippr:flex-col skippr:animate-skippr-tab-fade",
|
|
3094
|
-
children: /* @__PURE__ */
|
|
3747
|
+
children: /* @__PURE__ */ jsx18(StartSessionPrompt, {
|
|
3095
3748
|
onStartSession,
|
|
3749
|
+
agentId,
|
|
3750
|
+
agentControls,
|
|
3096
3751
|
isStarting,
|
|
3097
3752
|
error,
|
|
3098
|
-
label: startSessionLabel
|
|
3753
|
+
label: startSessionLabel,
|
|
3754
|
+
canResume,
|
|
3755
|
+
onResume
|
|
3099
3756
|
})
|
|
3100
3757
|
}, `${activeTab}-empty`)
|
|
3101
3758
|
}),
|
|
3102
|
-
isConnected && !hideControls && /* @__PURE__ */
|
|
3759
|
+
(isConnected || isPaused) && !isDisconnecting && !hideControls && /* @__PURE__ */ jsx18(MeetingControls, {
|
|
3103
3760
|
onHangUp: onDisconnect,
|
|
3761
|
+
onPause,
|
|
3762
|
+
onResume,
|
|
3763
|
+
isPaused,
|
|
3764
|
+
isPausing,
|
|
3104
3765
|
showScreenShareToggle
|
|
3105
3766
|
})
|
|
3106
3767
|
]
|
|
@@ -3108,7 +3769,7 @@ function AuthenticatedContent({
|
|
|
3108
3769
|
}
|
|
3109
3770
|
function ConnectedBanner() {
|
|
3110
3771
|
const remaining = useSessionRemaining();
|
|
3111
|
-
return /* @__PURE__ */
|
|
3772
|
+
return /* @__PURE__ */ jsx18(SessionWarningBanner, {
|
|
3112
3773
|
remaining
|
|
3113
3774
|
});
|
|
3114
3775
|
}
|
|
@@ -3119,17 +3780,17 @@ function ConnectedBody({
|
|
|
3119
3780
|
const { allMessages, agentState, sendChatMessage, isSendingChat } = useCombinedMessages();
|
|
3120
3781
|
const { phases } = usePhaseUpdates();
|
|
3121
3782
|
if (activeTab === "agenda") {
|
|
3122
|
-
return /* @__PURE__ */
|
|
3783
|
+
return /* @__PURE__ */ jsx18("div", {
|
|
3123
3784
|
className: "skippr:min-h-0 skippr:flex-1 skippr:overflow-y-auto skippr:animate-skippr-tab-fade",
|
|
3124
|
-
children: /* @__PURE__ */
|
|
3785
|
+
children: /* @__PURE__ */ jsx18(SessionAgenda, {
|
|
3125
3786
|
phases,
|
|
3126
3787
|
hasStarted: allMessages.length > 0 || agentState === "speaking"
|
|
3127
3788
|
})
|
|
3128
3789
|
}, "agenda");
|
|
3129
3790
|
}
|
|
3130
|
-
return /* @__PURE__ */
|
|
3791
|
+
return /* @__PURE__ */ jsx18("div", {
|
|
3131
3792
|
className: "skippr:flex skippr:min-h-0 skippr:flex-1 skippr:flex-col skippr:animate-skippr-tab-fade",
|
|
3132
|
-
children: /* @__PURE__ */
|
|
3793
|
+
children: /* @__PURE__ */ jsx18(MessageList, {
|
|
3133
3794
|
messages: allMessages,
|
|
3134
3795
|
isStreaming: agentState === "speaking",
|
|
3135
3796
|
sendChatMessage,
|
|
@@ -3140,31 +3801,31 @@ function ConnectedBody({
|
|
|
3140
3801
|
}
|
|
3141
3802
|
|
|
3142
3803
|
// src/components/SidebarTrigger.tsx
|
|
3143
|
-
import { jsx as
|
|
3804
|
+
import { jsx as jsx19 } from "react/jsx-runtime";
|
|
3144
3805
|
function SidebarTrigger() {
|
|
3145
3806
|
const { isPanelOpen, togglePanel, minimizePanel, minimizable, position, isMinimized } = useLiveAgent();
|
|
3146
3807
|
if (isMinimized)
|
|
3147
3808
|
return null;
|
|
3148
3809
|
const handleClick = isPanelOpen && minimizable ? minimizePanel : togglePanel;
|
|
3149
|
-
return /* @__PURE__ */
|
|
3810
|
+
return /* @__PURE__ */ jsx19("button", {
|
|
3150
3811
|
type: "button",
|
|
3151
3812
|
onClick: handleClick,
|
|
3152
3813
|
title: isPanelOpen ? "Close chat" : "Open chat",
|
|
3153
3814
|
"aria-label": isPanelOpen ? "Close chat" : "Open chat",
|
|
3154
3815
|
className: cn("skippr:fixed skippr:bottom-6 skippr:z-[9998]", "skippr:flex skippr:size-12 skippr:items-center skippr:justify-center", "skippr:rounded-[14px] skippr:bg-bubble skippr:text-white", "skippr:shadow-[0_4px_16px_rgba(45,43,61,0.45),0_2px_4px_rgba(0,0,0,0.1)] skippr:transition-all", "skippr:cursor-pointer skippr:hover:brightness-110 skippr:hover:-translate-y-0.5 skippr:active:translate-y-0", position === "right" ? "skippr:right-6" : "skippr:left-6"),
|
|
3155
|
-
children: isPanelOpen ? /* @__PURE__ */
|
|
3816
|
+
children: isPanelOpen ? /* @__PURE__ */ jsx19(ChevronDown, {
|
|
3156
3817
|
className: "skippr:size-5"
|
|
3157
|
-
}) : /* @__PURE__ */
|
|
3818
|
+
}) : /* @__PURE__ */ jsx19(Logo, {
|
|
3158
3819
|
className: "skippr:size-7"
|
|
3159
3820
|
})
|
|
3160
3821
|
});
|
|
3161
3822
|
}
|
|
3162
3823
|
|
|
3163
3824
|
// src/components/LiveAgent.tsx
|
|
3164
|
-
import { jsx as
|
|
3825
|
+
import { jsx as jsx20, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
3165
3826
|
function LiveAgent(props) {
|
|
3166
3827
|
const {
|
|
3167
|
-
agentId,
|
|
3828
|
+
agentId: hostAgentId,
|
|
3168
3829
|
authToken: authTokenProp,
|
|
3169
3830
|
appKey,
|
|
3170
3831
|
userToken,
|
|
@@ -3180,39 +3841,106 @@ function LiveAgent(props) {
|
|
|
3180
3841
|
children
|
|
3181
3842
|
} = props;
|
|
3182
3843
|
const captureMode = props.captureMode ?? "screenshare";
|
|
3183
|
-
let
|
|
3844
|
+
let hostAgentControls;
|
|
3184
3845
|
if ("agentControls" in props && props.agentControls) {
|
|
3185
3846
|
if (captureMode === "auto") {
|
|
3186
|
-
|
|
3847
|
+
hostAgentControls = props.agentControls;
|
|
3187
3848
|
} else {
|
|
3188
3849
|
console.warn('[Skippr] agentControls requires captureMode: "auto"');
|
|
3189
3850
|
}
|
|
3190
3851
|
}
|
|
3191
3852
|
const auth = useAuth({ appKey });
|
|
3192
3853
|
const effectiveAuthToken = authTokenProp || auth.authToken || undefined;
|
|
3854
|
+
const hasModuleSelector = !hostAgentId;
|
|
3855
|
+
const [activeModule, setActiveModule] = useState11(null);
|
|
3856
|
+
const agentId = hasModuleSelector ? activeModule?.id ?? null : hostAgentId;
|
|
3857
|
+
const agentControls = hasModuleSelector ? activeModule?.controls : hostAgentControls;
|
|
3858
|
+
const minimizeOnSessionStart = useCallback8(() => {
|
|
3859
|
+
if (minimizable) {
|
|
3860
|
+
setIsMinimized(true);
|
|
3861
|
+
setIsPanelOpen(false);
|
|
3862
|
+
}
|
|
3863
|
+
}, [minimizable]);
|
|
3864
|
+
const expandOnSessionStartError = useCallback8(() => {
|
|
3865
|
+
setIsMinimized(false);
|
|
3866
|
+
setIsPanelOpen(true);
|
|
3867
|
+
}, []);
|
|
3868
|
+
const minimizeOnSessionDisconnect = useCallback8(() => {
|
|
3869
|
+
if (hasModuleSelector) {
|
|
3870
|
+
setActiveModule(null);
|
|
3871
|
+
}
|
|
3872
|
+
if (minimizable && !hasModuleSelector) {
|
|
3873
|
+
setIsMinimized(true);
|
|
3874
|
+
setIsPanelOpen(false);
|
|
3875
|
+
}
|
|
3876
|
+
}, [minimizable, hasModuleSelector]);
|
|
3193
3877
|
const {
|
|
3194
3878
|
connection,
|
|
3195
3879
|
shouldConnect,
|
|
3196
3880
|
isStarting,
|
|
3881
|
+
isDisconnecting,
|
|
3882
|
+
isPausing,
|
|
3197
3883
|
error,
|
|
3198
3884
|
errorCode,
|
|
3199
3885
|
startSession,
|
|
3886
|
+
pauseSession,
|
|
3887
|
+
resumeSession: resumeSessionById,
|
|
3200
3888
|
disconnect,
|
|
3201
|
-
|
|
3889
|
+
isPaused,
|
|
3890
|
+
resumableSessions,
|
|
3891
|
+
historyMessages,
|
|
3892
|
+
pendingScreenStream,
|
|
3893
|
+
bearerToken
|
|
3202
3894
|
} = useSession({
|
|
3203
|
-
agentId,
|
|
3204
3895
|
captureMode,
|
|
3205
|
-
agentControls,
|
|
3206
3896
|
authToken: effectiveAuthToken,
|
|
3207
3897
|
appKey,
|
|
3208
|
-
userToken
|
|
3898
|
+
userToken,
|
|
3899
|
+
onStart: minimizeOnSessionStart,
|
|
3900
|
+
onStartError: expandOnSessionStartError,
|
|
3901
|
+
onDisconnect: minimizeOnSessionDisconnect
|
|
3209
3902
|
});
|
|
3210
|
-
const
|
|
3211
|
-
|
|
3212
|
-
const
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3903
|
+
const teardownInFlightRef = useRef10(false);
|
|
3904
|
+
teardownInFlightRef.current = isPaused || isPausing || isDisconnecting;
|
|
3905
|
+
const handleRoomDisconnected = useCallback8(() => {
|
|
3906
|
+
if (teardownInFlightRef.current)
|
|
3907
|
+
return;
|
|
3908
|
+
disconnect();
|
|
3909
|
+
}, [disconnect]);
|
|
3910
|
+
const resumableSession = resumableSessions.find((s) => s.agentId === agentId) ?? null;
|
|
3911
|
+
const resumeSession = useCallback8(async () => {
|
|
3912
|
+
if (!resumableSession)
|
|
3913
|
+
return;
|
|
3914
|
+
await resumeSessionById({ sessionId: resumableSession.id, agentControls });
|
|
3915
|
+
}, [resumableSession, resumeSessionById, agentControls]);
|
|
3916
|
+
const [isPanelOpen, setIsPanelOpen] = useState11(defaultOpen);
|
|
3917
|
+
const [isMinimized, setIsMinimized] = useState11(minimizable && !defaultOpen);
|
|
3918
|
+
const [sidebarTab, setSidebarTab] = useState11("agenda");
|
|
3919
|
+
const [phasesSnapshot, setPhasesSnapshot] = useState11([]);
|
|
3920
|
+
const {
|
|
3921
|
+
modules: availableModules,
|
|
3922
|
+
isLoading: isLoadingModules,
|
|
3923
|
+
error: modulesError,
|
|
3924
|
+
refetch: refetchModules
|
|
3925
|
+
} = useAvailableModules({
|
|
3926
|
+
enabled: hasModuleSelector && isPanelOpen,
|
|
3927
|
+
bearerToken
|
|
3928
|
+
});
|
|
3929
|
+
const selectModule = useCallback8((moduleId) => {
|
|
3930
|
+
const found = availableModules.find((m) => m.id === moduleId);
|
|
3931
|
+
if (!found)
|
|
3932
|
+
return;
|
|
3933
|
+
setActiveModule(found);
|
|
3934
|
+
const resumable = resumableSessions.find((s) => s.agentId === found.id);
|
|
3935
|
+
if (resumable) {
|
|
3936
|
+
resumeSessionById({ sessionId: resumable.id, agentControls: found.controls });
|
|
3937
|
+
} else {
|
|
3938
|
+
startSession({ agentId: found.id, agentControls: found.controls });
|
|
3939
|
+
}
|
|
3940
|
+
}, [availableModules, resumableSessions, startSession, resumeSessionById]);
|
|
3941
|
+
const [welcomeDismissed, setWelcomeDismissed] = useState11(false);
|
|
3942
|
+
const dismissWelcome = useCallback8(() => setWelcomeDismissed(true), []);
|
|
3943
|
+
const [currentPosition, setCurrentPosition] = useState11(() => {
|
|
3216
3944
|
try {
|
|
3217
3945
|
const saved = localStorage.getItem("skippr_widget_position");
|
|
3218
3946
|
if (saved === "left" || saved === "right")
|
|
@@ -3220,20 +3948,20 @@ function LiveAgent(props) {
|
|
|
3220
3948
|
} catch {}
|
|
3221
3949
|
return position;
|
|
3222
3950
|
});
|
|
3223
|
-
const setPositionWithPersist =
|
|
3951
|
+
const setPositionWithPersist = useCallback8((pos) => {
|
|
3224
3952
|
setCurrentPosition(pos);
|
|
3225
3953
|
try {
|
|
3226
3954
|
localStorage.setItem("skippr_widget_position", pos);
|
|
3227
3955
|
} catch {}
|
|
3228
3956
|
}, []);
|
|
3229
|
-
const openPanel =
|
|
3230
|
-
const closePanel =
|
|
3231
|
-
const togglePanel =
|
|
3232
|
-
const expandPanel =
|
|
3957
|
+
const openPanel = useCallback8(() => setIsPanelOpen(true), []);
|
|
3958
|
+
const closePanel = useCallback8(() => setIsPanelOpen(false), []);
|
|
3959
|
+
const togglePanel = useCallback8(() => setIsPanelOpen((prev) => !prev), []);
|
|
3960
|
+
const expandPanel = useCallback8(() => {
|
|
3233
3961
|
setIsMinimized(false);
|
|
3234
3962
|
setIsPanelOpen(true);
|
|
3235
3963
|
}, []);
|
|
3236
|
-
const minimizePanel =
|
|
3964
|
+
const minimizePanel = useCallback8(() => {
|
|
3237
3965
|
if (!minimizable)
|
|
3238
3966
|
return;
|
|
3239
3967
|
setIsMinimized(true);
|
|
@@ -3241,24 +3969,25 @@ function LiveAgent(props) {
|
|
|
3241
3969
|
}, [minimizable]);
|
|
3242
3970
|
const isConnected = connection !== null;
|
|
3243
3971
|
const isAuthenticated = !!userToken || !!authTokenProp || auth.isAuthenticated;
|
|
3244
|
-
const
|
|
3245
|
-
useEffect14(() => {
|
|
3246
|
-
const connectionChanged = prevConnectionRef.current !== connection;
|
|
3247
|
-
prevConnectionRef.current = connection;
|
|
3248
|
-
if (connectionChanged && minimizable) {
|
|
3249
|
-
setIsMinimized(true);
|
|
3250
|
-
setIsPanelOpen(false);
|
|
3251
|
-
}
|
|
3252
|
-
}, [connection, minimizable]);
|
|
3253
|
-
const ctx = useMemo5(() => ({
|
|
3972
|
+
const ctx = useMemo6(() => ({
|
|
3254
3973
|
connection,
|
|
3255
3974
|
shouldConnect,
|
|
3256
3975
|
isConnected,
|
|
3257
3976
|
isStarting,
|
|
3977
|
+
isDisconnecting,
|
|
3978
|
+
isPausing,
|
|
3258
3979
|
error,
|
|
3259
3980
|
errorCode,
|
|
3260
3981
|
startSession,
|
|
3982
|
+
pauseSession,
|
|
3983
|
+
resumeSession,
|
|
3261
3984
|
disconnect,
|
|
3985
|
+
isPaused,
|
|
3986
|
+
resumableSession,
|
|
3987
|
+
resumableSessions,
|
|
3988
|
+
historyMessages,
|
|
3989
|
+
phasesSnapshot,
|
|
3990
|
+
setPhasesSnapshot,
|
|
3262
3991
|
isPanelOpen,
|
|
3263
3992
|
openPanel,
|
|
3264
3993
|
closePanel,
|
|
@@ -3281,16 +4010,33 @@ function LiveAgent(props) {
|
|
|
3281
4010
|
setSidebarTab,
|
|
3282
4011
|
autoFocusChat,
|
|
3283
4012
|
captureMode,
|
|
3284
|
-
|
|
4013
|
+
agentId,
|
|
4014
|
+
agentControls,
|
|
4015
|
+
hasModuleSelector,
|
|
4016
|
+
availableModules,
|
|
4017
|
+
activeModule,
|
|
4018
|
+
isLoadingModules,
|
|
4019
|
+
modulesError,
|
|
4020
|
+
refetchModules,
|
|
4021
|
+
selectModule
|
|
3285
4022
|
}), [
|
|
3286
4023
|
connection,
|
|
3287
4024
|
shouldConnect,
|
|
3288
4025
|
isConnected,
|
|
3289
4026
|
isStarting,
|
|
4027
|
+
isDisconnecting,
|
|
4028
|
+
isPausing,
|
|
3290
4029
|
error,
|
|
3291
4030
|
errorCode,
|
|
3292
4031
|
startSession,
|
|
4032
|
+
pauseSession,
|
|
4033
|
+
resumeSession,
|
|
3293
4034
|
disconnect,
|
|
4035
|
+
isPaused,
|
|
4036
|
+
resumableSession,
|
|
4037
|
+
resumableSessions,
|
|
4038
|
+
historyMessages,
|
|
4039
|
+
phasesSnapshot,
|
|
3294
4040
|
isPanelOpen,
|
|
3295
4041
|
openPanel,
|
|
3296
4042
|
closePanel,
|
|
@@ -3312,33 +4058,41 @@ function LiveAgent(props) {
|
|
|
3312
4058
|
sidebarTab,
|
|
3313
4059
|
autoFocusChat,
|
|
3314
4060
|
captureMode,
|
|
3315
|
-
|
|
4061
|
+
agentId,
|
|
4062
|
+
agentControls,
|
|
4063
|
+
hasModuleSelector,
|
|
4064
|
+
availableModules,
|
|
4065
|
+
activeModule,
|
|
4066
|
+
isLoadingModules,
|
|
4067
|
+
modulesError,
|
|
4068
|
+
refetchModules,
|
|
4069
|
+
selectModule
|
|
3316
4070
|
]);
|
|
3317
|
-
return /* @__PURE__ */
|
|
4071
|
+
return /* @__PURE__ */ jsx20(LiveAgentContext.Provider, {
|
|
3318
4072
|
value: ctx,
|
|
3319
|
-
children: /* @__PURE__ */
|
|
4073
|
+
children: /* @__PURE__ */ jsxs17(LiveKitRoom, {
|
|
3320
4074
|
serverUrl: connection?.livekitUrl,
|
|
3321
4075
|
token: connection?.token,
|
|
3322
4076
|
connect: shouldConnect,
|
|
3323
4077
|
audio: true,
|
|
3324
|
-
onDisconnected:
|
|
4078
|
+
onDisconnected: handleRoomDisconnected,
|
|
3325
4079
|
children: [
|
|
3326
|
-
connection && /* @__PURE__ */
|
|
3327
|
-
connection && captureMode === "screenshare" && /* @__PURE__ */
|
|
4080
|
+
connection && /* @__PURE__ */ jsx20(RoomAudioRenderer, {}),
|
|
4081
|
+
connection && captureMode === "screenshare" && /* @__PURE__ */ jsx20(AutoStartMedia, {
|
|
3328
4082
|
pendingScreenStream
|
|
3329
4083
|
}),
|
|
3330
|
-
connection && captureMode === "auto" && /* @__PURE__ */
|
|
3331
|
-
connection && captureMode === "auto" && agentControls?.highlight && /* @__PURE__ */
|
|
3332
|
-
/* @__PURE__ */
|
|
4084
|
+
connection && captureMode === "auto" && /* @__PURE__ */ jsx20(DomCapture, {}),
|
|
4085
|
+
connection && captureMode === "auto" && agentControls?.highlight && /* @__PURE__ */ jsx20(HighlightOverlay, {}),
|
|
4086
|
+
/* @__PURE__ */ jsxs17("div", {
|
|
3333
4087
|
id: WIDGET_ROOT_ID,
|
|
3334
4088
|
children: [
|
|
3335
|
-
isMinimized && /* @__PURE__ */
|
|
4089
|
+
isMinimized && /* @__PURE__ */ jsx20(MinimizedBubble, {
|
|
3336
4090
|
welcomeMessage,
|
|
3337
4091
|
welcomeDismissed,
|
|
3338
4092
|
onDismissWelcome: dismissWelcome
|
|
3339
4093
|
}),
|
|
3340
|
-
/* @__PURE__ */
|
|
3341
|
-
/* @__PURE__ */
|
|
4094
|
+
/* @__PURE__ */ jsx20(SidebarTrigger, {}),
|
|
4095
|
+
/* @__PURE__ */ jsx20(Sidebar, {
|
|
3342
4096
|
hideControls,
|
|
3343
4097
|
hideHeader,
|
|
3344
4098
|
startSessionLabel
|