@skippr/live-agent-sdk 0.16.0 → 0.17.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/dist/esm/lib-exports.js +802 -459
- package/dist/skippr-sdk.css +1 -1
- package/dist/skippr-sdk.js +119 -119
- package/dist/types/components/ChatHeader.d.ts +2 -2
- package/dist/types/components/LiveAgent.d.ts +4 -1
- package/dist/types/components/MinimizedBubble.d.ts +1 -0
- package/dist/types/components/SettingsView.d.ts +5 -0
- package/dist/types/components/SidebarTrigger.d.ts +1 -1
- package/dist/types/context/LiveAgentContext.d.ts +7 -0
- package/dist/types/lib/constants.d.ts +1 -1
- package/package.json +1 -1
package/dist/esm/lib-exports.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/components/LiveAgent.tsx
|
|
2
2
|
import { LiveKitRoom, RoomAudioRenderer } from "@livekit/components-react";
|
|
3
|
-
import { useCallback as
|
|
3
|
+
import { useCallback as useCallback8, useEffect as useEffect8, useMemo as useMemo4, useState as useState8 } from "react";
|
|
4
4
|
|
|
5
5
|
// src/context/LiveAgentContext.tsx
|
|
6
6
|
import { createContext } from "react";
|
|
@@ -243,188 +243,9 @@ function useSession({ agentId, authToken, appKey, userToken }) {
|
|
|
243
243
|
return { connection, shouldConnect, isStarting, error, startSession, disconnect };
|
|
244
244
|
}
|
|
245
245
|
|
|
246
|
-
// src/components/
|
|
247
|
-
import {
|
|
248
|
-
import {
|
|
249
|
-
import { useEffect as useEffect7 } from "react";
|
|
250
|
-
|
|
251
|
-
// src/hooks/useCombinedMessages.ts
|
|
252
|
-
import { useVoiceAssistant } from "@livekit/components-react";
|
|
253
|
-
import { useMemo as useMemo3 } from "react";
|
|
254
|
-
|
|
255
|
-
// src/hooks/useChatMessages.ts
|
|
256
|
-
import { useChat, useLocalParticipant } from "@livekit/components-react";
|
|
257
|
-
import { useMemo } from "react";
|
|
258
|
-
|
|
259
|
-
// src/lib/filterSystemMessages.ts
|
|
260
|
-
var SYSTEM_MESSAGE_PATTERN = /^\[\w+\]$/;
|
|
261
|
-
function filterSystemMessages(messages) {
|
|
262
|
-
return messages.filter((m) => !SYSTEM_MESSAGE_PATTERN.test(m.content.trim()));
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
// src/hooks/useChatMessages.ts
|
|
266
|
-
function useChatMessages() {
|
|
267
|
-
const { chatMessages: rawMessages, send, isSending } = useChat();
|
|
268
|
-
const { localParticipant } = useLocalParticipant();
|
|
269
|
-
const localIdentity = localParticipant.identity;
|
|
270
|
-
const chatMessages = useMemo(() => {
|
|
271
|
-
const sortedMessages = rawMessages.map((msg) => ({
|
|
272
|
-
id: msg.id,
|
|
273
|
-
role: msg.from?.identity === localIdentity ? "user" : "assistant",
|
|
274
|
-
content: msg.message,
|
|
275
|
-
source: "chat",
|
|
276
|
-
timestamp: msg.timestamp
|
|
277
|
-
})).sort((a, b) => (a.timestamp ?? 0) - (b.timestamp ?? 0));
|
|
278
|
-
return filterSystemMessages(sortedMessages);
|
|
279
|
-
}, [rawMessages, localIdentity]);
|
|
280
|
-
return { chatMessages, sendChatMessage: send, isSendingChat: isSending };
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
// src/hooks/useStreamingTranscript.ts
|
|
284
|
-
import { useLocalParticipant as useLocalParticipant2, useTranscriptions } from "@livekit/components-react";
|
|
285
|
-
import { useMemo as useMemo2 } from "react";
|
|
286
|
-
function useStreamingTranscript() {
|
|
287
|
-
const transcriptions = useTranscriptions();
|
|
288
|
-
const { localParticipant } = useLocalParticipant2();
|
|
289
|
-
const localIdentity = localParticipant.identity;
|
|
290
|
-
const transcriptMessages = useMemo2(() => filterSystemMessages(transcriptions.filter((stream) => stream.text.trim().length > 0).map((stream) => ({
|
|
291
|
-
id: stream.streamInfo.id,
|
|
292
|
-
role: stream.participantInfo.identity === localIdentity ? "user" : "assistant",
|
|
293
|
-
content: stream.text,
|
|
294
|
-
source: "voice-transcript",
|
|
295
|
-
timestamp: stream.streamInfo.timestamp
|
|
296
|
-
}))), [transcriptions, localIdentity]);
|
|
297
|
-
return { transcriptMessages };
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
// src/hooks/useCombinedMessages.ts
|
|
301
|
-
function mergeChatsIntoTranscripts(transcripts, chats) {
|
|
302
|
-
const merged = [];
|
|
303
|
-
let chatIndex = 0;
|
|
304
|
-
for (const transcript of transcripts) {
|
|
305
|
-
while (chatIndex < chats.length && (chats[chatIndex].timestamp ?? 0) <= (transcript.timestamp ?? 0)) {
|
|
306
|
-
merged.push(chats[chatIndex]);
|
|
307
|
-
chatIndex++;
|
|
308
|
-
}
|
|
309
|
-
merged.push(transcript);
|
|
310
|
-
}
|
|
311
|
-
while (chatIndex < chats.length) {
|
|
312
|
-
merged.push(chats[chatIndex]);
|
|
313
|
-
chatIndex++;
|
|
314
|
-
}
|
|
315
|
-
return merged;
|
|
316
|
-
}
|
|
317
|
-
function useCombinedMessages() {
|
|
318
|
-
const { transcriptMessages } = useStreamingTranscript();
|
|
319
|
-
const { chatMessages, sendChatMessage, isSendingChat } = useChatMessages();
|
|
320
|
-
const { state: agentState } = useVoiceAssistant();
|
|
321
|
-
const allMessages = useMemo3(() => {
|
|
322
|
-
if (chatMessages.length === 0)
|
|
323
|
-
return transcriptMessages;
|
|
324
|
-
if (transcriptMessages.length === 0)
|
|
325
|
-
return chatMessages;
|
|
326
|
-
return mergeChatsIntoTranscripts(transcriptMessages, chatMessages);
|
|
327
|
-
}, [transcriptMessages, chatMessages]);
|
|
328
|
-
return { allMessages, agentState, sendChatMessage, isSendingChat };
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
// src/hooks/useLiveAgent.ts
|
|
332
|
-
import { use } from "react";
|
|
333
|
-
function useLiveAgent() {
|
|
334
|
-
const ctx = use(LiveAgentContext);
|
|
335
|
-
if (!ctx) {
|
|
336
|
-
throw new Error("useLiveAgent must be used within a <LiveAgent> provider");
|
|
337
|
-
}
|
|
338
|
-
const { connection, shouldConnect, ...publicValue } = ctx;
|
|
339
|
-
return publicValue;
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
// src/hooks/usePhaseUpdates.ts
|
|
343
|
-
import { useCallback as useCallback3 } from "react";
|
|
344
|
-
|
|
345
|
-
// src/hooks/useAgentState.ts
|
|
346
|
-
import { useRemoteParticipants } from "@livekit/components-react";
|
|
347
|
-
import { useEffect as useEffect3, useState as useState3 } from "react";
|
|
348
|
-
function useAgentState(attributeKey, parse, initial) {
|
|
349
|
-
const [value, setValue] = useState3(initial);
|
|
350
|
-
const remoteParticipants = useRemoteParticipants();
|
|
351
|
-
useEffect3(() => {
|
|
352
|
-
const agentParticipant = remoteParticipants.find((p) => p.attributes?.[attributeKey]);
|
|
353
|
-
if (agentParticipant) {
|
|
354
|
-
const attr = agentParticipant.attributes?.[attributeKey];
|
|
355
|
-
if (attr) {
|
|
356
|
-
const parsed = parse(attr);
|
|
357
|
-
if (parsed)
|
|
358
|
-
setValue(parsed);
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
const handlers = new Map;
|
|
362
|
-
for (const p of remoteParticipants) {
|
|
363
|
-
const handler = (changedAttributes) => {
|
|
364
|
-
if (changedAttributes[attributeKey]) {
|
|
365
|
-
const parsed = parse(changedAttributes[attributeKey]);
|
|
366
|
-
if (parsed)
|
|
367
|
-
setValue(parsed);
|
|
368
|
-
} else if (p.attributes?.[attributeKey]) {
|
|
369
|
-
const parsed = parse(p.attributes[attributeKey]);
|
|
370
|
-
if (parsed)
|
|
371
|
-
setValue(parsed);
|
|
372
|
-
}
|
|
373
|
-
};
|
|
374
|
-
handlers.set(p, handler);
|
|
375
|
-
p.on("attributesChanged", handler);
|
|
376
|
-
}
|
|
377
|
-
return () => {
|
|
378
|
-
for (const [p, handler] of handlers) {
|
|
379
|
-
p.off("attributesChanged", handler);
|
|
380
|
-
}
|
|
381
|
-
};
|
|
382
|
-
}, [remoteParticipants, attributeKey, parse]);
|
|
383
|
-
return value;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
// src/hooks/usePhaseUpdates.ts
|
|
387
|
-
function parsePhases(json) {
|
|
388
|
-
try {
|
|
389
|
-
const data = JSON.parse(json);
|
|
390
|
-
if (data.type === "phase_update" && Array.isArray(data.phases)) {
|
|
391
|
-
return data.phases;
|
|
392
|
-
}
|
|
393
|
-
} catch {}
|
|
394
|
-
return null;
|
|
395
|
-
}
|
|
396
|
-
function usePhaseUpdates() {
|
|
397
|
-
const parse = useCallback3(parsePhases, []);
|
|
398
|
-
const phases = useAgentState("phases", parse, []);
|
|
399
|
-
return { phases };
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
// src/hooks/useQuestionUpdates.ts
|
|
403
|
-
import { useCallback as useCallback4 } from "react";
|
|
404
|
-
function parseQuestions(json) {
|
|
405
|
-
try {
|
|
406
|
-
const data = JSON.parse(json);
|
|
407
|
-
if (data.type === "question_update" && Array.isArray(data.questions)) {
|
|
408
|
-
return data.questions;
|
|
409
|
-
}
|
|
410
|
-
} catch {}
|
|
411
|
-
return null;
|
|
412
|
-
}
|
|
413
|
-
function useQuestionUpdates() {
|
|
414
|
-
const parse = useCallback4(parseQuestions, []);
|
|
415
|
-
const questions = useAgentState("questions", parse, []);
|
|
416
|
-
return { questions };
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
// src/lib/constants.ts
|
|
420
|
-
var SIDEBAR_WIDTH = 600;
|
|
421
|
-
|
|
422
|
-
// src/lib/utils.ts
|
|
423
|
-
import { clsx } from "clsx";
|
|
424
|
-
import { twMerge } from "tailwind-merge";
|
|
425
|
-
function cn(...inputs) {
|
|
426
|
-
return twMerge(clsx(inputs));
|
|
427
|
-
}
|
|
246
|
+
// src/components/MinimizedBubble.tsx
|
|
247
|
+
import { useLocalParticipant, useVoiceAssistant } from "@livekit/components-react";
|
|
248
|
+
import { ScreenSharePresets } from "livekit-client";
|
|
428
249
|
// ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/createLucideIcon.js
|
|
429
250
|
import { forwardRef as forwardRef2, createElement as createElement2 } from "react";
|
|
430
251
|
|
|
@@ -524,112 +345,471 @@ var __iconNode2 = [
|
|
|
524
345
|
["path", { d: "M12 17h.01", key: "p32p05" }]
|
|
525
346
|
];
|
|
526
347
|
var MessageCircleQuestionMark = createLucideIcon("message-circle-question-mark", __iconNode2);
|
|
527
|
-
// ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/
|
|
348
|
+
// ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/panel-left.js
|
|
528
349
|
var __iconNode3 = [
|
|
350
|
+
["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", key: "afitv7" }],
|
|
351
|
+
["path", { d: "M9 3v18", key: "fh3hqa" }]
|
|
352
|
+
];
|
|
353
|
+
var PanelLeft = createLucideIcon("panel-left", __iconNode3);
|
|
354
|
+
// ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/send-horizontal.js
|
|
355
|
+
var __iconNode4 = [
|
|
529
356
|
[
|
|
530
357
|
"path",
|
|
531
358
|
{
|
|
532
359
|
d: "M3.714 3.048a.498.498 0 0 0-.683.627l2.843 7.627a2 2 0 0 1 0 1.396l-2.842 7.627a.498.498 0 0 0 .682.627l18-8.5a.5.5 0 0 0 0-.904z",
|
|
533
360
|
key: "117uat"
|
|
534
361
|
}
|
|
535
|
-
],
|
|
536
|
-
["path", { d: "M6 12h16", key: "s4cdu5" }]
|
|
537
|
-
];
|
|
538
|
-
var SendHorizontal = createLucideIcon("send-horizontal",
|
|
539
|
-
// ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/
|
|
540
|
-
var
|
|
541
|
-
["path", { d: "
|
|
542
|
-
["
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
]
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
var
|
|
555
|
-
// ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/
|
|
556
|
-
var __iconNode7 = [
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
];
|
|
560
|
-
var
|
|
561
|
-
// ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/
|
|
562
|
-
var
|
|
563
|
-
[
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
362
|
+
],
|
|
363
|
+
["path", { d: "M6 12h16", key: "s4cdu5" }]
|
|
364
|
+
];
|
|
365
|
+
var SendHorizontal = createLucideIcon("send-horizontal", __iconNode4);
|
|
366
|
+
// ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/arrow-left.js
|
|
367
|
+
var __iconNode5 = [
|
|
368
|
+
["path", { d: "m12 19-7-7 7-7", key: "1l729n" }],
|
|
369
|
+
["path", { d: "M19 12H5", key: "x3x0zl" }]
|
|
370
|
+
];
|
|
371
|
+
var ArrowLeft = createLucideIcon("arrow-left", __iconNode5);
|
|
372
|
+
// ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/bot.js
|
|
373
|
+
var __iconNode6 = [
|
|
374
|
+
["path", { d: "M12 8V4H8", key: "hb8ula" }],
|
|
375
|
+
["rect", { width: "16", height: "12", x: "4", y: "8", rx: "2", key: "enze0r" }],
|
|
376
|
+
["path", { d: "M2 14h2", key: "vft8re" }],
|
|
377
|
+
["path", { d: "M20 14h2", key: "4cs60a" }],
|
|
378
|
+
["path", { d: "M15 13v2", key: "1xurst" }],
|
|
379
|
+
["path", { d: "M9 13v2", key: "rq6x2g" }]
|
|
380
|
+
];
|
|
381
|
+
var Bot = createLucideIcon("bot", __iconNode6);
|
|
382
|
+
// ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/check.js
|
|
383
|
+
var __iconNode7 = [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]];
|
|
384
|
+
var Check = createLucideIcon("check", __iconNode7);
|
|
385
|
+
// ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/circle.js
|
|
386
|
+
var __iconNode8 = [["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }]];
|
|
387
|
+
var Circle = createLucideIcon("circle", __iconNode8);
|
|
388
|
+
// ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/mail.js
|
|
389
|
+
var __iconNode9 = [
|
|
390
|
+
["path", { d: "m22 7-8.991 5.727a2 2 0 0 1-2.009 0L2 7", key: "132q7q" }],
|
|
391
|
+
["rect", { x: "2", y: "4", width: "20", height: "16", rx: "2", key: "izxlao" }]
|
|
392
|
+
];
|
|
393
|
+
var Mail = createLucideIcon("mail", __iconNode9);
|
|
394
|
+
// ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/message-circle.js
|
|
395
|
+
var __iconNode10 = [
|
|
396
|
+
[
|
|
397
|
+
"path",
|
|
398
|
+
{
|
|
399
|
+
d: "M2.992 16.342a2 2 0 0 1 .094 1.167l-1.065 3.29a1 1 0 0 0 1.236 1.168l3.413-.998a2 2 0 0 1 1.099.092 10 10 0 1 0-4.777-4.719",
|
|
400
|
+
key: "1sd12s"
|
|
401
|
+
}
|
|
402
|
+
]
|
|
403
|
+
];
|
|
404
|
+
var MessageCircle = createLucideIcon("message-circle", __iconNode10);
|
|
405
|
+
// ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/mic-off.js
|
|
406
|
+
var __iconNode11 = [
|
|
407
|
+
["path", { d: "M12 19v3", key: "npa21l" }],
|
|
408
|
+
["path", { d: "M15 9.34V5a3 3 0 0 0-5.68-1.33", key: "1gzdoj" }],
|
|
409
|
+
["path", { d: "M16.95 16.95A7 7 0 0 1 5 12v-2", key: "cqa7eg" }],
|
|
410
|
+
["path", { d: "M18.89 13.23A7 7 0 0 0 19 12v-2", key: "16hl24" }],
|
|
411
|
+
["path", { d: "m2 2 20 20", key: "1ooewy" }],
|
|
412
|
+
["path", { d: "M9 9v3a3 3 0 0 0 5.12 2.12", key: "r2i35w" }]
|
|
413
|
+
];
|
|
414
|
+
var MicOff = createLucideIcon("mic-off", __iconNode11);
|
|
415
|
+
// ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/mic.js
|
|
416
|
+
var __iconNode12 = [
|
|
417
|
+
["path", { d: "M12 19v3", key: "npa21l" }],
|
|
418
|
+
["path", { d: "M19 10v2a7 7 0 0 1-14 0v-2", key: "1vc78b" }],
|
|
419
|
+
["rect", { x: "9", y: "2", width: "6", height: "13", rx: "3", key: "s6n7sd" }]
|
|
420
|
+
];
|
|
421
|
+
var Mic = createLucideIcon("mic", __iconNode12);
|
|
422
|
+
// ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/minimize-2.js
|
|
423
|
+
var __iconNode13 = [
|
|
424
|
+
["path", { d: "m14 10 7-7", key: "oa77jy" }],
|
|
425
|
+
["path", { d: "M20 10h-6V4", key: "mjg0md" }],
|
|
426
|
+
["path", { d: "m3 21 7-7", key: "tjx5ai" }],
|
|
427
|
+
["path", { d: "M4 14h6v6", key: "rmj7iw" }]
|
|
428
|
+
];
|
|
429
|
+
var Minimize2 = createLucideIcon("minimize-2", __iconNode13);
|
|
430
|
+
// ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/monitor-off.js
|
|
431
|
+
var __iconNode14 = [
|
|
432
|
+
["path", { d: "M12 17v4", key: "1riwvh" }],
|
|
433
|
+
["path", { d: "M17 17H4a2 2 0 0 1-2-2V5a2 2 0 0 1 1.184-1.826", key: "cv7jms" }],
|
|
434
|
+
["path", { d: "m2 2 20 20", key: "1ooewy" }],
|
|
435
|
+
["path", { d: "M8 21h8", key: "1ev6f3" }],
|
|
436
|
+
["path", { d: "M8.656 3H20a2 2 0 0 1 2 2v10a2 2 0 0 1-.293 1.042", key: "z8ni2w" }]
|
|
437
|
+
];
|
|
438
|
+
var MonitorOff = createLucideIcon("monitor-off", __iconNode14);
|
|
439
|
+
// ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/monitor.js
|
|
440
|
+
var __iconNode15 = [
|
|
441
|
+
["rect", { width: "20", height: "14", x: "2", y: "3", rx: "2", key: "48i651" }],
|
|
442
|
+
["line", { x1: "8", x2: "16", y1: "21", y2: "21", key: "1svkeh" }],
|
|
443
|
+
["line", { x1: "12", x2: "12", y1: "17", y2: "21", key: "vw1qmm" }]
|
|
444
|
+
];
|
|
445
|
+
var Monitor = createLucideIcon("monitor", __iconNode15);
|
|
446
|
+
// ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/panel-right.js
|
|
447
|
+
var __iconNode16 = [
|
|
448
|
+
["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", key: "afitv7" }],
|
|
449
|
+
["path", { d: "M15 3v18", key: "14nvp0" }]
|
|
450
|
+
];
|
|
451
|
+
var PanelRight = createLucideIcon("panel-right", __iconNode16);
|
|
452
|
+
// ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/phone-off.js
|
|
453
|
+
var __iconNode17 = [
|
|
454
|
+
[
|
|
455
|
+
"path",
|
|
456
|
+
{
|
|
457
|
+
d: "M10.1 13.9a14 14 0 0 0 3.732 2.668 1 1 0 0 0 1.213-.303l.355-.465A2 2 0 0 1 17 15h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2 18 18 0 0 1-12.728-5.272",
|
|
458
|
+
key: "1wngk7"
|
|
459
|
+
}
|
|
460
|
+
],
|
|
461
|
+
["path", { d: "M22 2 2 22", key: "y4kqgn" }],
|
|
462
|
+
[
|
|
463
|
+
"path",
|
|
464
|
+
{
|
|
465
|
+
d: "M4.76 13.582A18 18 0 0 1 2 4a2 2 0 0 1 2-2h3a2 2 0 0 1 2 2v3a2 2 0 0 1-.8 1.6l-.468.351a1 1 0 0 0-.292 1.233 14 14 0 0 0 .244.473",
|
|
466
|
+
key: "10hv5p"
|
|
467
|
+
}
|
|
468
|
+
]
|
|
469
|
+
];
|
|
470
|
+
var PhoneOff = createLucideIcon("phone-off", __iconNode17);
|
|
471
|
+
// ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/settings.js
|
|
472
|
+
var __iconNode18 = [
|
|
473
|
+
[
|
|
474
|
+
"path",
|
|
475
|
+
{
|
|
476
|
+
d: "M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915",
|
|
477
|
+
key: "1i5ecw"
|
|
478
|
+
}
|
|
479
|
+
],
|
|
480
|
+
["circle", { cx: "12", cy: "12", r: "3", key: "1v7zrd" }]
|
|
481
|
+
];
|
|
482
|
+
var Settings = createLucideIcon("settings", __iconNode18);
|
|
483
|
+
// ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/x.js
|
|
484
|
+
var __iconNode19 = [
|
|
485
|
+
["path", { d: "M18 6 6 18", key: "1bl5f8" }],
|
|
486
|
+
["path", { d: "m6 6 12 12", key: "d8bk6v" }]
|
|
487
|
+
];
|
|
488
|
+
var X = createLucideIcon("x", __iconNode19);
|
|
489
|
+
// src/components/MinimizedBubble.tsx
|
|
490
|
+
import { useCallback as useCallback3 } from "react";
|
|
491
|
+
|
|
492
|
+
// src/hooks/useLiveAgent.ts
|
|
493
|
+
import { use } from "react";
|
|
494
|
+
function useLiveAgent() {
|
|
495
|
+
const ctx = use(LiveAgentContext);
|
|
496
|
+
if (!ctx) {
|
|
497
|
+
throw new Error("useLiveAgent must be used within a <LiveAgent> provider");
|
|
498
|
+
}
|
|
499
|
+
const { connection, shouldConnect, ...publicValue } = ctx;
|
|
500
|
+
return publicValue;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
// src/lib/utils.ts
|
|
504
|
+
import { clsx } from "clsx";
|
|
505
|
+
import { twMerge } from "tailwind-merge";
|
|
506
|
+
function cn(...inputs) {
|
|
507
|
+
return twMerge(clsx(inputs));
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// src/components/MinimizedBubble.tsx
|
|
511
|
+
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
512
|
+
function AgentAvatar({ agentState }) {
|
|
513
|
+
if (agentState === "speaking") {
|
|
514
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
515
|
+
className: "skippr:flex skippr:items-end skippr:justify-center skippr:gap-[3px] skippr:h-5",
|
|
516
|
+
children: [
|
|
517
|
+
/* @__PURE__ */ jsx("span", {
|
|
518
|
+
className: "skippr:w-[3px] skippr:h-full skippr:rounded-full skippr:bg-primary-foreground skippr:origin-bottom skippr:animate-skippr-bar-1"
|
|
519
|
+
}),
|
|
520
|
+
/* @__PURE__ */ jsx("span", {
|
|
521
|
+
className: "skippr:w-[3px] skippr:h-full skippr:rounded-full skippr:bg-primary-foreground skippr:origin-bottom skippr:animate-skippr-bar-2"
|
|
522
|
+
}),
|
|
523
|
+
/* @__PURE__ */ jsx("span", {
|
|
524
|
+
className: "skippr:w-[3px] skippr:h-full skippr:rounded-full skippr:bg-primary-foreground skippr:origin-bottom skippr:animate-skippr-bar-3"
|
|
525
|
+
}),
|
|
526
|
+
/* @__PURE__ */ jsx("span", {
|
|
527
|
+
className: "skippr:w-[3px] skippr:h-full skippr:rounded-full skippr:bg-primary-foreground skippr:origin-bottom skippr:animate-skippr-bar-4"
|
|
528
|
+
})
|
|
529
|
+
]
|
|
530
|
+
});
|
|
531
|
+
}
|
|
532
|
+
if (agentState === "listening") {
|
|
533
|
+
return /* @__PURE__ */ jsx(Bot, {
|
|
534
|
+
className: "skippr:relative skippr:z-10 skippr:size-5 skippr:animate-skippr-breathe"
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
if (agentState === "thinking") {
|
|
538
|
+
return /* @__PURE__ */ jsx(Bot, {
|
|
539
|
+
className: "skippr:relative skippr:z-10 skippr:size-5 skippr:animate-pulse"
|
|
540
|
+
});
|
|
541
|
+
}
|
|
542
|
+
return /* @__PURE__ */ jsx(Bot, {
|
|
543
|
+
className: "skippr:relative skippr:z-10 skippr:size-5"
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
function MinimizedBubble() {
|
|
547
|
+
const { expandPanel, disconnect, position } = useLiveAgent();
|
|
548
|
+
const { state: agentState } = useVoiceAssistant();
|
|
549
|
+
const { localParticipant } = useLocalParticipant();
|
|
550
|
+
const isMuted = !localParticipant.isMicrophoneEnabled;
|
|
551
|
+
const isScreenSharing = localParticipant.isScreenShareEnabled;
|
|
552
|
+
const toggleMute = useCallback3(async () => {
|
|
553
|
+
try {
|
|
554
|
+
await localParticipant.setMicrophoneEnabled(isMuted);
|
|
555
|
+
} catch (e) {
|
|
556
|
+
console.error("Failed to toggle microphone:", e);
|
|
557
|
+
}
|
|
558
|
+
}, [localParticipant, isMuted]);
|
|
559
|
+
const toggleScreenShare = useCallback3(async () => {
|
|
560
|
+
try {
|
|
561
|
+
await localParticipant.setScreenShareEnabled(!isScreenSharing, {
|
|
562
|
+
video: { displaySurface: "browser" },
|
|
563
|
+
resolution: ScreenSharePresets.h720fps30.resolution,
|
|
564
|
+
contentHint: "detail"
|
|
565
|
+
});
|
|
566
|
+
} catch (e) {
|
|
567
|
+
console.error("Failed to toggle screen share:", e);
|
|
568
|
+
}
|
|
569
|
+
}, [localParticipant, isScreenSharing]);
|
|
570
|
+
const handleHangUp = useCallback3(async () => {
|
|
571
|
+
await disconnect();
|
|
572
|
+
}, [disconnect]);
|
|
573
|
+
const isSpeaking = agentState === "speaking";
|
|
574
|
+
const isListening = agentState === "listening";
|
|
575
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
576
|
+
className: cn("skippr:fixed skippr:bottom-6 skippr:z-[9999]", "skippr:flex skippr:items-center skippr:gap-0", "skippr:rounded-full skippr:bg-card skippr:shadow-2xl", "skippr:border skippr:border-border", "skippr:p-1.5", position === "right" ? "skippr:right-6" : "skippr:left-6"),
|
|
577
|
+
children: [
|
|
578
|
+
/* @__PURE__ */ jsxs("button", {
|
|
579
|
+
type: "button",
|
|
580
|
+
onClick: expandPanel,
|
|
581
|
+
className: cn("skippr:relative skippr:size-11 skippr:rounded-full", "skippr:bg-primary skippr:text-primary-foreground", "skippr:flex skippr:items-center skippr:justify-center", "skippr:cursor-pointer skippr:transition-all skippr:duration-300", "skippr:hover:brightness-110", isListening && "skippr:animate-skippr-pulse-ring"),
|
|
582
|
+
"aria-label": "Expand meeting panel",
|
|
583
|
+
children: [
|
|
584
|
+
isSpeaking && /* @__PURE__ */ jsxs(Fragment, {
|
|
585
|
+
children: [
|
|
586
|
+
/* @__PURE__ */ jsx("span", {
|
|
587
|
+
className: "skippr:absolute skippr:inset-0 skippr:rounded-full skippr:bg-primary skippr:animate-skippr-speak-ripple"
|
|
588
|
+
}),
|
|
589
|
+
/* @__PURE__ */ jsx("span", {
|
|
590
|
+
className: "skippr:absolute skippr:inset-0 skippr:rounded-full skippr:bg-primary skippr:animate-skippr-speak-ripple-delayed"
|
|
591
|
+
})
|
|
592
|
+
]
|
|
593
|
+
}),
|
|
594
|
+
/* @__PURE__ */ jsx(AgentAvatar, {
|
|
595
|
+
agentState
|
|
596
|
+
})
|
|
597
|
+
]
|
|
598
|
+
}),
|
|
599
|
+
/* @__PURE__ */ jsx("div", {
|
|
600
|
+
className: "skippr:mx-1 skippr:h-6 skippr:w-px skippr:bg-border"
|
|
601
|
+
}),
|
|
602
|
+
/* @__PURE__ */ jsxs("div", {
|
|
603
|
+
className: "skippr:flex skippr:items-center skippr:gap-1",
|
|
604
|
+
children: [
|
|
605
|
+
/* @__PURE__ */ jsx("button", {
|
|
606
|
+
type: "button",
|
|
607
|
+
onClick: toggleMute,
|
|
608
|
+
className: cn("skippr:size-9 skippr:rounded-full skippr:flex skippr:items-center skippr:justify-center", "skippr:transition-colors skippr:cursor-pointer", isMuted ? "skippr:bg-destructive skippr:text-white" : "skippr:text-foreground skippr:hover:bg-accent"),
|
|
609
|
+
"aria-label": isMuted ? "Unmute" : "Mute",
|
|
610
|
+
children: isMuted ? /* @__PURE__ */ jsx(MicOff, {
|
|
611
|
+
className: "skippr:size-4"
|
|
612
|
+
}) : /* @__PURE__ */ jsx(Mic, {
|
|
613
|
+
className: "skippr:size-4"
|
|
614
|
+
})
|
|
615
|
+
}),
|
|
616
|
+
/* @__PURE__ */ jsx("button", {
|
|
617
|
+
type: "button",
|
|
618
|
+
onClick: toggleScreenShare,
|
|
619
|
+
className: cn("skippr:size-9 skippr:rounded-full skippr:flex skippr:items-center skippr:justify-center", "skippr:transition-colors skippr:cursor-pointer", isScreenSharing ? "skippr:text-foreground skippr:hover:bg-accent" : "skippr:bg-destructive skippr:text-white"),
|
|
620
|
+
"aria-label": isScreenSharing ? "Stop sharing" : "Share screen",
|
|
621
|
+
children: isScreenSharing ? /* @__PURE__ */ jsx(MonitorOff, {
|
|
622
|
+
className: "skippr:size-4"
|
|
623
|
+
}) : /* @__PURE__ */ jsx(Monitor, {
|
|
624
|
+
className: "skippr:size-4"
|
|
625
|
+
})
|
|
626
|
+
})
|
|
627
|
+
]
|
|
628
|
+
}),
|
|
629
|
+
/* @__PURE__ */ jsx("div", {
|
|
630
|
+
className: "skippr:mx-1 skippr:h-6 skippr:w-px skippr:bg-border"
|
|
631
|
+
}),
|
|
632
|
+
/* @__PURE__ */ jsx("button", {
|
|
633
|
+
type: "button",
|
|
634
|
+
onClick: handleHangUp,
|
|
635
|
+
className: "skippr:size-9 skippr:rounded-full skippr:flex skippr:items-center skippr:justify-center skippr:bg-destructive skippr:text-white skippr:cursor-pointer skippr:transition-colors skippr:hover:bg-destructive/90",
|
|
636
|
+
"aria-label": "Hang up",
|
|
637
|
+
children: /* @__PURE__ */ jsx(PhoneOff, {
|
|
638
|
+
className: "skippr:size-4"
|
|
639
|
+
})
|
|
640
|
+
})
|
|
641
|
+
]
|
|
642
|
+
});
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
// src/components/Sidebar.tsx
|
|
646
|
+
import { useConnectionState } from "@livekit/components-react";
|
|
647
|
+
import { ConnectionState } from "livekit-client";
|
|
648
|
+
import { useEffect as useEffect7, useState as useState7 } from "react";
|
|
649
|
+
|
|
650
|
+
// src/hooks/useCombinedMessages.ts
|
|
651
|
+
import { useVoiceAssistant as useVoiceAssistant2 } from "@livekit/components-react";
|
|
652
|
+
import { useMemo as useMemo3 } from "react";
|
|
653
|
+
|
|
654
|
+
// src/hooks/useChatMessages.ts
|
|
655
|
+
import { useChat, useLocalParticipant as useLocalParticipant2 } from "@livekit/components-react";
|
|
656
|
+
import { useMemo } from "react";
|
|
657
|
+
|
|
658
|
+
// src/lib/filterSystemMessages.ts
|
|
659
|
+
var SYSTEM_MESSAGE_PATTERN = /^\[\w+\]$/;
|
|
660
|
+
function filterSystemMessages(messages) {
|
|
661
|
+
return messages.filter((m) => !SYSTEM_MESSAGE_PATTERN.test(m.content.trim()));
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
// src/hooks/useChatMessages.ts
|
|
665
|
+
function useChatMessages() {
|
|
666
|
+
const { chatMessages: rawMessages, send, isSending } = useChat();
|
|
667
|
+
const { localParticipant } = useLocalParticipant2();
|
|
668
|
+
const localIdentity = localParticipant.identity;
|
|
669
|
+
const chatMessages = useMemo(() => {
|
|
670
|
+
const sortedMessages = rawMessages.map((msg) => ({
|
|
671
|
+
id: msg.id,
|
|
672
|
+
role: msg.from?.identity === localIdentity ? "user" : "assistant",
|
|
673
|
+
content: msg.message,
|
|
674
|
+
source: "chat",
|
|
675
|
+
timestamp: msg.timestamp
|
|
676
|
+
})).sort((a, b) => (a.timestamp ?? 0) - (b.timestamp ?? 0));
|
|
677
|
+
return filterSystemMessages(sortedMessages);
|
|
678
|
+
}, [rawMessages, localIdentity]);
|
|
679
|
+
return { chatMessages, sendChatMessage: send, isSendingChat: isSending };
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
// src/hooks/useStreamingTranscript.ts
|
|
683
|
+
import { useLocalParticipant as useLocalParticipant3, useTranscriptions } from "@livekit/components-react";
|
|
684
|
+
import { useMemo as useMemo2 } from "react";
|
|
685
|
+
function useStreamingTranscript() {
|
|
686
|
+
const transcriptions = useTranscriptions();
|
|
687
|
+
const { localParticipant } = useLocalParticipant3();
|
|
688
|
+
const localIdentity = localParticipant.identity;
|
|
689
|
+
const transcriptMessages = useMemo2(() => filterSystemMessages(transcriptions.filter((stream) => stream.text.trim().length > 0).map((stream) => ({
|
|
690
|
+
id: stream.streamInfo.id,
|
|
691
|
+
role: stream.participantInfo.identity === localIdentity ? "user" : "assistant",
|
|
692
|
+
content: stream.text,
|
|
693
|
+
source: "voice-transcript",
|
|
694
|
+
timestamp: stream.streamInfo.timestamp
|
|
695
|
+
}))), [transcriptions, localIdentity]);
|
|
696
|
+
return { transcriptMessages };
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
// src/hooks/useCombinedMessages.ts
|
|
700
|
+
function mergeChatsIntoTranscripts(transcripts, chats) {
|
|
701
|
+
const merged = [];
|
|
702
|
+
let chatIndex = 0;
|
|
703
|
+
for (const transcript of transcripts) {
|
|
704
|
+
while (chatIndex < chats.length && (chats[chatIndex].timestamp ?? 0) <= (transcript.timestamp ?? 0)) {
|
|
705
|
+
merged.push(chats[chatIndex]);
|
|
706
|
+
chatIndex++;
|
|
707
|
+
}
|
|
708
|
+
merged.push(transcript);
|
|
709
|
+
}
|
|
710
|
+
while (chatIndex < chats.length) {
|
|
711
|
+
merged.push(chats[chatIndex]);
|
|
712
|
+
chatIndex++;
|
|
713
|
+
}
|
|
714
|
+
return merged;
|
|
715
|
+
}
|
|
716
|
+
function useCombinedMessages() {
|
|
717
|
+
const { transcriptMessages } = useStreamingTranscript();
|
|
718
|
+
const { chatMessages, sendChatMessage, isSendingChat } = useChatMessages();
|
|
719
|
+
const { state: agentState } = useVoiceAssistant2();
|
|
720
|
+
const allMessages = useMemo3(() => {
|
|
721
|
+
if (chatMessages.length === 0)
|
|
722
|
+
return transcriptMessages;
|
|
723
|
+
if (transcriptMessages.length === 0)
|
|
724
|
+
return chatMessages;
|
|
725
|
+
return mergeChatsIntoTranscripts(transcriptMessages, chatMessages);
|
|
726
|
+
}, [transcriptMessages, chatMessages]);
|
|
727
|
+
return { allMessages, agentState, sendChatMessage, isSendingChat };
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
// src/hooks/usePhaseUpdates.ts
|
|
731
|
+
import { useCallback as useCallback4 } from "react";
|
|
732
|
+
|
|
733
|
+
// src/hooks/useAgentState.ts
|
|
734
|
+
import { useRemoteParticipants } from "@livekit/components-react";
|
|
735
|
+
import { useEffect as useEffect3, useState as useState3 } from "react";
|
|
736
|
+
function useAgentState(attributeKey, parse, initial) {
|
|
737
|
+
const [value, setValue] = useState3(initial);
|
|
738
|
+
const remoteParticipants = useRemoteParticipants();
|
|
739
|
+
useEffect3(() => {
|
|
740
|
+
const agentParticipant = remoteParticipants.find((p) => p.attributes?.[attributeKey]);
|
|
741
|
+
if (agentParticipant) {
|
|
742
|
+
const attr = agentParticipant.attributes?.[attributeKey];
|
|
743
|
+
if (attr) {
|
|
744
|
+
const parsed = parse(attr);
|
|
745
|
+
if (parsed)
|
|
746
|
+
setValue(parsed);
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
const handlers = new Map;
|
|
750
|
+
for (const p of remoteParticipants) {
|
|
751
|
+
const handler = (changedAttributes) => {
|
|
752
|
+
if (changedAttributes[attributeKey]) {
|
|
753
|
+
const parsed = parse(changedAttributes[attributeKey]);
|
|
754
|
+
if (parsed)
|
|
755
|
+
setValue(parsed);
|
|
756
|
+
} else if (p.attributes?.[attributeKey]) {
|
|
757
|
+
const parsed = parse(p.attributes[attributeKey]);
|
|
758
|
+
if (parsed)
|
|
759
|
+
setValue(parsed);
|
|
760
|
+
}
|
|
761
|
+
};
|
|
762
|
+
handlers.set(p, handler);
|
|
763
|
+
p.on("attributesChanged", handler);
|
|
568
764
|
}
|
|
569
|
-
|
|
570
|
-
]
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
[
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
["path", { d: "M12 19v3", key: "npa21l" }],
|
|
585
|
-
["path", { d: "M19 10v2a7 7 0 0 1-14 0v-2", key: "1vc78b" }],
|
|
586
|
-
["rect", { x: "9", y: "2", width: "6", height: "13", rx: "3", key: "s6n7sd" }]
|
|
587
|
-
];
|
|
588
|
-
var Mic = createLucideIcon("mic", __iconNode10);
|
|
589
|
-
// ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/monitor-off.js
|
|
590
|
-
var __iconNode11 = [
|
|
591
|
-
["path", { d: "M12 17v4", key: "1riwvh" }],
|
|
592
|
-
["path", { d: "M17 17H4a2 2 0 0 1-2-2V5a2 2 0 0 1 1.184-1.826", key: "cv7jms" }],
|
|
593
|
-
["path", { d: "m2 2 20 20", key: "1ooewy" }],
|
|
594
|
-
["path", { d: "M8 21h8", key: "1ev6f3" }],
|
|
595
|
-
["path", { d: "M8.656 3H20a2 2 0 0 1 2 2v10a2 2 0 0 1-.293 1.042", key: "z8ni2w" }]
|
|
596
|
-
];
|
|
597
|
-
var MonitorOff = createLucideIcon("monitor-off", __iconNode11);
|
|
598
|
-
// ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/monitor.js
|
|
599
|
-
var __iconNode12 = [
|
|
600
|
-
["rect", { width: "20", height: "14", x: "2", y: "3", rx: "2", key: "48i651" }],
|
|
601
|
-
["line", { x1: "8", x2: "16", y1: "21", y2: "21", key: "1svkeh" }],
|
|
602
|
-
["line", { x1: "12", x2: "12", y1: "17", y2: "21", key: "vw1qmm" }]
|
|
603
|
-
];
|
|
604
|
-
var Monitor = createLucideIcon("monitor", __iconNode12);
|
|
605
|
-
// ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/phone-off.js
|
|
606
|
-
var __iconNode13 = [
|
|
607
|
-
[
|
|
608
|
-
"path",
|
|
609
|
-
{
|
|
610
|
-
d: "M10.1 13.9a14 14 0 0 0 3.732 2.668 1 1 0 0 0 1.213-.303l.355-.465A2 2 0 0 1 17 15h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2 18 18 0 0 1-12.728-5.272",
|
|
611
|
-
key: "1wngk7"
|
|
765
|
+
return () => {
|
|
766
|
+
for (const [p, handler] of handlers) {
|
|
767
|
+
p.off("attributesChanged", handler);
|
|
768
|
+
}
|
|
769
|
+
};
|
|
770
|
+
}, [remoteParticipants, attributeKey, parse]);
|
|
771
|
+
return value;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
// src/hooks/usePhaseUpdates.ts
|
|
775
|
+
function parsePhases(json) {
|
|
776
|
+
try {
|
|
777
|
+
const data = JSON.parse(json);
|
|
778
|
+
if (data.type === "phase_update" && Array.isArray(data.phases)) {
|
|
779
|
+
return data.phases;
|
|
612
780
|
}
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
781
|
+
} catch {}
|
|
782
|
+
return null;
|
|
783
|
+
}
|
|
784
|
+
function usePhaseUpdates() {
|
|
785
|
+
const parse = useCallback4(parsePhases, []);
|
|
786
|
+
const phases = useAgentState("phases", parse, []);
|
|
787
|
+
return { phases };
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
// src/hooks/useQuestionUpdates.ts
|
|
791
|
+
import { useCallback as useCallback5 } from "react";
|
|
792
|
+
function parseQuestions(json) {
|
|
793
|
+
try {
|
|
794
|
+
const data = JSON.parse(json);
|
|
795
|
+
if (data.type === "question_update" && Array.isArray(data.questions)) {
|
|
796
|
+
return data.questions;
|
|
620
797
|
}
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
798
|
+
} catch {}
|
|
799
|
+
return null;
|
|
800
|
+
}
|
|
801
|
+
function useQuestionUpdates() {
|
|
802
|
+
const parse = useCallback5(parseQuestions, []);
|
|
803
|
+
const questions = useAgentState("questions", parse, []);
|
|
804
|
+
return { questions };
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
// src/lib/constants.ts
|
|
808
|
+
var SIDEBAR_WIDTH = 480;
|
|
809
|
+
|
|
630
810
|
// src/components/ui/button.tsx
|
|
631
811
|
import { forwardRef as forwardRef3 } from "react";
|
|
632
|
-
import { jsx } from "react/jsx-runtime";
|
|
812
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
633
813
|
var variantClasses = {
|
|
634
814
|
default: "skippr:bg-primary skippr:text-primary-foreground skippr:hover:bg-primary/90",
|
|
635
815
|
destructive: "skippr:bg-destructive skippr:text-white skippr:hover:bg-destructive/90",
|
|
@@ -648,7 +828,7 @@ var sizeClasses = {
|
|
|
648
828
|
"icon-lg": "skippr:size-10"
|
|
649
829
|
};
|
|
650
830
|
var Button = forwardRef3(({ className, variant = "default", size = "default", ...props }, ref) => {
|
|
651
|
-
return /* @__PURE__ */
|
|
831
|
+
return /* @__PURE__ */ jsx2("button", {
|
|
652
832
|
className: cn("skippr:inline-flex skippr:items-center skippr:justify-center skippr:gap-2 skippr:whitespace-nowrap skippr:rounded-md skippr:text-sm skippr:font-medium skippr:ring-offset-background skippr:transition-all skippr:focus-visible:outline-none skippr:focus-visible:ring-2 skippr:focus-visible:ring-ring skippr:focus-visible:ring-offset-2 skippr:disabled:pointer-events-none skippr:disabled:opacity-50 skippr:shrink-0 skippr:[&_svg]:pointer-events-none skippr:[&_svg:not([class*='size-'])]:size-4 skippr:[&_svg]:shrink-0", variantClasses[variant], sizeClasses[size], className),
|
|
653
833
|
ref,
|
|
654
834
|
...props
|
|
@@ -657,61 +837,88 @@ var Button = forwardRef3(({ className, variant = "default", size = "default", ..
|
|
|
657
837
|
Button.displayName = "Button";
|
|
658
838
|
|
|
659
839
|
// src/components/ChatHeader.tsx
|
|
660
|
-
import { jsx as
|
|
661
|
-
function ChatHeader({
|
|
662
|
-
|
|
840
|
+
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
841
|
+
function ChatHeader({ onOpenSettings }) {
|
|
842
|
+
const { closePanel, minimizePanel, minimizable, isConnected } = useLiveAgent();
|
|
843
|
+
return /* @__PURE__ */ jsxs2("div", {
|
|
663
844
|
className: "skippr:flex skippr:items-center skippr:gap-3 skippr:bg-primary skippr:px-4 skippr:py-3 skippr:text-primary-foreground",
|
|
664
845
|
children: [
|
|
665
|
-
/* @__PURE__ */
|
|
846
|
+
/* @__PURE__ */ jsx3("div", {
|
|
666
847
|
className: "skippr:flex skippr:size-6 skippr:items-center skippr:justify-center skippr:rounded-full skippr:bg-primary-foreground/20",
|
|
667
|
-
children: /* @__PURE__ */
|
|
848
|
+
children: /* @__PURE__ */ jsx3(Bot, {
|
|
668
849
|
className: "skippr:size-3.5 skippr:text-primary-foreground"
|
|
669
850
|
})
|
|
670
851
|
}),
|
|
671
|
-
/* @__PURE__ */
|
|
852
|
+
/* @__PURE__ */ jsx3("div", {
|
|
672
853
|
className: "skippr:flex-1",
|
|
673
|
-
children: /* @__PURE__ */
|
|
854
|
+
children: /* @__PURE__ */ jsx3("p", {
|
|
674
855
|
className: "skippr:text-sm skippr:font-semibold skippr:leading-none",
|
|
675
856
|
children: "AI Agent"
|
|
676
857
|
})
|
|
677
858
|
}),
|
|
678
|
-
/* @__PURE__ */
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
859
|
+
/* @__PURE__ */ jsxs2("div", {
|
|
860
|
+
className: "skippr:flex skippr:items-center skippr:gap-1",
|
|
861
|
+
children: [
|
|
862
|
+
/* @__PURE__ */ jsx3(Button, {
|
|
863
|
+
variant: "ghost",
|
|
864
|
+
size: "icon-xs",
|
|
865
|
+
onClick: onOpenSettings,
|
|
866
|
+
className: "skippr:text-primary-foreground skippr:hover:bg-primary-foreground/20 skippr:hover:text-primary-foreground",
|
|
867
|
+
"aria-label": "Settings",
|
|
868
|
+
children: /* @__PURE__ */ jsx3(Settings, {
|
|
869
|
+
className: "skippr:size-4"
|
|
870
|
+
})
|
|
871
|
+
}),
|
|
872
|
+
minimizable && isConnected && /* @__PURE__ */ jsx3(Button, {
|
|
873
|
+
variant: "ghost",
|
|
874
|
+
size: "icon-xs",
|
|
875
|
+
onClick: minimizePanel,
|
|
876
|
+
className: "skippr:text-primary-foreground skippr:hover:bg-primary-foreground/20 skippr:hover:text-primary-foreground",
|
|
877
|
+
"aria-label": "Minimize",
|
|
878
|
+
children: /* @__PURE__ */ jsx3(Minimize2, {
|
|
879
|
+
className: "skippr:size-4"
|
|
880
|
+
})
|
|
881
|
+
}),
|
|
882
|
+
/* @__PURE__ */ jsx3(Button, {
|
|
883
|
+
variant: "ghost",
|
|
884
|
+
size: "icon-xs",
|
|
885
|
+
onClick: closePanel,
|
|
886
|
+
className: "skippr:text-primary-foreground skippr:hover:bg-primary-foreground/20 skippr:hover:text-primary-foreground",
|
|
887
|
+
"aria-label": "Close",
|
|
888
|
+
children: /* @__PURE__ */ jsx3(X, {
|
|
889
|
+
className: "skippr:size-4"
|
|
890
|
+
})
|
|
891
|
+
})
|
|
892
|
+
]
|
|
686
893
|
})
|
|
687
894
|
]
|
|
688
895
|
});
|
|
689
896
|
}
|
|
690
897
|
|
|
691
898
|
// src/components/LoginFlow.tsx
|
|
692
|
-
import { useCallback as
|
|
693
|
-
import { jsx as
|
|
899
|
+
import { useCallback as useCallback6, useEffect as useEffect4, useRef, useState as useState4 } from "react";
|
|
900
|
+
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
694
901
|
var OTP_LENGTH = 6;
|
|
695
902
|
var DIGIT_KEYS = ["d0", "d1", "d2", "d3", "d4", "d5"];
|
|
696
903
|
function LoginFlow({ requestOtp, verifyOtp, error, isSubmitting }) {
|
|
697
904
|
const [step, setStep] = useState4("email");
|
|
698
905
|
const [email, setEmail] = useState4("");
|
|
699
|
-
const handleRequestOtp =
|
|
906
|
+
const handleRequestOtp = useCallback6(async (emailValue) => {
|
|
700
907
|
const success = await requestOtp(emailValue);
|
|
701
908
|
if (success)
|
|
702
909
|
setStep("otp");
|
|
703
910
|
}, [requestOtp]);
|
|
704
|
-
const handleVerifyOtp =
|
|
911
|
+
const handleVerifyOtp = useCallback6(async (code) => {
|
|
705
912
|
await verifyOtp(email, code);
|
|
706
913
|
}, [verifyOtp, email]);
|
|
707
|
-
const handleBack =
|
|
914
|
+
const handleBack = useCallback6(() => {
|
|
708
915
|
setStep("email");
|
|
709
916
|
}, []);
|
|
710
|
-
const handleResend =
|
|
917
|
+
const handleResend = useCallback6(async () => {
|
|
711
918
|
await requestOtp(email);
|
|
712
919
|
}, [requestOtp, email]);
|
|
713
920
|
if (step === "otp") {
|
|
714
|
-
return /* @__PURE__ */
|
|
921
|
+
return /* @__PURE__ */ jsx4(OtpStep, {
|
|
715
922
|
email,
|
|
716
923
|
onSubmit: handleVerifyOtp,
|
|
717
924
|
onResend: handleResend,
|
|
@@ -720,7 +927,7 @@ function LoginFlow({ requestOtp, verifyOtp, error, isSubmitting }) {
|
|
|
720
927
|
isSubmitting
|
|
721
928
|
});
|
|
722
929
|
}
|
|
723
|
-
return /* @__PURE__ */
|
|
930
|
+
return /* @__PURE__ */ jsx4(EmailStep, {
|
|
724
931
|
email,
|
|
725
932
|
onEmailChange: setEmail,
|
|
726
933
|
onSubmit: handleRequestOtp,
|
|
@@ -734,30 +941,30 @@ function EmailStep({ email, onEmailChange, onSubmit, error, isSubmitting }) {
|
|
|
734
941
|
if (email.trim())
|
|
735
942
|
onSubmit(email.trim());
|
|
736
943
|
}
|
|
737
|
-
return /* @__PURE__ */
|
|
944
|
+
return /* @__PURE__ */ jsxs3("div", {
|
|
738
945
|
className: "skippr:flex skippr:flex-1 skippr:flex-col skippr:px-4 skippr:py-4",
|
|
739
946
|
children: [
|
|
740
|
-
/* @__PURE__ */
|
|
947
|
+
/* @__PURE__ */ jsxs3("div", {
|
|
741
948
|
className: "skippr:mb-4 skippr:text-center",
|
|
742
949
|
children: [
|
|
743
|
-
/* @__PURE__ */
|
|
950
|
+
/* @__PURE__ */ jsx4(Mail, {
|
|
744
951
|
className: "skippr:mx-auto skippr:mb-2 skippr:size-6 skippr:text-primary"
|
|
745
952
|
}),
|
|
746
|
-
/* @__PURE__ */
|
|
953
|
+
/* @__PURE__ */ jsx4("p", {
|
|
747
954
|
className: "skippr:text-sm skippr:font-medium skippr:text-foreground",
|
|
748
955
|
children: "Sign in to continue"
|
|
749
956
|
}),
|
|
750
|
-
/* @__PURE__ */
|
|
957
|
+
/* @__PURE__ */ jsx4("p", {
|
|
751
958
|
className: "skippr:mt-1 skippr:text-xs skippr:text-muted-foreground",
|
|
752
959
|
children: "Your email will be used to identify you across sessions"
|
|
753
960
|
})
|
|
754
961
|
]
|
|
755
962
|
}),
|
|
756
|
-
/* @__PURE__ */
|
|
963
|
+
/* @__PURE__ */ jsxs3("form", {
|
|
757
964
|
onSubmit: handleSubmit,
|
|
758
965
|
className: "skippr:flex skippr:flex-col skippr:gap-3",
|
|
759
966
|
children: [
|
|
760
|
-
/* @__PURE__ */
|
|
967
|
+
/* @__PURE__ */ jsx4("input", {
|
|
761
968
|
type: "email",
|
|
762
969
|
placeholder: "you@example.com",
|
|
763
970
|
value: email,
|
|
@@ -766,15 +973,15 @@ function EmailStep({ email, onEmailChange, onSubmit, error, isSubmitting }) {
|
|
|
766
973
|
required: true,
|
|
767
974
|
className: "skippr:w-full skippr:rounded-md skippr:border skippr:border-border skippr:bg-background skippr:px-3 skippr:py-2 skippr:text-sm skippr:text-foreground skippr:placeholder-muted-foreground skippr:outline-none focus:skippr:ring-2 focus:skippr:ring-primary/30 focus:skippr:border-primary disabled:skippr:opacity-50"
|
|
768
975
|
}),
|
|
769
|
-
/* @__PURE__ */
|
|
976
|
+
/* @__PURE__ */ jsx4(Button, {
|
|
770
977
|
type: "submit",
|
|
771
978
|
disabled: isSubmitting || !email.trim(),
|
|
772
979
|
className: "skippr:w-full",
|
|
773
|
-
children: isSubmitting ? /* @__PURE__ */
|
|
980
|
+
children: isSubmitting ? /* @__PURE__ */ jsx4(LoaderCircle, {
|
|
774
981
|
className: "skippr:size-4 skippr:animate-spin"
|
|
775
982
|
}) : "Continue"
|
|
776
983
|
}),
|
|
777
|
-
error && /* @__PURE__ */
|
|
984
|
+
error && /* @__PURE__ */ jsx4("p", {
|
|
778
985
|
className: "skippr:text-xs skippr:text-center skippr:text-destructive",
|
|
779
986
|
children: error
|
|
780
987
|
})
|
|
@@ -801,13 +1008,13 @@ function OtpStep({ email, onSubmit, onResend, onBack, error, isSubmitting }) {
|
|
|
801
1008
|
const timer = setTimeout(() => setResendCooldown((c) => c - 1), 1000);
|
|
802
1009
|
return () => clearTimeout(timer);
|
|
803
1010
|
}, [resendCooldown]);
|
|
804
|
-
const submitCode =
|
|
1011
|
+
const submitCode = useCallback6((code) => {
|
|
805
1012
|
if (submittedRef.current || isSubmitting)
|
|
806
1013
|
return;
|
|
807
1014
|
submittedRef.current = true;
|
|
808
1015
|
onSubmit(code);
|
|
809
1016
|
}, [onSubmit, isSubmitting]);
|
|
810
|
-
const handleDigitChange =
|
|
1017
|
+
const handleDigitChange = useCallback6((index2, value) => {
|
|
811
1018
|
const digit = value.replace(/\D/g, "").slice(-1);
|
|
812
1019
|
const newDigits = [...digits];
|
|
813
1020
|
newDigits[index2] = digit;
|
|
@@ -821,12 +1028,12 @@ function OtpStep({ email, onSubmit, onResend, onBack, error, isSubmitting }) {
|
|
|
821
1028
|
submitCode(code);
|
|
822
1029
|
}
|
|
823
1030
|
}, [digits, submitCode]);
|
|
824
|
-
const handleKeyDown =
|
|
1031
|
+
const handleKeyDown = useCallback6((index2, e) => {
|
|
825
1032
|
if (e.key === "Backspace" && !digits[index2] && index2 > 0) {
|
|
826
1033
|
inputRefs.current[index2 - 1]?.focus();
|
|
827
1034
|
}
|
|
828
1035
|
}, [digits]);
|
|
829
|
-
const handlePaste =
|
|
1036
|
+
const handlePaste = useCallback6((e) => {
|
|
830
1037
|
e.preventDefault();
|
|
831
1038
|
const pasted = e.clipboardData.getData("text").replace(/\D/g, "").slice(0, OTP_LENGTH);
|
|
832
1039
|
if (pasted.length > 0) {
|
|
@@ -854,22 +1061,22 @@ function OtpStep({ email, onSubmit, onResend, onBack, error, isSubmitting }) {
|
|
|
854
1061
|
submittedRef.current = false;
|
|
855
1062
|
inputRefs.current[0]?.focus();
|
|
856
1063
|
}
|
|
857
|
-
return /* @__PURE__ */
|
|
1064
|
+
return /* @__PURE__ */ jsxs3("div", {
|
|
858
1065
|
className: "skippr:flex skippr:flex-1 skippr:flex-col skippr:px-4 skippr:py-4",
|
|
859
1066
|
children: [
|
|
860
|
-
/* @__PURE__ */
|
|
1067
|
+
/* @__PURE__ */ jsxs3("div", {
|
|
861
1068
|
className: "skippr:mb-4 skippr:text-center",
|
|
862
1069
|
children: [
|
|
863
|
-
/* @__PURE__ */
|
|
1070
|
+
/* @__PURE__ */ jsx4("p", {
|
|
864
1071
|
className: "skippr:text-sm skippr:font-medium skippr:text-foreground",
|
|
865
1072
|
children: "Enter verification code"
|
|
866
1073
|
}),
|
|
867
|
-
/* @__PURE__ */
|
|
1074
|
+
/* @__PURE__ */ jsxs3("p", {
|
|
868
1075
|
className: "skippr:mt-1 skippr:text-xs skippr:text-muted-foreground",
|
|
869
1076
|
children: [
|
|
870
1077
|
"We sent a 6-digit code to",
|
|
871
1078
|
" ",
|
|
872
|
-
/* @__PURE__ */
|
|
1079
|
+
/* @__PURE__ */ jsx4("span", {
|
|
873
1080
|
className: "skippr:font-medium skippr:text-foreground",
|
|
874
1081
|
children: email
|
|
875
1082
|
})
|
|
@@ -877,13 +1084,13 @@ function OtpStep({ email, onSubmit, onResend, onBack, error, isSubmitting }) {
|
|
|
877
1084
|
})
|
|
878
1085
|
]
|
|
879
1086
|
}),
|
|
880
|
-
/* @__PURE__ */
|
|
1087
|
+
/* @__PURE__ */ jsxs3("form", {
|
|
881
1088
|
onSubmit: handleSubmit,
|
|
882
1089
|
className: "skippr:flex skippr:flex-col skippr:gap-3",
|
|
883
1090
|
children: [
|
|
884
|
-
/* @__PURE__ */
|
|
1091
|
+
/* @__PURE__ */ jsx4("div", {
|
|
885
1092
|
className: "skippr:flex skippr:justify-center skippr:gap-1.5",
|
|
886
|
-
children: digits.map((digit, index2) => /* @__PURE__ */
|
|
1093
|
+
children: digits.map((digit, index2) => /* @__PURE__ */ jsx4("input", {
|
|
887
1094
|
ref: (el) => {
|
|
888
1095
|
inputRefs.current[index2] = el;
|
|
889
1096
|
},
|
|
@@ -898,29 +1105,29 @@ function OtpStep({ email, onSubmit, onResend, onBack, error, isSubmitting }) {
|
|
|
898
1105
|
className: "skippr:h-10 skippr:w-10 skippr:rounded-md skippr:border skippr:border-border skippr:bg-background skippr:text-center skippr:text-sm skippr:font-semibold skippr:text-foreground skippr:outline-none focus:skippr:ring-2 focus:skippr:ring-primary/30 focus:skippr:border-primary disabled:skippr:opacity-50"
|
|
899
1106
|
}, DIGIT_KEYS[index2]))
|
|
900
1107
|
}),
|
|
901
|
-
error && /* @__PURE__ */
|
|
1108
|
+
error && /* @__PURE__ */ jsx4("p", {
|
|
902
1109
|
className: "skippr:text-xs skippr:text-center skippr:text-destructive",
|
|
903
1110
|
children: error
|
|
904
1111
|
}),
|
|
905
|
-
/* @__PURE__ */
|
|
1112
|
+
/* @__PURE__ */ jsx4(Button, {
|
|
906
1113
|
type: "submit",
|
|
907
1114
|
disabled: isSubmitting || digits.join("").length !== OTP_LENGTH,
|
|
908
1115
|
className: "skippr:w-full",
|
|
909
|
-
children: isSubmitting ? /* @__PURE__ */
|
|
1116
|
+
children: isSubmitting ? /* @__PURE__ */ jsx4(LoaderCircle, {
|
|
910
1117
|
className: "skippr:size-4 skippr:animate-spin"
|
|
911
1118
|
}) : "Verify"
|
|
912
1119
|
}),
|
|
913
|
-
/* @__PURE__ */
|
|
1120
|
+
/* @__PURE__ */ jsxs3("div", {
|
|
914
1121
|
className: "skippr:flex skippr:items-center skippr:justify-between skippr:text-xs",
|
|
915
1122
|
children: [
|
|
916
|
-
/* @__PURE__ */
|
|
1123
|
+
/* @__PURE__ */ jsx4("button", {
|
|
917
1124
|
type: "button",
|
|
918
1125
|
onClick: onBack,
|
|
919
1126
|
disabled: isSubmitting,
|
|
920
1127
|
className: "skippr:text-muted-foreground hover:skippr:text-foreground skippr:transition-colors disabled:skippr:opacity-50",
|
|
921
1128
|
children: "Change email"
|
|
922
1129
|
}),
|
|
923
|
-
/* @__PURE__ */
|
|
1130
|
+
/* @__PURE__ */ jsx4("button", {
|
|
924
1131
|
type: "button",
|
|
925
1132
|
onClick: handleResend,
|
|
926
1133
|
disabled: isSubmitting || resendCooldown > 0,
|
|
@@ -936,9 +1143,9 @@ function OtpStep({ email, onSubmit, onResend, onBack, error, isSubmitting }) {
|
|
|
936
1143
|
}
|
|
937
1144
|
|
|
938
1145
|
// src/components/MeetingControls.tsx
|
|
939
|
-
import { useLocalParticipant as
|
|
940
|
-
import { ScreenSharePresets } from "livekit-client";
|
|
941
|
-
import { useCallback as
|
|
1146
|
+
import { useLocalParticipant as useLocalParticipant4 } from "@livekit/components-react";
|
|
1147
|
+
import { ScreenSharePresets as ScreenSharePresets2 } from "livekit-client";
|
|
1148
|
+
import { useCallback as useCallback7, useEffect as useEffect5, useRef as useRef2, useState as useState5 } from "react";
|
|
942
1149
|
|
|
943
1150
|
// src/lib/format.ts
|
|
944
1151
|
function formatTime(seconds) {
|
|
@@ -952,12 +1159,12 @@ function parseNumber(s) {
|
|
|
952
1159
|
}
|
|
953
1160
|
|
|
954
1161
|
// src/components/SessionWarningBanner.tsx
|
|
955
|
-
import { jsx as
|
|
1162
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
956
1163
|
var SESSION_WARNING_THRESHOLD_SECS = 60;
|
|
957
1164
|
function SessionWarningBanner({ remaining }) {
|
|
958
1165
|
if (remaining === null || remaining <= 0 || remaining > SESSION_WARNING_THRESHOLD_SECS)
|
|
959
1166
|
return null;
|
|
960
|
-
return /* @__PURE__ */
|
|
1167
|
+
return /* @__PURE__ */ jsx5("div", {
|
|
961
1168
|
"data-testid": "session-warning-banner",
|
|
962
1169
|
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",
|
|
963
1170
|
children: "Session ending soon"
|
|
@@ -965,10 +1172,10 @@ function SessionWarningBanner({ remaining }) {
|
|
|
965
1172
|
}
|
|
966
1173
|
|
|
967
1174
|
// src/components/MeetingControls.tsx
|
|
968
|
-
import { jsx as
|
|
1175
|
+
import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
969
1176
|
function MeetingControls({ onHangUp }) {
|
|
970
1177
|
const maxCallDuration = useAgentState("maxCallDuration", parseNumber, null);
|
|
971
|
-
const { localParticipant } =
|
|
1178
|
+
const { localParticipant } = useLocalParticipant4();
|
|
972
1179
|
const isMuted = !localParticipant.isMicrophoneEnabled;
|
|
973
1180
|
const isScreenSharing = localParticipant.isScreenShareEnabled;
|
|
974
1181
|
const endTimeRef = useRef2(null);
|
|
@@ -985,18 +1192,18 @@ function MeetingControls({ onHangUp }) {
|
|
|
985
1192
|
const id = setInterval(tick, 1000);
|
|
986
1193
|
return () => clearInterval(id);
|
|
987
1194
|
}, [maxCallDuration]);
|
|
988
|
-
const toggleMute =
|
|
1195
|
+
const toggleMute = useCallback7(async () => {
|
|
989
1196
|
try {
|
|
990
1197
|
await localParticipant.setMicrophoneEnabled(isMuted);
|
|
991
1198
|
} catch (e) {
|
|
992
1199
|
console.error("Failed to toggle microphone:", e);
|
|
993
1200
|
}
|
|
994
1201
|
}, [localParticipant, isMuted]);
|
|
995
|
-
const toggleScreenShare =
|
|
1202
|
+
const toggleScreenShare = useCallback7(async () => {
|
|
996
1203
|
try {
|
|
997
1204
|
await localParticipant.setScreenShareEnabled(!isScreenSharing, {
|
|
998
1205
|
video: { displaySurface: "browser" },
|
|
999
|
-
resolution:
|
|
1206
|
+
resolution: ScreenSharePresets2.h720fps30.resolution,
|
|
1000
1207
|
contentHint: "detail"
|
|
1001
1208
|
});
|
|
1002
1209
|
} catch (e) {
|
|
@@ -1006,51 +1213,51 @@ function MeetingControls({ onHangUp }) {
|
|
|
1006
1213
|
useEffect5(() => {
|
|
1007
1214
|
toggleMute().then(() => toggleScreenShare());
|
|
1008
1215
|
}, []);
|
|
1009
|
-
return /* @__PURE__ */
|
|
1216
|
+
return /* @__PURE__ */ jsxs4("div", {
|
|
1010
1217
|
children: [
|
|
1011
|
-
/* @__PURE__ */
|
|
1218
|
+
/* @__PURE__ */ jsx6(SessionWarningBanner, {
|
|
1012
1219
|
remaining
|
|
1013
1220
|
}),
|
|
1014
|
-
/* @__PURE__ */
|
|
1221
|
+
/* @__PURE__ */ jsxs4("div", {
|
|
1015
1222
|
className: "skippr:flex skippr:items-center skippr:justify-between skippr:border-b skippr:px-4 skippr:py-3",
|
|
1016
1223
|
children: [
|
|
1017
|
-
/* @__PURE__ */
|
|
1224
|
+
/* @__PURE__ */ jsxs4("div", {
|
|
1018
1225
|
className: "skippr:flex skippr:items-center skippr:gap-2",
|
|
1019
1226
|
children: [
|
|
1020
|
-
/* @__PURE__ */
|
|
1227
|
+
/* @__PURE__ */ jsx6(Button, {
|
|
1021
1228
|
size: "icon-sm",
|
|
1022
1229
|
variant: isMuted ? "destructive" : "outline",
|
|
1023
1230
|
onClick: toggleMute,
|
|
1024
1231
|
"aria-label": isMuted ? "Unmute" : "Mute",
|
|
1025
|
-
children: isMuted ? /* @__PURE__ */
|
|
1232
|
+
children: isMuted ? /* @__PURE__ */ jsx6(MicOff, {
|
|
1026
1233
|
className: "skippr:size-4"
|
|
1027
|
-
}) : /* @__PURE__ */
|
|
1234
|
+
}) : /* @__PURE__ */ jsx6(Mic, {
|
|
1028
1235
|
className: "skippr:size-4"
|
|
1029
1236
|
})
|
|
1030
1237
|
}),
|
|
1031
|
-
/* @__PURE__ */
|
|
1238
|
+
/* @__PURE__ */ jsx6(Button, {
|
|
1032
1239
|
size: "icon-sm",
|
|
1033
|
-
variant: isScreenSharing ? "
|
|
1240
|
+
variant: isScreenSharing ? "outline" : "destructive",
|
|
1034
1241
|
onClick: toggleScreenShare,
|
|
1035
1242
|
"aria-label": isScreenSharing ? "Stop sharing" : "Share screen",
|
|
1036
|
-
children: isScreenSharing ? /* @__PURE__ */
|
|
1243
|
+
children: isScreenSharing ? /* @__PURE__ */ jsx6(MonitorOff, {
|
|
1037
1244
|
className: "skippr:size-4"
|
|
1038
|
-
}) : /* @__PURE__ */
|
|
1245
|
+
}) : /* @__PURE__ */ jsx6(Monitor, {
|
|
1039
1246
|
className: "skippr:size-4"
|
|
1040
1247
|
})
|
|
1041
1248
|
})
|
|
1042
1249
|
]
|
|
1043
1250
|
}),
|
|
1044
|
-
remaining !== null && /* @__PURE__ */
|
|
1251
|
+
remaining !== null && /* @__PURE__ */ jsx6("span", {
|
|
1045
1252
|
className: cn("skippr:text-sm skippr:font-medium skippr:tabular-nums", remaining <= SESSION_WARNING_THRESHOLD_SECS ? "skippr:text-red-600 skippr:animate-pulse" : "skippr:text-muted-foreground"),
|
|
1046
1253
|
children: formatTime(remaining)
|
|
1047
1254
|
}),
|
|
1048
|
-
/* @__PURE__ */
|
|
1255
|
+
/* @__PURE__ */ jsx6(Button, {
|
|
1049
1256
|
size: "icon-sm",
|
|
1050
1257
|
variant: "destructive",
|
|
1051
1258
|
onClick: onHangUp,
|
|
1052
1259
|
"aria-label": "Hang up",
|
|
1053
|
-
children: /* @__PURE__ */
|
|
1260
|
+
children: /* @__PURE__ */ jsx6(PhoneOff, {
|
|
1054
1261
|
className: "skippr:size-4"
|
|
1055
1262
|
})
|
|
1056
1263
|
})
|
|
@@ -1065,7 +1272,7 @@ import { useEffect as useEffect6, useRef as useRef3 } from "react";
|
|
|
1065
1272
|
|
|
1066
1273
|
// src/components/ChatInput.tsx
|
|
1067
1274
|
import { useState as useState6 } from "react";
|
|
1068
|
-
import { jsx as
|
|
1275
|
+
import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1069
1276
|
function ChatInput({ sendChatMessage, isSendingChat }) {
|
|
1070
1277
|
const [inputText, setInputText] = useState6("");
|
|
1071
1278
|
const canSend = inputText.trim().length > 0 && !isSendingChat;
|
|
@@ -1077,11 +1284,11 @@ function ChatInput({ sendChatMessage, isSendingChat }) {
|
|
|
1077
1284
|
setInputText("");
|
|
1078
1285
|
sendChatMessage(text).catch(() => setInputText(text));
|
|
1079
1286
|
}
|
|
1080
|
-
return /* @__PURE__ */
|
|
1287
|
+
return /* @__PURE__ */ jsxs5("form", {
|
|
1081
1288
|
onSubmit: handleSubmit,
|
|
1082
1289
|
className: "skippr:flex skippr:items-center skippr:gap-2 skippr:border-t skippr:border-border skippr:px-3 skippr:py-2",
|
|
1083
1290
|
children: [
|
|
1084
|
-
/* @__PURE__ */
|
|
1291
|
+
/* @__PURE__ */ jsx7("input", {
|
|
1085
1292
|
type: "text",
|
|
1086
1293
|
value: inputText,
|
|
1087
1294
|
onChange: (e) => setInputText(e.target.value),
|
|
@@ -1089,12 +1296,12 @@ function ChatInput({ sendChatMessage, isSendingChat }) {
|
|
|
1089
1296
|
className: cn("skippr:flex-1 skippr:rounded-lg skippr:border skippr:border-border skippr:bg-background", "skippr:px-3 skippr:py-2 skippr:text-sm skippr:text-foreground", "skippr:placeholder:text-muted-foreground skippr:outline-none", "skippr:focus:ring-1 skippr:focus:ring-ring"),
|
|
1090
1297
|
disabled: isSendingChat
|
|
1091
1298
|
}),
|
|
1092
|
-
/* @__PURE__ */
|
|
1299
|
+
/* @__PURE__ */ jsx7("button", {
|
|
1093
1300
|
type: "submit",
|
|
1094
1301
|
disabled: !canSend,
|
|
1095
1302
|
"aria-label": "Send message",
|
|
1096
1303
|
className: cn("skippr:flex skippr:size-9 skippr:shrink-0 skippr:items-center skippr:justify-center", "skippr:rounded-lg skippr:bg-primary skippr:text-primary-foreground", "skippr:transition-opacity", !canSend && "skippr:opacity-50 skippr:cursor-not-allowed"),
|
|
1097
|
-
children: /* @__PURE__ */
|
|
1304
|
+
children: /* @__PURE__ */ jsx7(SendHorizontal, {
|
|
1098
1305
|
className: "skippr:size-4"
|
|
1099
1306
|
})
|
|
1100
1307
|
})
|
|
@@ -1103,12 +1310,12 @@ function ChatInput({ sendChatMessage, isSendingChat }) {
|
|
|
1103
1310
|
}
|
|
1104
1311
|
|
|
1105
1312
|
// src/components/ChatMessage.tsx
|
|
1106
|
-
import { jsx as
|
|
1313
|
+
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
1107
1314
|
function ChatMessage({ message }) {
|
|
1108
1315
|
const isUser = message.role === "user";
|
|
1109
|
-
return /* @__PURE__ */
|
|
1316
|
+
return /* @__PURE__ */ jsx8("div", {
|
|
1110
1317
|
className: cn("skippr:flex skippr:w-full skippr:px-4 skippr:py-1", isUser ? "skippr:justify-end" : "skippr:justify-start"),
|
|
1111
|
-
children: /* @__PURE__ */
|
|
1318
|
+
children: /* @__PURE__ */ jsx8("div", {
|
|
1112
1319
|
className: cn("skippr:max-w-[85%] skippr:whitespace-pre-wrap skippr:rounded-2xl skippr:px-4 skippr:py-2.5 skippr:text-sm skippr:leading-relaxed", isUser ? "skippr:rounded-br-sm skippr:bg-primary skippr:text-primary-foreground" : "skippr:rounded-bl-sm skippr:bg-muted skippr:text-foreground"),
|
|
1113
1320
|
children: message.content
|
|
1114
1321
|
})
|
|
@@ -1116,20 +1323,20 @@ function ChatMessage({ message }) {
|
|
|
1116
1323
|
}
|
|
1117
1324
|
|
|
1118
1325
|
// src/components/TypingIndicator.tsx
|
|
1119
|
-
import { jsx as
|
|
1326
|
+
import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1120
1327
|
function TypingIndicator() {
|
|
1121
|
-
return /* @__PURE__ */
|
|
1328
|
+
return /* @__PURE__ */ jsx9("div", {
|
|
1122
1329
|
className: "skippr:flex skippr:items-center skippr:gap-1 skippr:px-4 skippr:py-3",
|
|
1123
|
-
children: /* @__PURE__ */
|
|
1330
|
+
children: /* @__PURE__ */ jsxs6("div", {
|
|
1124
1331
|
className: "skippr:flex skippr:items-center skippr:gap-1 skippr:rounded-2xl skippr:rounded-bl-sm skippr:bg-muted skippr:px-4 skippr:py-2.5",
|
|
1125
1332
|
children: [
|
|
1126
|
-
/* @__PURE__ */
|
|
1333
|
+
/* @__PURE__ */ jsx9("span", {
|
|
1127
1334
|
className: "skippr:size-1.5 skippr:animate-bounce skippr:rounded-full skippr:bg-muted-foreground/60 skippr:[animation-delay:0ms]"
|
|
1128
1335
|
}),
|
|
1129
|
-
/* @__PURE__ */
|
|
1336
|
+
/* @__PURE__ */ jsx9("span", {
|
|
1130
1337
|
className: "skippr:size-1.5 skippr:animate-bounce skippr:rounded-full skippr:bg-muted-foreground/60 skippr:[animation-delay:150ms]"
|
|
1131
1338
|
}),
|
|
1132
|
-
/* @__PURE__ */
|
|
1339
|
+
/* @__PURE__ */ jsx9("span", {
|
|
1133
1340
|
className: "skippr:size-1.5 skippr:animate-bounce skippr:rounded-full skippr:bg-muted-foreground/60 skippr:[animation-delay:300ms]"
|
|
1134
1341
|
})
|
|
1135
1342
|
]
|
|
@@ -1138,7 +1345,7 @@ function TypingIndicator() {
|
|
|
1138
1345
|
}
|
|
1139
1346
|
|
|
1140
1347
|
// src/components/MessageList.tsx
|
|
1141
|
-
import { jsx as
|
|
1348
|
+
import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1142
1349
|
function MessageList({
|
|
1143
1350
|
messages,
|
|
1144
1351
|
isStreaming,
|
|
@@ -1151,25 +1358,25 @@ function MessageList({
|
|
|
1151
1358
|
scrollRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
1152
1359
|
}, [messages.length, lastMessage?.content]);
|
|
1153
1360
|
const showTyping = isStreaming && lastMessage?.role === "assistant" && lastMessage.content === "";
|
|
1154
|
-
return /* @__PURE__ */
|
|
1361
|
+
return /* @__PURE__ */ jsxs7("div", {
|
|
1155
1362
|
className: "skippr:flex skippr:min-h-0 skippr:flex-1 skippr:flex-col",
|
|
1156
1363
|
children: [
|
|
1157
|
-
/* @__PURE__ */
|
|
1364
|
+
/* @__PURE__ */ jsx10("div", {
|
|
1158
1365
|
className: "skippr:min-h-0 skippr:flex-1 skippr:overflow-y-auto",
|
|
1159
|
-
children: /* @__PURE__ */
|
|
1366
|
+
children: /* @__PURE__ */ jsxs7("div", {
|
|
1160
1367
|
className: "skippr:flex skippr:flex-col skippr:gap-1 skippr:py-3",
|
|
1161
1368
|
children: [
|
|
1162
|
-
messages.map((message) => /* @__PURE__ */
|
|
1369
|
+
messages.map((message) => /* @__PURE__ */ jsx10(ChatMessage, {
|
|
1163
1370
|
message
|
|
1164
1371
|
}, message.id)),
|
|
1165
|
-
showTyping && /* @__PURE__ */
|
|
1166
|
-
/* @__PURE__ */
|
|
1372
|
+
showTyping && /* @__PURE__ */ jsx10(TypingIndicator, {}),
|
|
1373
|
+
/* @__PURE__ */ jsx10("div", {
|
|
1167
1374
|
ref: scrollRef
|
|
1168
1375
|
})
|
|
1169
1376
|
]
|
|
1170
1377
|
})
|
|
1171
1378
|
}),
|
|
1172
|
-
/* @__PURE__ */
|
|
1379
|
+
/* @__PURE__ */ jsx10(ChatInput, {
|
|
1173
1380
|
sendChatMessage,
|
|
1174
1381
|
isSendingChat
|
|
1175
1382
|
})
|
|
@@ -1178,30 +1385,30 @@ function MessageList({
|
|
|
1178
1385
|
}
|
|
1179
1386
|
|
|
1180
1387
|
// src/components/QuickActions.tsx
|
|
1181
|
-
import { jsx as
|
|
1388
|
+
import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1182
1389
|
function QuickActions({ onStartSession, isStarting, error }) {
|
|
1183
|
-
return /* @__PURE__ */
|
|
1390
|
+
return /* @__PURE__ */ jsxs8("div", {
|
|
1184
1391
|
className: "skippr:flex skippr:flex-1 skippr:flex-col skippr:items-center skippr:gap-6 skippr:overflow-y-auto skippr:px-4 skippr:py-4",
|
|
1185
1392
|
children: [
|
|
1186
|
-
/* @__PURE__ */
|
|
1393
|
+
/* @__PURE__ */ jsx11("p", {
|
|
1187
1394
|
className: "skippr:mb-1 skippr:text-sm skippr:text-muted-foreground",
|
|
1188
1395
|
children: "How can I help you today?"
|
|
1189
1396
|
}),
|
|
1190
|
-
/* @__PURE__ */
|
|
1397
|
+
/* @__PURE__ */ jsxs8(Button, {
|
|
1191
1398
|
variant: "outline",
|
|
1192
1399
|
className: "skippr:h-auto skippr:flex-col skippr:gap-1.5 skippr:whitespace-normal skippr:py-3 skippr:text-xs",
|
|
1193
1400
|
onClick: onStartSession,
|
|
1194
1401
|
disabled: isStarting,
|
|
1195
1402
|
children: [
|
|
1196
|
-
isStarting ? /* @__PURE__ */
|
|
1403
|
+
isStarting ? /* @__PURE__ */ jsx11(LoaderCircle, {
|
|
1197
1404
|
className: "skippr:size-4 skippr:animate-spin skippr:text-primary"
|
|
1198
|
-
}) : /* @__PURE__ */
|
|
1405
|
+
}) : /* @__PURE__ */ jsx11(MessageCircleQuestionMark, {
|
|
1199
1406
|
className: "skippr:size-4 skippr:text-primary"
|
|
1200
1407
|
}),
|
|
1201
1408
|
isStarting ? "Starting..." : "Start Session"
|
|
1202
1409
|
]
|
|
1203
1410
|
}),
|
|
1204
|
-
error && /* @__PURE__ */
|
|
1411
|
+
error && /* @__PURE__ */ jsx11("p", {
|
|
1205
1412
|
className: "skippr:text-xs skippr:text-destructive",
|
|
1206
1413
|
children: error
|
|
1207
1414
|
})
|
|
@@ -1210,52 +1417,52 @@ function QuickActions({ onStartSession, isStarting, error }) {
|
|
|
1210
1417
|
}
|
|
1211
1418
|
|
|
1212
1419
|
// src/components/SessionAgenda.tsx
|
|
1213
|
-
import { jsx as
|
|
1420
|
+
import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1214
1421
|
function SessionAgenda({ phases, questions = [] }) {
|
|
1215
1422
|
if (phases.length === 0) {
|
|
1216
|
-
return /* @__PURE__ */
|
|
1423
|
+
return /* @__PURE__ */ jsxs9("div", {
|
|
1217
1424
|
className: "skippr:flex skippr:flex-col skippr:gap-3 skippr:p-4",
|
|
1218
1425
|
children: [
|
|
1219
|
-
/* @__PURE__ */
|
|
1426
|
+
/* @__PURE__ */ jsx12("h3", {
|
|
1220
1427
|
className: "skippr:text-sm skippr:font-semibold",
|
|
1221
1428
|
children: "Agenda"
|
|
1222
1429
|
}),
|
|
1223
|
-
/* @__PURE__ */
|
|
1430
|
+
/* @__PURE__ */ jsx12("p", {
|
|
1224
1431
|
className: "skippr:text-xs skippr:text-muted-foreground",
|
|
1225
1432
|
children: "Waiting for session..."
|
|
1226
1433
|
})
|
|
1227
1434
|
]
|
|
1228
1435
|
});
|
|
1229
1436
|
}
|
|
1230
|
-
return /* @__PURE__ */
|
|
1437
|
+
return /* @__PURE__ */ jsxs9("div", {
|
|
1231
1438
|
className: "skippr:flex skippr:flex-col skippr:gap-3 skippr:p-4",
|
|
1232
1439
|
children: [
|
|
1233
|
-
/* @__PURE__ */
|
|
1440
|
+
/* @__PURE__ */ jsx12("h3", {
|
|
1234
1441
|
className: "skippr:text-sm skippr:font-semibold",
|
|
1235
1442
|
children: "Agenda"
|
|
1236
1443
|
}),
|
|
1237
|
-
/* @__PURE__ */
|
|
1444
|
+
/* @__PURE__ */ jsx12("ul", {
|
|
1238
1445
|
className: "skippr:flex skippr:flex-col skippr:gap-2",
|
|
1239
1446
|
children: phases.map((phase) => {
|
|
1240
1447
|
const phaseQuestions = questions.filter((q) => q.phaseName === phase.name);
|
|
1241
1448
|
const answeredCount = phaseQuestions.filter((q) => q.status === "answered").length;
|
|
1242
1449
|
const totalCount = phaseQuestions.length;
|
|
1243
|
-
return /* @__PURE__ */
|
|
1450
|
+
return /* @__PURE__ */ jsxs9("li", {
|
|
1244
1451
|
className: "skippr:flex skippr:flex-col skippr:gap-0.5",
|
|
1245
1452
|
children: [
|
|
1246
|
-
/* @__PURE__ */
|
|
1453
|
+
/* @__PURE__ */ jsxs9("div", {
|
|
1247
1454
|
className: "skippr:flex skippr:items-center skippr:gap-2 skippr:text-sm",
|
|
1248
1455
|
children: [
|
|
1249
|
-
/* @__PURE__ */
|
|
1456
|
+
/* @__PURE__ */ jsx12(PhaseIcon, {
|
|
1250
1457
|
status: phase.status
|
|
1251
1458
|
}),
|
|
1252
|
-
/* @__PURE__ */
|
|
1459
|
+
/* @__PURE__ */ jsx12("span", {
|
|
1253
1460
|
className: cn(phase.status === "completed" && "skippr:text-muted-foreground skippr:line-through", phase.status === "active" && "skippr:font-medium skippr:text-primary"),
|
|
1254
1461
|
children: phase.name
|
|
1255
1462
|
})
|
|
1256
1463
|
]
|
|
1257
1464
|
}),
|
|
1258
|
-
totalCount > 0 && /* @__PURE__ */
|
|
1465
|
+
totalCount > 0 && /* @__PURE__ */ jsxs9("span", {
|
|
1259
1466
|
className: "skippr:ml-6 skippr:text-xs skippr:text-muted-foreground",
|
|
1260
1467
|
children: [
|
|
1261
1468
|
answeredCount,
|
|
@@ -1273,35 +1480,110 @@ function SessionAgenda({ phases, questions = [] }) {
|
|
|
1273
1480
|
}
|
|
1274
1481
|
function PhaseIcon({ status }) {
|
|
1275
1482
|
if (status === "completed") {
|
|
1276
|
-
return /* @__PURE__ */
|
|
1483
|
+
return /* @__PURE__ */ jsx12("div", {
|
|
1277
1484
|
className: "skippr:flex skippr:size-4 skippr:shrink-0 skippr:items-center skippr:justify-center skippr:rounded-full skippr:bg-primary",
|
|
1278
|
-
children: /* @__PURE__ */
|
|
1485
|
+
children: /* @__PURE__ */ jsx12(Check, {
|
|
1279
1486
|
className: "skippr:size-2.5 skippr:text-primary-foreground",
|
|
1280
1487
|
strokeWidth: 3
|
|
1281
1488
|
})
|
|
1282
1489
|
});
|
|
1283
1490
|
}
|
|
1284
1491
|
if (status === "active") {
|
|
1285
|
-
return /* @__PURE__ */
|
|
1492
|
+
return /* @__PURE__ */ jsx12(LoaderCircle, {
|
|
1286
1493
|
className: "skippr:size-4 skippr:shrink-0 skippr:text-primary skippr:animate-spin"
|
|
1287
1494
|
});
|
|
1288
1495
|
}
|
|
1289
|
-
return /* @__PURE__ */
|
|
1496
|
+
return /* @__PURE__ */ jsx12(Circle, {
|
|
1290
1497
|
className: "skippr:size-4 skippr:shrink-0 skippr:text-muted-foreground"
|
|
1291
1498
|
});
|
|
1292
1499
|
}
|
|
1293
1500
|
|
|
1501
|
+
// src/components/SettingsView.tsx
|
|
1502
|
+
import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1503
|
+
function SettingsView({ onBack }) {
|
|
1504
|
+
const { position, setPosition } = useLiveAgent();
|
|
1505
|
+
return /* @__PURE__ */ jsxs10("div", {
|
|
1506
|
+
className: "skippr:flex skippr:flex-1 skippr:flex-col",
|
|
1507
|
+
children: [
|
|
1508
|
+
/* @__PURE__ */ jsxs10("div", {
|
|
1509
|
+
className: "skippr:flex skippr:items-center skippr:gap-2 skippr:border-b skippr:border-border skippr:px-4 skippr:py-3",
|
|
1510
|
+
children: [
|
|
1511
|
+
/* @__PURE__ */ jsx13(Button, {
|
|
1512
|
+
variant: "ghost",
|
|
1513
|
+
size: "icon-xs",
|
|
1514
|
+
onClick: onBack,
|
|
1515
|
+
"aria-label": "Back",
|
|
1516
|
+
children: /* @__PURE__ */ jsx13(ArrowLeft, {
|
|
1517
|
+
className: "skippr:size-4"
|
|
1518
|
+
})
|
|
1519
|
+
}),
|
|
1520
|
+
/* @__PURE__ */ jsx13("p", {
|
|
1521
|
+
className: "skippr:text-sm skippr:font-semibold",
|
|
1522
|
+
children: "Settings"
|
|
1523
|
+
})
|
|
1524
|
+
]
|
|
1525
|
+
}),
|
|
1526
|
+
/* @__PURE__ */ jsx13("div", {
|
|
1527
|
+
className: "skippr:flex-1 skippr:overflow-y-auto skippr:p-4",
|
|
1528
|
+
children: /* @__PURE__ */ jsxs10("div", {
|
|
1529
|
+
className: "skippr:mb-4",
|
|
1530
|
+
children: [
|
|
1531
|
+
/* @__PURE__ */ jsx13("p", {
|
|
1532
|
+
className: "skippr:mb-2 skippr:text-xs skippr:font-medium skippr:uppercase skippr:tracking-wide skippr:text-muted-foreground",
|
|
1533
|
+
children: "Widget Position"
|
|
1534
|
+
}),
|
|
1535
|
+
/* @__PURE__ */ jsxs10("div", {
|
|
1536
|
+
className: "skippr:flex skippr:gap-2",
|
|
1537
|
+
children: [
|
|
1538
|
+
/* @__PURE__ */ jsxs10("button", {
|
|
1539
|
+
type: "button",
|
|
1540
|
+
onClick: () => setPosition("left"),
|
|
1541
|
+
className: cn("skippr:flex skippr:flex-1 skippr:flex-col skippr:items-center skippr:gap-2 skippr:rounded-lg skippr:border skippr:p-3 skippr:cursor-pointer skippr:transition-colors", position === "left" ? "skippr:border-primary skippr:bg-primary/5 skippr:text-primary" : "skippr:border-border skippr:text-muted-foreground skippr:hover:border-primary/40"),
|
|
1542
|
+
children: [
|
|
1543
|
+
/* @__PURE__ */ jsx13(PanelLeft, {
|
|
1544
|
+
className: "skippr:size-5"
|
|
1545
|
+
}),
|
|
1546
|
+
/* @__PURE__ */ jsx13("span", {
|
|
1547
|
+
className: "skippr:text-xs skippr:font-medium",
|
|
1548
|
+
children: "Left"
|
|
1549
|
+
})
|
|
1550
|
+
]
|
|
1551
|
+
}),
|
|
1552
|
+
/* @__PURE__ */ jsxs10("button", {
|
|
1553
|
+
type: "button",
|
|
1554
|
+
onClick: () => setPosition("right"),
|
|
1555
|
+
className: cn("skippr:flex skippr:flex-1 skippr:flex-col skippr:items-center skippr:gap-2 skippr:rounded-lg skippr:border skippr:p-3 skippr:cursor-pointer skippr:transition-colors", position === "right" ? "skippr:border-primary skippr:bg-primary/5 skippr:text-primary" : "skippr:border-border skippr:text-muted-foreground skippr:hover:border-primary/40"),
|
|
1556
|
+
children: [
|
|
1557
|
+
/* @__PURE__ */ jsx13(PanelRight, {
|
|
1558
|
+
className: "skippr:size-5"
|
|
1559
|
+
}),
|
|
1560
|
+
/* @__PURE__ */ jsx13("span", {
|
|
1561
|
+
className: "skippr:text-xs skippr:font-medium",
|
|
1562
|
+
children: "Right"
|
|
1563
|
+
})
|
|
1564
|
+
]
|
|
1565
|
+
})
|
|
1566
|
+
]
|
|
1567
|
+
})
|
|
1568
|
+
]
|
|
1569
|
+
})
|
|
1570
|
+
})
|
|
1571
|
+
]
|
|
1572
|
+
});
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1294
1575
|
// src/components/Sidebar.tsx
|
|
1295
|
-
import { jsx as
|
|
1576
|
+
import { jsx as jsx14, jsxs as jsxs11, Fragment as Fragment2 } from "react/jsx-runtime";
|
|
1296
1577
|
function Sidebar() {
|
|
1297
1578
|
const {
|
|
1579
|
+
variant,
|
|
1298
1580
|
isConnected,
|
|
1299
1581
|
isStarting,
|
|
1300
1582
|
error,
|
|
1301
1583
|
startSession,
|
|
1302
1584
|
disconnect,
|
|
1303
1585
|
isPanelOpen,
|
|
1304
|
-
|
|
1586
|
+
position,
|
|
1305
1587
|
isAuthenticated,
|
|
1306
1588
|
isValidating,
|
|
1307
1589
|
authError,
|
|
@@ -1309,42 +1591,53 @@ function Sidebar() {
|
|
|
1309
1591
|
verifyOtp,
|
|
1310
1592
|
isAuthSubmitting
|
|
1311
1593
|
} = useLiveAgent();
|
|
1594
|
+
const [view, setView] = useState7("main");
|
|
1595
|
+
const isFloating = variant === "floating";
|
|
1596
|
+
const isSidebar = variant === "sidebar";
|
|
1312
1597
|
useEffect7(() => {
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1598
|
+
if (!isSidebar)
|
|
1599
|
+
return;
|
|
1600
|
+
const prop = position === "right" ? "marginRight" : "marginLeft";
|
|
1601
|
+
const opposite = position === "right" ? "marginLeft" : "marginRight";
|
|
1602
|
+
document.body.style.transition = "margin 300ms ease-in-out";
|
|
1603
|
+
document.body.style[opposite] = "";
|
|
1604
|
+
document.body.style[prop] = isPanelOpen ? `${SIDEBAR_WIDTH}px` : "";
|
|
1317
1605
|
return () => {
|
|
1318
1606
|
document.body.style.marginRight = "";
|
|
1607
|
+
document.body.style.marginLeft = "";
|
|
1319
1608
|
document.body.style.transition = "";
|
|
1320
1609
|
};
|
|
1321
|
-
}, []);
|
|
1322
|
-
return /* @__PURE__ */
|
|
1323
|
-
className: cn("skippr:fixed skippr:
|
|
1610
|
+
}, [isSidebar, isPanelOpen, position]);
|
|
1611
|
+
return /* @__PURE__ */ jsx14("div", {
|
|
1612
|
+
className: cn("skippr:fixed skippr:z-[9999]", "skippr:bg-background skippr:border skippr:border-border", "skippr:flex skippr:flex-col", "skippr:transition-all skippr:duration-300 skippr:ease-in-out skippr:overflow-hidden", isFloating && "skippr:bottom-4 skippr:min-h-[28rem] skippr:max-h-[calc(100vh-6rem)] skippr:rounded-2xl skippr:shadow-2xl", isFloating && (position === "right" ? "skippr:right-4" : "skippr:left-4"), isFloating && !isPanelOpen && "skippr:w-0 skippr:h-0 skippr:border-0", isSidebar && "skippr:top-0 skippr:h-full", 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"),
|
|
1324
1613
|
style: { width: isPanelOpen ? SIDEBAR_WIDTH : undefined },
|
|
1325
|
-
children:
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1614
|
+
children: view === "settings" ? /* @__PURE__ */ jsx14(SettingsView, {
|
|
1615
|
+
onBack: () => setView("main")
|
|
1616
|
+
}) : /* @__PURE__ */ jsxs11(Fragment2, {
|
|
1617
|
+
children: [
|
|
1618
|
+
/* @__PURE__ */ jsx14(ChatHeader, {
|
|
1619
|
+
onOpenSettings: () => setView("settings")
|
|
1620
|
+
}),
|
|
1621
|
+
isConnected ? /* @__PURE__ */ jsx14(ConnectedContent, {
|
|
1622
|
+
onDisconnect: disconnect
|
|
1623
|
+
}) : isValidating ? /* @__PURE__ */ jsx14("div", {
|
|
1624
|
+
className: "skippr:flex skippr:flex-1 skippr:items-center skippr:justify-center",
|
|
1625
|
+
children: /* @__PURE__ */ jsx14("p", {
|
|
1626
|
+
className: "skippr:text-sm skippr:text-muted-foreground",
|
|
1627
|
+
children: "Loading..."
|
|
1628
|
+
})
|
|
1629
|
+
}) : isAuthenticated ? /* @__PURE__ */ jsx14(QuickActions, {
|
|
1630
|
+
onStartSession: startSession,
|
|
1631
|
+
isStarting,
|
|
1632
|
+
error
|
|
1633
|
+
}) : /* @__PURE__ */ jsx14(LoginFlow, {
|
|
1634
|
+
requestOtp,
|
|
1635
|
+
verifyOtp,
|
|
1636
|
+
error: authError,
|
|
1637
|
+
isSubmitting: isAuthSubmitting
|
|
1336
1638
|
})
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
isStarting,
|
|
1340
|
-
error
|
|
1341
|
-
}) : /* @__PURE__ */ jsx12(LoginFlow, {
|
|
1342
|
-
requestOtp,
|
|
1343
|
-
verifyOtp,
|
|
1344
|
-
error: authError,
|
|
1345
|
-
isSubmitting: isAuthSubmitting
|
|
1346
|
-
})
|
|
1347
|
-
]
|
|
1639
|
+
]
|
|
1640
|
+
})
|
|
1348
1641
|
});
|
|
1349
1642
|
}
|
|
1350
1643
|
function ConnectedContent({ onDisconnect }) {
|
|
@@ -1354,33 +1647,33 @@ function ConnectedContent({ onDisconnect }) {
|
|
|
1354
1647
|
const { phases } = usePhaseUpdates();
|
|
1355
1648
|
const { questions } = useQuestionUpdates();
|
|
1356
1649
|
if (!isConnected) {
|
|
1357
|
-
return /* @__PURE__ */
|
|
1650
|
+
return /* @__PURE__ */ jsx14("div", {
|
|
1358
1651
|
className: "skippr:flex skippr:flex-1 skippr:items-center skippr:justify-center",
|
|
1359
|
-
children: /* @__PURE__ */
|
|
1652
|
+
children: /* @__PURE__ */ jsx14("p", {
|
|
1360
1653
|
className: "skippr:text-sm skippr:text-muted-foreground",
|
|
1361
1654
|
children: "Connecting..."
|
|
1362
1655
|
})
|
|
1363
1656
|
});
|
|
1364
1657
|
}
|
|
1365
1658
|
const isAgentSpeaking = agentState === "speaking";
|
|
1366
|
-
return /* @__PURE__ */
|
|
1659
|
+
return /* @__PURE__ */ jsxs11(Fragment2, {
|
|
1367
1660
|
children: [
|
|
1368
|
-
/* @__PURE__ */
|
|
1661
|
+
/* @__PURE__ */ jsx14(MeetingControls, {
|
|
1369
1662
|
onHangUp: onDisconnect
|
|
1370
1663
|
}),
|
|
1371
|
-
/* @__PURE__ */
|
|
1664
|
+
/* @__PURE__ */ jsxs11("div", {
|
|
1372
1665
|
className: "skippr:flex skippr:min-h-0 skippr:flex-1",
|
|
1373
1666
|
children: [
|
|
1374
|
-
/* @__PURE__ */
|
|
1375
|
-
className: "skippr:w-[
|
|
1376
|
-
children: /* @__PURE__ */
|
|
1667
|
+
/* @__PURE__ */ jsx14("div", {
|
|
1668
|
+
className: "skippr:w-[180px] skippr:shrink-0 skippr:overflow-y-auto skippr:border-r",
|
|
1669
|
+
children: /* @__PURE__ */ jsx14(SessionAgenda, {
|
|
1377
1670
|
phases,
|
|
1378
1671
|
questions
|
|
1379
1672
|
})
|
|
1380
1673
|
}),
|
|
1381
|
-
/* @__PURE__ */
|
|
1674
|
+
/* @__PURE__ */ jsx14("div", {
|
|
1382
1675
|
className: "skippr:flex skippr:min-w-0 skippr:flex-1 skippr:flex-col",
|
|
1383
|
-
children: /* @__PURE__ */
|
|
1676
|
+
children: /* @__PURE__ */ jsx14(MessageList, {
|
|
1384
1677
|
messages: allMessages,
|
|
1385
1678
|
isStreaming: isAgentSpeaking,
|
|
1386
1679
|
sendChatMessage,
|
|
@@ -1394,32 +1687,34 @@ function ConnectedContent({ onDisconnect }) {
|
|
|
1394
1687
|
}
|
|
1395
1688
|
|
|
1396
1689
|
// src/components/SidebarTrigger.tsx
|
|
1397
|
-
import { jsx as
|
|
1398
|
-
var TRIGGER_GAP = 16;
|
|
1399
|
-
var TRIGGER_DEFAULT_RIGHT = 24;
|
|
1690
|
+
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
1400
1691
|
function SidebarTrigger() {
|
|
1401
|
-
const { isPanelOpen, togglePanel } = useLiveAgent();
|
|
1402
|
-
|
|
1692
|
+
const { isPanelOpen, togglePanel, position, isMinimized, isConnected } = useLiveAgent();
|
|
1693
|
+
if (isMinimized && isConnected)
|
|
1694
|
+
return null;
|
|
1695
|
+
return /* @__PURE__ */ jsx15(Button, {
|
|
1403
1696
|
size: "icon-lg",
|
|
1404
1697
|
onClick: togglePanel,
|
|
1405
|
-
className: "skippr:fixed skippr:bottom-6 skippr:z-[9998] skippr:size-14 skippr:rounded-full skippr:shadow-lg skippr:transition-all skippr:duration-300",
|
|
1406
|
-
style: { right: isPanelOpen ? SIDEBAR_WIDTH + TRIGGER_GAP : TRIGGER_DEFAULT_RIGHT },
|
|
1698
|
+
className: cn("skippr:fixed skippr:bottom-6 skippr:z-[9998] skippr:size-14 skippr:rounded-full skippr:shadow-lg skippr:transition-all skippr:duration-300", position === "right" ? "skippr:right-6" : "skippr:left-6"),
|
|
1407
1699
|
title: isPanelOpen ? "Close chat" : "Chat with us",
|
|
1408
|
-
children: isPanelOpen ? /* @__PURE__ */
|
|
1700
|
+
children: isPanelOpen ? /* @__PURE__ */ jsx15(X, {
|
|
1409
1701
|
className: "skippr:size-6"
|
|
1410
|
-
}) : /* @__PURE__ */
|
|
1702
|
+
}) : /* @__PURE__ */ jsx15(MessageCircle, {
|
|
1411
1703
|
className: "skippr:size-6"
|
|
1412
1704
|
})
|
|
1413
1705
|
});
|
|
1414
1706
|
}
|
|
1415
1707
|
|
|
1416
1708
|
// src/components/LiveAgent.tsx
|
|
1417
|
-
import { jsx as
|
|
1709
|
+
import { jsx as jsx16, jsxs as jsxs12, Fragment as Fragment3 } from "react/jsx-runtime";
|
|
1418
1710
|
function LiveAgent({
|
|
1419
1711
|
agentId,
|
|
1420
1712
|
authToken: authTokenProp,
|
|
1421
1713
|
appKey,
|
|
1422
1714
|
userToken,
|
|
1715
|
+
position = "right",
|
|
1716
|
+
variant = "floating",
|
|
1717
|
+
minimizable = true,
|
|
1423
1718
|
defaultOpen = false,
|
|
1424
1719
|
children
|
|
1425
1720
|
}) {
|
|
@@ -1431,12 +1726,45 @@ function LiveAgent({
|
|
|
1431
1726
|
appKey,
|
|
1432
1727
|
userToken
|
|
1433
1728
|
});
|
|
1434
|
-
const [isPanelOpen, setIsPanelOpen] =
|
|
1435
|
-
const
|
|
1436
|
-
const
|
|
1437
|
-
|
|
1729
|
+
const [isPanelOpen, setIsPanelOpen] = useState8(defaultOpen);
|
|
1730
|
+
const [isMinimized, setIsMinimized] = useState8(false);
|
|
1731
|
+
const [currentPosition, setCurrentPosition] = useState8(() => {
|
|
1732
|
+
try {
|
|
1733
|
+
const saved = localStorage.getItem("skippr_widget_position");
|
|
1734
|
+
if (saved === "left" || saved === "right")
|
|
1735
|
+
return saved;
|
|
1736
|
+
} catch {}
|
|
1737
|
+
return position;
|
|
1738
|
+
});
|
|
1739
|
+
const setPositionWithPersist = useCallback8((pos) => {
|
|
1740
|
+
setCurrentPosition(pos);
|
|
1741
|
+
try {
|
|
1742
|
+
localStorage.setItem("skippr_widget_position", pos);
|
|
1743
|
+
} catch {}
|
|
1744
|
+
}, []);
|
|
1745
|
+
const openPanel = useCallback8(() => setIsPanelOpen(true), []);
|
|
1746
|
+
const closePanel = useCallback8(() => setIsPanelOpen(false), []);
|
|
1747
|
+
const togglePanel = useCallback8(() => setIsPanelOpen((prev) => !prev), []);
|
|
1748
|
+
const expandPanel = useCallback8(() => {
|
|
1749
|
+
setIsMinimized(false);
|
|
1750
|
+
setIsPanelOpen(true);
|
|
1751
|
+
}, []);
|
|
1752
|
+
const minimizePanel = useCallback8(() => {
|
|
1753
|
+
if (!minimizable)
|
|
1754
|
+
return;
|
|
1755
|
+
setIsMinimized(true);
|
|
1756
|
+
setIsPanelOpen(false);
|
|
1757
|
+
}, [minimizable]);
|
|
1438
1758
|
const isConnected = connection !== null;
|
|
1439
1759
|
const isAuthenticated = !!userToken || !!authTokenProp || auth.isAuthenticated;
|
|
1760
|
+
useEffect8(() => {
|
|
1761
|
+
if (connection && minimizable) {
|
|
1762
|
+
setIsMinimized(true);
|
|
1763
|
+
setIsPanelOpen(false);
|
|
1764
|
+
} else if (!connection) {
|
|
1765
|
+
setIsMinimized(false);
|
|
1766
|
+
}
|
|
1767
|
+
}, [connection, minimizable]);
|
|
1440
1768
|
const ctx = useMemo4(() => ({
|
|
1441
1769
|
connection,
|
|
1442
1770
|
shouldConnect,
|
|
@@ -1449,6 +1777,13 @@ function LiveAgent({
|
|
|
1449
1777
|
openPanel,
|
|
1450
1778
|
closePanel,
|
|
1451
1779
|
togglePanel,
|
|
1780
|
+
variant,
|
|
1781
|
+
position: currentPosition,
|
|
1782
|
+
setPosition: setPositionWithPersist,
|
|
1783
|
+
minimizable,
|
|
1784
|
+
isMinimized,
|
|
1785
|
+
expandPanel,
|
|
1786
|
+
minimizePanel,
|
|
1452
1787
|
isAuthenticated,
|
|
1453
1788
|
isValidating: auth.isValidating,
|
|
1454
1789
|
authError: auth.error,
|
|
@@ -1468,6 +1803,13 @@ function LiveAgent({
|
|
|
1468
1803
|
openPanel,
|
|
1469
1804
|
closePanel,
|
|
1470
1805
|
togglePanel,
|
|
1806
|
+
variant,
|
|
1807
|
+
currentPosition,
|
|
1808
|
+
setPositionWithPersist,
|
|
1809
|
+
minimizable,
|
|
1810
|
+
isMinimized,
|
|
1811
|
+
expandPanel,
|
|
1812
|
+
minimizePanel,
|
|
1471
1813
|
isAuthenticated,
|
|
1472
1814
|
auth.isValidating,
|
|
1473
1815
|
auth.error,
|
|
@@ -1476,17 +1818,18 @@ function LiveAgent({
|
|
|
1476
1818
|
auth.logout,
|
|
1477
1819
|
auth.isSubmitting
|
|
1478
1820
|
]);
|
|
1479
|
-
const widgetContent = /* @__PURE__ */
|
|
1821
|
+
const widgetContent = /* @__PURE__ */ jsxs12(Fragment3, {
|
|
1480
1822
|
children: [
|
|
1481
|
-
connection && /* @__PURE__ */
|
|
1482
|
-
/* @__PURE__ */
|
|
1483
|
-
/* @__PURE__ */
|
|
1823
|
+
connection && /* @__PURE__ */ jsx16(RoomAudioRenderer, {}),
|
|
1824
|
+
isMinimized && isConnected && /* @__PURE__ */ jsx16(MinimizedBubble, {}),
|
|
1825
|
+
/* @__PURE__ */ jsx16(SidebarTrigger, {}),
|
|
1826
|
+
/* @__PURE__ */ jsx16(Sidebar, {}),
|
|
1484
1827
|
children
|
|
1485
1828
|
]
|
|
1486
1829
|
});
|
|
1487
|
-
return /* @__PURE__ */
|
|
1830
|
+
return /* @__PURE__ */ jsx16(LiveAgentContext.Provider, {
|
|
1488
1831
|
value: ctx,
|
|
1489
|
-
children: connection ? /* @__PURE__ */
|
|
1832
|
+
children: connection ? /* @__PURE__ */ jsx16(LiveKitRoom, {
|
|
1490
1833
|
serverUrl: connection.livekitUrl,
|
|
1491
1834
|
token: connection.token,
|
|
1492
1835
|
connect: shouldConnect,
|