@skippr/live-agent-sdk 0.15.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 +855 -489
- package/dist/skippr-sdk.css +1 -1
- package/dist/skippr-sdk.js +128 -128
- 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";
|
|
@@ -145,17 +145,21 @@ function useAuth({ appKey }) {
|
|
|
145
145
|
}
|
|
146
146
|
|
|
147
147
|
// src/hooks/useSession.ts
|
|
148
|
-
import { useCallback as useCallback2, useState as useState2 } from "react";
|
|
148
|
+
import { useCallback as useCallback2, useEffect as useEffect2, useState as useState2 } from "react";
|
|
149
149
|
var API_URL2 = "https://skipprapi-production.up.railway.app";
|
|
150
|
-
function
|
|
151
|
-
const
|
|
152
|
-
|
|
153
|
-
headers
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
150
|
+
async function exchangeForBearerToken(appKey, userToken) {
|
|
151
|
+
const resp = await fetch(`${API_URL2}/v1/auth/token-exchange`, {
|
|
152
|
+
method: "POST",
|
|
153
|
+
headers: {
|
|
154
|
+
"X-App-Key": appKey,
|
|
155
|
+
"X-User-Token": userToken
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
if (!resp.ok) {
|
|
159
|
+
throw new Error(`Token exchange failed: ${resp.status}`);
|
|
160
|
+
}
|
|
161
|
+
const { token } = await resp.json();
|
|
162
|
+
return token;
|
|
159
163
|
}
|
|
160
164
|
function useSession({ agentId, authToken, appKey, userToken }) {
|
|
161
165
|
const [connection, setConnection] = useState2(null);
|
|
@@ -163,32 +167,53 @@ function useSession({ agentId, authToken, appKey, userToken }) {
|
|
|
163
167
|
const [isStarting, setIsStarting] = useState2(false);
|
|
164
168
|
const [error, setError] = useState2("");
|
|
165
169
|
const [sessionId, setSessionId] = useState2(null);
|
|
166
|
-
const [
|
|
170
|
+
const [bearerToken, setBearerToken] = useState2(authToken ?? null);
|
|
171
|
+
useEffect2(() => {
|
|
172
|
+
let stale = false;
|
|
173
|
+
if (authToken) {
|
|
174
|
+
setBearerToken(authToken);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
if (appKey && userToken) {
|
|
178
|
+
exchangeForBearerToken(appKey, userToken).then((token) => {
|
|
179
|
+
if (!stale)
|
|
180
|
+
setBearerToken(token);
|
|
181
|
+
}).catch((e) => {
|
|
182
|
+
if (!stale)
|
|
183
|
+
setError(e instanceof Error ? e.message : "Token exchange failed");
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
return () => {
|
|
187
|
+
stale = true;
|
|
188
|
+
};
|
|
189
|
+
}, [authToken, appKey, userToken]);
|
|
167
190
|
const startSession = useCallback2(async () => {
|
|
191
|
+
if (!bearerToken) {
|
|
192
|
+
setError("No auth token available");
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
const headers = { Authorization: `Bearer ${bearerToken}` };
|
|
168
196
|
setIsStarting(true);
|
|
169
197
|
setError("");
|
|
170
198
|
try {
|
|
171
|
-
const authHeaders = resolveAuthHeaders(authToken, appKey, userToken);
|
|
172
199
|
const createResp = await fetch(`${API_URL2}/v1/sessions`, {
|
|
173
200
|
method: "POST",
|
|
174
|
-
headers: { "Content-Type": "application/json", ...
|
|
201
|
+
headers: { "Content-Type": "application/json", ...headers },
|
|
175
202
|
body: JSON.stringify({ agentId })
|
|
176
203
|
});
|
|
177
204
|
if (!createResp.ok) {
|
|
178
205
|
throw new Error(`Failed to create session: ${createResp.status}`);
|
|
179
206
|
}
|
|
180
207
|
const { session } = await createResp.json();
|
|
181
|
-
const sessionHeaders = { "X-Session-Token": session.sessionToken };
|
|
182
208
|
const startResp = await fetch(`${API_URL2}/v1/sessions/${session.id}/start`, {
|
|
183
209
|
method: "POST",
|
|
184
|
-
headers
|
|
210
|
+
headers
|
|
185
211
|
});
|
|
186
212
|
if (!startResp.ok) {
|
|
187
213
|
throw new Error(`Failed to start session: ${startResp.status}`);
|
|
188
214
|
}
|
|
189
215
|
const { connection: conn } = await startResp.json();
|
|
190
216
|
setSessionId(session.id);
|
|
191
|
-
setSessionToken(session.sessionToken);
|
|
192
217
|
setConnection({
|
|
193
218
|
livekitUrl: conn.livekitUrl,
|
|
194
219
|
token: conn.token
|
|
@@ -199,14 +224,13 @@ function useSession({ agentId, authToken, appKey, userToken }) {
|
|
|
199
224
|
} finally {
|
|
200
225
|
setIsStarting(false);
|
|
201
226
|
}
|
|
202
|
-
}, [agentId,
|
|
227
|
+
}, [agentId, bearerToken]);
|
|
203
228
|
const disconnect = useCallback2(async () => {
|
|
204
|
-
if (sessionId &&
|
|
205
|
-
const sessionHeaders = { "X-Session-Token": sessionToken };
|
|
229
|
+
if (sessionId && bearerToken) {
|
|
206
230
|
try {
|
|
207
231
|
await fetch(`${API_URL2}/v1/sessions/${sessionId}/complete`, {
|
|
208
232
|
method: "POST",
|
|
209
|
-
headers: { "Content-Type": "application/json",
|
|
233
|
+
headers: { "Content-Type": "application/json", Authorization: `Bearer ${bearerToken}` },
|
|
210
234
|
body: JSON.stringify({})
|
|
211
235
|
});
|
|
212
236
|
} catch {}
|
|
@@ -215,193 +239,13 @@ function useSession({ agentId, authToken, appKey, userToken }) {
|
|
|
215
239
|
setShouldConnect(false);
|
|
216
240
|
setConnection(null);
|
|
217
241
|
setSessionId(null);
|
|
218
|
-
|
|
219
|
-
}, [sessionId, sessionToken]);
|
|
242
|
+
}, [sessionId, bearerToken]);
|
|
220
243
|
return { connection, shouldConnect, isStarting, error, startSession, disconnect };
|
|
221
244
|
}
|
|
222
245
|
|
|
223
|
-
// src/components/
|
|
224
|
-
import {
|
|
225
|
-
import {
|
|
226
|
-
import { useEffect as useEffect6 } from "react";
|
|
227
|
-
|
|
228
|
-
// src/hooks/useCombinedMessages.ts
|
|
229
|
-
import { useVoiceAssistant } from "@livekit/components-react";
|
|
230
|
-
import { useMemo as useMemo3 } from "react";
|
|
231
|
-
|
|
232
|
-
// src/hooks/useChatMessages.ts
|
|
233
|
-
import { useChat, useLocalParticipant } from "@livekit/components-react";
|
|
234
|
-
import { useMemo } from "react";
|
|
235
|
-
|
|
236
|
-
// src/lib/filterSystemMessages.ts
|
|
237
|
-
var SYSTEM_MESSAGE_PATTERN = /^\[\w+\]$/;
|
|
238
|
-
function filterSystemMessages(messages) {
|
|
239
|
-
return messages.filter((m) => !SYSTEM_MESSAGE_PATTERN.test(m.content.trim()));
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
// src/hooks/useChatMessages.ts
|
|
243
|
-
function useChatMessages() {
|
|
244
|
-
const { chatMessages: rawMessages, send, isSending } = useChat();
|
|
245
|
-
const { localParticipant } = useLocalParticipant();
|
|
246
|
-
const localIdentity = localParticipant.identity;
|
|
247
|
-
const chatMessages = useMemo(() => {
|
|
248
|
-
const sortedMessages = rawMessages.map((msg) => ({
|
|
249
|
-
id: msg.id,
|
|
250
|
-
role: msg.from?.identity === localIdentity ? "user" : "assistant",
|
|
251
|
-
content: msg.message,
|
|
252
|
-
source: "chat",
|
|
253
|
-
timestamp: msg.timestamp
|
|
254
|
-
})).sort((a, b) => (a.timestamp ?? 0) - (b.timestamp ?? 0));
|
|
255
|
-
return filterSystemMessages(sortedMessages);
|
|
256
|
-
}, [rawMessages, localIdentity]);
|
|
257
|
-
return { chatMessages, sendChatMessage: send, isSendingChat: isSending };
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
// src/hooks/useStreamingTranscript.ts
|
|
261
|
-
import { useLocalParticipant as useLocalParticipant2, useTranscriptions } from "@livekit/components-react";
|
|
262
|
-
import { useMemo as useMemo2 } from "react";
|
|
263
|
-
function useStreamingTranscript() {
|
|
264
|
-
const transcriptions = useTranscriptions();
|
|
265
|
-
const { localParticipant } = useLocalParticipant2();
|
|
266
|
-
const localIdentity = localParticipant.identity;
|
|
267
|
-
const transcriptMessages = useMemo2(() => filterSystemMessages(transcriptions.filter((stream) => stream.text.trim().length > 0).map((stream) => ({
|
|
268
|
-
id: stream.streamInfo.id,
|
|
269
|
-
role: stream.participantInfo.identity === localIdentity ? "user" : "assistant",
|
|
270
|
-
content: stream.text,
|
|
271
|
-
source: "voice-transcript",
|
|
272
|
-
timestamp: stream.streamInfo.timestamp
|
|
273
|
-
}))), [transcriptions, localIdentity]);
|
|
274
|
-
return { transcriptMessages };
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
// src/hooks/useCombinedMessages.ts
|
|
278
|
-
function mergeChatsIntoTranscripts(transcripts, chats) {
|
|
279
|
-
const merged = [];
|
|
280
|
-
let chatIndex = 0;
|
|
281
|
-
for (const transcript of transcripts) {
|
|
282
|
-
while (chatIndex < chats.length && (chats[chatIndex].timestamp ?? 0) <= (transcript.timestamp ?? 0)) {
|
|
283
|
-
merged.push(chats[chatIndex]);
|
|
284
|
-
chatIndex++;
|
|
285
|
-
}
|
|
286
|
-
merged.push(transcript);
|
|
287
|
-
}
|
|
288
|
-
while (chatIndex < chats.length) {
|
|
289
|
-
merged.push(chats[chatIndex]);
|
|
290
|
-
chatIndex++;
|
|
291
|
-
}
|
|
292
|
-
return merged;
|
|
293
|
-
}
|
|
294
|
-
function useCombinedMessages() {
|
|
295
|
-
const { transcriptMessages } = useStreamingTranscript();
|
|
296
|
-
const { chatMessages, sendChatMessage, isSendingChat } = useChatMessages();
|
|
297
|
-
const { state: agentState } = useVoiceAssistant();
|
|
298
|
-
const allMessages = useMemo3(() => {
|
|
299
|
-
if (chatMessages.length === 0)
|
|
300
|
-
return transcriptMessages;
|
|
301
|
-
if (transcriptMessages.length === 0)
|
|
302
|
-
return chatMessages;
|
|
303
|
-
return mergeChatsIntoTranscripts(transcriptMessages, chatMessages);
|
|
304
|
-
}, [transcriptMessages, chatMessages]);
|
|
305
|
-
return { allMessages, agentState, sendChatMessage, isSendingChat };
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
// src/hooks/useLiveAgent.ts
|
|
309
|
-
import { use } from "react";
|
|
310
|
-
function useLiveAgent() {
|
|
311
|
-
const ctx = use(LiveAgentContext);
|
|
312
|
-
if (!ctx) {
|
|
313
|
-
throw new Error("useLiveAgent must be used within a <LiveAgent> provider");
|
|
314
|
-
}
|
|
315
|
-
const { connection, shouldConnect, ...publicValue } = ctx;
|
|
316
|
-
return publicValue;
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
// src/hooks/usePhaseUpdates.ts
|
|
320
|
-
import { useCallback as useCallback3 } from "react";
|
|
321
|
-
|
|
322
|
-
// src/hooks/useAgentState.ts
|
|
323
|
-
import { useRemoteParticipants } from "@livekit/components-react";
|
|
324
|
-
import { useEffect as useEffect2, useState as useState3 } from "react";
|
|
325
|
-
function useAgentState(attributeKey, parse, initial) {
|
|
326
|
-
const [value, setValue] = useState3(initial);
|
|
327
|
-
const remoteParticipants = useRemoteParticipants();
|
|
328
|
-
useEffect2(() => {
|
|
329
|
-
const agentParticipant = remoteParticipants.find((p) => p.attributes?.[attributeKey]);
|
|
330
|
-
if (agentParticipant) {
|
|
331
|
-
const attr = agentParticipant.attributes?.[attributeKey];
|
|
332
|
-
if (attr) {
|
|
333
|
-
const parsed = parse(attr);
|
|
334
|
-
if (parsed)
|
|
335
|
-
setValue(parsed);
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
const handlers = new Map;
|
|
339
|
-
for (const p of remoteParticipants) {
|
|
340
|
-
const handler = (changedAttributes) => {
|
|
341
|
-
if (changedAttributes[attributeKey]) {
|
|
342
|
-
const parsed = parse(changedAttributes[attributeKey]);
|
|
343
|
-
if (parsed)
|
|
344
|
-
setValue(parsed);
|
|
345
|
-
} else if (p.attributes?.[attributeKey]) {
|
|
346
|
-
const parsed = parse(p.attributes[attributeKey]);
|
|
347
|
-
if (parsed)
|
|
348
|
-
setValue(parsed);
|
|
349
|
-
}
|
|
350
|
-
};
|
|
351
|
-
handlers.set(p, handler);
|
|
352
|
-
p.on("attributesChanged", handler);
|
|
353
|
-
}
|
|
354
|
-
return () => {
|
|
355
|
-
for (const [p, handler] of handlers) {
|
|
356
|
-
p.off("attributesChanged", handler);
|
|
357
|
-
}
|
|
358
|
-
};
|
|
359
|
-
}, [remoteParticipants, attributeKey, parse]);
|
|
360
|
-
return value;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
// src/hooks/usePhaseUpdates.ts
|
|
364
|
-
function parsePhases(json) {
|
|
365
|
-
try {
|
|
366
|
-
const data = JSON.parse(json);
|
|
367
|
-
if (data.type === "phase_update" && Array.isArray(data.phases)) {
|
|
368
|
-
return data.phases;
|
|
369
|
-
}
|
|
370
|
-
} catch {}
|
|
371
|
-
return null;
|
|
372
|
-
}
|
|
373
|
-
function usePhaseUpdates() {
|
|
374
|
-
const parse = useCallback3(parsePhases, []);
|
|
375
|
-
const phases = useAgentState("phases", parse, []);
|
|
376
|
-
return { phases };
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
// src/hooks/useQuestionUpdates.ts
|
|
380
|
-
import { useCallback as useCallback4 } from "react";
|
|
381
|
-
function parseQuestions(json) {
|
|
382
|
-
try {
|
|
383
|
-
const data = JSON.parse(json);
|
|
384
|
-
if (data.type === "question_update" && Array.isArray(data.questions)) {
|
|
385
|
-
return data.questions;
|
|
386
|
-
}
|
|
387
|
-
} catch {}
|
|
388
|
-
return null;
|
|
389
|
-
}
|
|
390
|
-
function useQuestionUpdates() {
|
|
391
|
-
const parse = useCallback4(parseQuestions, []);
|
|
392
|
-
const questions = useAgentState("questions", parse, []);
|
|
393
|
-
return { questions };
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
// src/lib/constants.ts
|
|
397
|
-
var SIDEBAR_WIDTH = 600;
|
|
398
|
-
|
|
399
|
-
// src/lib/utils.ts
|
|
400
|
-
import { clsx } from "clsx";
|
|
401
|
-
import { twMerge } from "tailwind-merge";
|
|
402
|
-
function cn(...inputs) {
|
|
403
|
-
return twMerge(clsx(inputs));
|
|
404
|
-
}
|
|
246
|
+
// src/components/MinimizedBubble.tsx
|
|
247
|
+
import { useLocalParticipant, useVoiceAssistant } from "@livekit/components-react";
|
|
248
|
+
import { ScreenSharePresets } from "livekit-client";
|
|
405
249
|
// ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/createLucideIcon.js
|
|
406
250
|
import { forwardRef as forwardRef2, createElement as createElement2 } from "react";
|
|
407
251
|
|
|
@@ -501,112 +345,471 @@ var __iconNode2 = [
|
|
|
501
345
|
["path", { d: "M12 17h.01", key: "p32p05" }]
|
|
502
346
|
];
|
|
503
347
|
var MessageCircleQuestionMark = createLucideIcon("message-circle-question-mark", __iconNode2);
|
|
504
|
-
// ../../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
|
|
505
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 = [
|
|
506
356
|
[
|
|
507
357
|
"path",
|
|
508
358
|
{
|
|
509
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",
|
|
510
360
|
key: "117uat"
|
|
511
361
|
}
|
|
512
|
-
],
|
|
513
|
-
["path", { d: "M6 12h16", key: "s4cdu5" }]
|
|
514
|
-
];
|
|
515
|
-
var SendHorizontal = createLucideIcon("send-horizontal",
|
|
516
|
-
// ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/
|
|
517
|
-
var
|
|
518
|
-
["path", { d: "
|
|
519
|
-
["
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
]
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
var
|
|
532
|
-
// ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/
|
|
533
|
-
var __iconNode7 = [
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
];
|
|
537
|
-
var
|
|
538
|
-
// ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/
|
|
539
|
-
var
|
|
540
|
-
[
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
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);
|
|
545
764
|
}
|
|
546
|
-
|
|
547
|
-
]
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
[
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
["path", { d: "M12 19v3", key: "npa21l" }],
|
|
562
|
-
["path", { d: "M19 10v2a7 7 0 0 1-14 0v-2", key: "1vc78b" }],
|
|
563
|
-
["rect", { x: "9", y: "2", width: "6", height: "13", rx: "3", key: "s6n7sd" }]
|
|
564
|
-
];
|
|
565
|
-
var Mic = createLucideIcon("mic", __iconNode10);
|
|
566
|
-
// ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/monitor-off.js
|
|
567
|
-
var __iconNode11 = [
|
|
568
|
-
["path", { d: "M12 17v4", key: "1riwvh" }],
|
|
569
|
-
["path", { d: "M17 17H4a2 2 0 0 1-2-2V5a2 2 0 0 1 1.184-1.826", key: "cv7jms" }],
|
|
570
|
-
["path", { d: "m2 2 20 20", key: "1ooewy" }],
|
|
571
|
-
["path", { d: "M8 21h8", key: "1ev6f3" }],
|
|
572
|
-
["path", { d: "M8.656 3H20a2 2 0 0 1 2 2v10a2 2 0 0 1-.293 1.042", key: "z8ni2w" }]
|
|
573
|
-
];
|
|
574
|
-
var MonitorOff = createLucideIcon("monitor-off", __iconNode11);
|
|
575
|
-
// ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/monitor.js
|
|
576
|
-
var __iconNode12 = [
|
|
577
|
-
["rect", { width: "20", height: "14", x: "2", y: "3", rx: "2", key: "48i651" }],
|
|
578
|
-
["line", { x1: "8", x2: "16", y1: "21", y2: "21", key: "1svkeh" }],
|
|
579
|
-
["line", { x1: "12", x2: "12", y1: "17", y2: "21", key: "vw1qmm" }]
|
|
580
|
-
];
|
|
581
|
-
var Monitor = createLucideIcon("monitor", __iconNode12);
|
|
582
|
-
// ../../node_modules/.bun/lucide-react@0.563.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/phone-off.js
|
|
583
|
-
var __iconNode13 = [
|
|
584
|
-
[
|
|
585
|
-
"path",
|
|
586
|
-
{
|
|
587
|
-
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",
|
|
588
|
-
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;
|
|
589
780
|
}
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
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;
|
|
597
797
|
}
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
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
|
+
|
|
607
810
|
// src/components/ui/button.tsx
|
|
608
811
|
import { forwardRef as forwardRef3 } from "react";
|
|
609
|
-
import { jsx } from "react/jsx-runtime";
|
|
812
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
610
813
|
var variantClasses = {
|
|
611
814
|
default: "skippr:bg-primary skippr:text-primary-foreground skippr:hover:bg-primary/90",
|
|
612
815
|
destructive: "skippr:bg-destructive skippr:text-white skippr:hover:bg-destructive/90",
|
|
@@ -625,7 +828,7 @@ var sizeClasses = {
|
|
|
625
828
|
"icon-lg": "skippr:size-10"
|
|
626
829
|
};
|
|
627
830
|
var Button = forwardRef3(({ className, variant = "default", size = "default", ...props }, ref) => {
|
|
628
|
-
return /* @__PURE__ */
|
|
831
|
+
return /* @__PURE__ */ jsx2("button", {
|
|
629
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),
|
|
630
833
|
ref,
|
|
631
834
|
...props
|
|
@@ -634,61 +837,88 @@ var Button = forwardRef3(({ className, variant = "default", size = "default", ..
|
|
|
634
837
|
Button.displayName = "Button";
|
|
635
838
|
|
|
636
839
|
// src/components/ChatHeader.tsx
|
|
637
|
-
import { jsx as
|
|
638
|
-
function ChatHeader({
|
|
639
|
-
|
|
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", {
|
|
640
844
|
className: "skippr:flex skippr:items-center skippr:gap-3 skippr:bg-primary skippr:px-4 skippr:py-3 skippr:text-primary-foreground",
|
|
641
845
|
children: [
|
|
642
|
-
/* @__PURE__ */
|
|
846
|
+
/* @__PURE__ */ jsx3("div", {
|
|
643
847
|
className: "skippr:flex skippr:size-6 skippr:items-center skippr:justify-center skippr:rounded-full skippr:bg-primary-foreground/20",
|
|
644
|
-
children: /* @__PURE__ */
|
|
848
|
+
children: /* @__PURE__ */ jsx3(Bot, {
|
|
645
849
|
className: "skippr:size-3.5 skippr:text-primary-foreground"
|
|
646
850
|
})
|
|
647
851
|
}),
|
|
648
|
-
/* @__PURE__ */
|
|
852
|
+
/* @__PURE__ */ jsx3("div", {
|
|
649
853
|
className: "skippr:flex-1",
|
|
650
|
-
children: /* @__PURE__ */
|
|
854
|
+
children: /* @__PURE__ */ jsx3("p", {
|
|
651
855
|
className: "skippr:text-sm skippr:font-semibold skippr:leading-none",
|
|
652
856
|
children: "AI Agent"
|
|
653
857
|
})
|
|
654
858
|
}),
|
|
655
|
-
/* @__PURE__ */
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
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
|
+
]
|
|
663
893
|
})
|
|
664
894
|
]
|
|
665
895
|
});
|
|
666
896
|
}
|
|
667
897
|
|
|
668
898
|
// src/components/LoginFlow.tsx
|
|
669
|
-
import { useCallback as
|
|
670
|
-
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";
|
|
671
901
|
var OTP_LENGTH = 6;
|
|
672
902
|
var DIGIT_KEYS = ["d0", "d1", "d2", "d3", "d4", "d5"];
|
|
673
903
|
function LoginFlow({ requestOtp, verifyOtp, error, isSubmitting }) {
|
|
674
904
|
const [step, setStep] = useState4("email");
|
|
675
905
|
const [email, setEmail] = useState4("");
|
|
676
|
-
const handleRequestOtp =
|
|
906
|
+
const handleRequestOtp = useCallback6(async (emailValue) => {
|
|
677
907
|
const success = await requestOtp(emailValue);
|
|
678
908
|
if (success)
|
|
679
909
|
setStep("otp");
|
|
680
910
|
}, [requestOtp]);
|
|
681
|
-
const handleVerifyOtp =
|
|
911
|
+
const handleVerifyOtp = useCallback6(async (code) => {
|
|
682
912
|
await verifyOtp(email, code);
|
|
683
913
|
}, [verifyOtp, email]);
|
|
684
|
-
const handleBack =
|
|
914
|
+
const handleBack = useCallback6(() => {
|
|
685
915
|
setStep("email");
|
|
686
916
|
}, []);
|
|
687
|
-
const handleResend =
|
|
917
|
+
const handleResend = useCallback6(async () => {
|
|
688
918
|
await requestOtp(email);
|
|
689
919
|
}, [requestOtp, email]);
|
|
690
920
|
if (step === "otp") {
|
|
691
|
-
return /* @__PURE__ */
|
|
921
|
+
return /* @__PURE__ */ jsx4(OtpStep, {
|
|
692
922
|
email,
|
|
693
923
|
onSubmit: handleVerifyOtp,
|
|
694
924
|
onResend: handleResend,
|
|
@@ -697,7 +927,7 @@ function LoginFlow({ requestOtp, verifyOtp, error, isSubmitting }) {
|
|
|
697
927
|
isSubmitting
|
|
698
928
|
});
|
|
699
929
|
}
|
|
700
|
-
return /* @__PURE__ */
|
|
930
|
+
return /* @__PURE__ */ jsx4(EmailStep, {
|
|
701
931
|
email,
|
|
702
932
|
onEmailChange: setEmail,
|
|
703
933
|
onSubmit: handleRequestOtp,
|
|
@@ -711,30 +941,30 @@ function EmailStep({ email, onEmailChange, onSubmit, error, isSubmitting }) {
|
|
|
711
941
|
if (email.trim())
|
|
712
942
|
onSubmit(email.trim());
|
|
713
943
|
}
|
|
714
|
-
return /* @__PURE__ */
|
|
944
|
+
return /* @__PURE__ */ jsxs3("div", {
|
|
715
945
|
className: "skippr:flex skippr:flex-1 skippr:flex-col skippr:px-4 skippr:py-4",
|
|
716
946
|
children: [
|
|
717
|
-
/* @__PURE__ */
|
|
947
|
+
/* @__PURE__ */ jsxs3("div", {
|
|
718
948
|
className: "skippr:mb-4 skippr:text-center",
|
|
719
949
|
children: [
|
|
720
|
-
/* @__PURE__ */
|
|
950
|
+
/* @__PURE__ */ jsx4(Mail, {
|
|
721
951
|
className: "skippr:mx-auto skippr:mb-2 skippr:size-6 skippr:text-primary"
|
|
722
952
|
}),
|
|
723
|
-
/* @__PURE__ */
|
|
953
|
+
/* @__PURE__ */ jsx4("p", {
|
|
724
954
|
className: "skippr:text-sm skippr:font-medium skippr:text-foreground",
|
|
725
955
|
children: "Sign in to continue"
|
|
726
956
|
}),
|
|
727
|
-
/* @__PURE__ */
|
|
957
|
+
/* @__PURE__ */ jsx4("p", {
|
|
728
958
|
className: "skippr:mt-1 skippr:text-xs skippr:text-muted-foreground",
|
|
729
959
|
children: "Your email will be used to identify you across sessions"
|
|
730
960
|
})
|
|
731
961
|
]
|
|
732
962
|
}),
|
|
733
|
-
/* @__PURE__ */
|
|
963
|
+
/* @__PURE__ */ jsxs3("form", {
|
|
734
964
|
onSubmit: handleSubmit,
|
|
735
965
|
className: "skippr:flex skippr:flex-col skippr:gap-3",
|
|
736
966
|
children: [
|
|
737
|
-
/* @__PURE__ */
|
|
967
|
+
/* @__PURE__ */ jsx4("input", {
|
|
738
968
|
type: "email",
|
|
739
969
|
placeholder: "you@example.com",
|
|
740
970
|
value: email,
|
|
@@ -743,15 +973,15 @@ function EmailStep({ email, onEmailChange, onSubmit, error, isSubmitting }) {
|
|
|
743
973
|
required: true,
|
|
744
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"
|
|
745
975
|
}),
|
|
746
|
-
/* @__PURE__ */
|
|
976
|
+
/* @__PURE__ */ jsx4(Button, {
|
|
747
977
|
type: "submit",
|
|
748
978
|
disabled: isSubmitting || !email.trim(),
|
|
749
979
|
className: "skippr:w-full",
|
|
750
|
-
children: isSubmitting ? /* @__PURE__ */
|
|
980
|
+
children: isSubmitting ? /* @__PURE__ */ jsx4(LoaderCircle, {
|
|
751
981
|
className: "skippr:size-4 skippr:animate-spin"
|
|
752
982
|
}) : "Continue"
|
|
753
983
|
}),
|
|
754
|
-
error && /* @__PURE__ */
|
|
984
|
+
error && /* @__PURE__ */ jsx4("p", {
|
|
755
985
|
className: "skippr:text-xs skippr:text-center skippr:text-destructive",
|
|
756
986
|
children: error
|
|
757
987
|
})
|
|
@@ -765,26 +995,26 @@ function OtpStep({ email, onSubmit, onResend, onBack, error, isSubmitting }) {
|
|
|
765
995
|
const [resendCooldown, setResendCooldown] = useState4(0);
|
|
766
996
|
const inputRefs = useRef([]);
|
|
767
997
|
const submittedRef = useRef(false);
|
|
768
|
-
|
|
998
|
+
useEffect4(() => {
|
|
769
999
|
inputRefs.current[0]?.focus();
|
|
770
1000
|
}, []);
|
|
771
|
-
|
|
1001
|
+
useEffect4(() => {
|
|
772
1002
|
if (error)
|
|
773
1003
|
submittedRef.current = false;
|
|
774
1004
|
}, [error]);
|
|
775
|
-
|
|
1005
|
+
useEffect4(() => {
|
|
776
1006
|
if (resendCooldown <= 0)
|
|
777
1007
|
return;
|
|
778
1008
|
const timer = setTimeout(() => setResendCooldown((c) => c - 1), 1000);
|
|
779
1009
|
return () => clearTimeout(timer);
|
|
780
1010
|
}, [resendCooldown]);
|
|
781
|
-
const submitCode =
|
|
1011
|
+
const submitCode = useCallback6((code) => {
|
|
782
1012
|
if (submittedRef.current || isSubmitting)
|
|
783
1013
|
return;
|
|
784
1014
|
submittedRef.current = true;
|
|
785
1015
|
onSubmit(code);
|
|
786
1016
|
}, [onSubmit, isSubmitting]);
|
|
787
|
-
const handleDigitChange =
|
|
1017
|
+
const handleDigitChange = useCallback6((index2, value) => {
|
|
788
1018
|
const digit = value.replace(/\D/g, "").slice(-1);
|
|
789
1019
|
const newDigits = [...digits];
|
|
790
1020
|
newDigits[index2] = digit;
|
|
@@ -798,12 +1028,12 @@ function OtpStep({ email, onSubmit, onResend, onBack, error, isSubmitting }) {
|
|
|
798
1028
|
submitCode(code);
|
|
799
1029
|
}
|
|
800
1030
|
}, [digits, submitCode]);
|
|
801
|
-
const handleKeyDown =
|
|
1031
|
+
const handleKeyDown = useCallback6((index2, e) => {
|
|
802
1032
|
if (e.key === "Backspace" && !digits[index2] && index2 > 0) {
|
|
803
1033
|
inputRefs.current[index2 - 1]?.focus();
|
|
804
1034
|
}
|
|
805
1035
|
}, [digits]);
|
|
806
|
-
const handlePaste =
|
|
1036
|
+
const handlePaste = useCallback6((e) => {
|
|
807
1037
|
e.preventDefault();
|
|
808
1038
|
const pasted = e.clipboardData.getData("text").replace(/\D/g, "").slice(0, OTP_LENGTH);
|
|
809
1039
|
if (pasted.length > 0) {
|
|
@@ -831,22 +1061,22 @@ function OtpStep({ email, onSubmit, onResend, onBack, error, isSubmitting }) {
|
|
|
831
1061
|
submittedRef.current = false;
|
|
832
1062
|
inputRefs.current[0]?.focus();
|
|
833
1063
|
}
|
|
834
|
-
return /* @__PURE__ */
|
|
1064
|
+
return /* @__PURE__ */ jsxs3("div", {
|
|
835
1065
|
className: "skippr:flex skippr:flex-1 skippr:flex-col skippr:px-4 skippr:py-4",
|
|
836
1066
|
children: [
|
|
837
|
-
/* @__PURE__ */
|
|
1067
|
+
/* @__PURE__ */ jsxs3("div", {
|
|
838
1068
|
className: "skippr:mb-4 skippr:text-center",
|
|
839
1069
|
children: [
|
|
840
|
-
/* @__PURE__ */
|
|
1070
|
+
/* @__PURE__ */ jsx4("p", {
|
|
841
1071
|
className: "skippr:text-sm skippr:font-medium skippr:text-foreground",
|
|
842
1072
|
children: "Enter verification code"
|
|
843
1073
|
}),
|
|
844
|
-
/* @__PURE__ */
|
|
1074
|
+
/* @__PURE__ */ jsxs3("p", {
|
|
845
1075
|
className: "skippr:mt-1 skippr:text-xs skippr:text-muted-foreground",
|
|
846
1076
|
children: [
|
|
847
1077
|
"We sent a 6-digit code to",
|
|
848
1078
|
" ",
|
|
849
|
-
/* @__PURE__ */
|
|
1079
|
+
/* @__PURE__ */ jsx4("span", {
|
|
850
1080
|
className: "skippr:font-medium skippr:text-foreground",
|
|
851
1081
|
children: email
|
|
852
1082
|
})
|
|
@@ -854,13 +1084,13 @@ function OtpStep({ email, onSubmit, onResend, onBack, error, isSubmitting }) {
|
|
|
854
1084
|
})
|
|
855
1085
|
]
|
|
856
1086
|
}),
|
|
857
|
-
/* @__PURE__ */
|
|
1087
|
+
/* @__PURE__ */ jsxs3("form", {
|
|
858
1088
|
onSubmit: handleSubmit,
|
|
859
1089
|
className: "skippr:flex skippr:flex-col skippr:gap-3",
|
|
860
1090
|
children: [
|
|
861
|
-
/* @__PURE__ */
|
|
1091
|
+
/* @__PURE__ */ jsx4("div", {
|
|
862
1092
|
className: "skippr:flex skippr:justify-center skippr:gap-1.5",
|
|
863
|
-
children: digits.map((digit, index2) => /* @__PURE__ */
|
|
1093
|
+
children: digits.map((digit, index2) => /* @__PURE__ */ jsx4("input", {
|
|
864
1094
|
ref: (el) => {
|
|
865
1095
|
inputRefs.current[index2] = el;
|
|
866
1096
|
},
|
|
@@ -875,29 +1105,29 @@ function OtpStep({ email, onSubmit, onResend, onBack, error, isSubmitting }) {
|
|
|
875
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"
|
|
876
1106
|
}, DIGIT_KEYS[index2]))
|
|
877
1107
|
}),
|
|
878
|
-
error && /* @__PURE__ */
|
|
1108
|
+
error && /* @__PURE__ */ jsx4("p", {
|
|
879
1109
|
className: "skippr:text-xs skippr:text-center skippr:text-destructive",
|
|
880
1110
|
children: error
|
|
881
1111
|
}),
|
|
882
|
-
/* @__PURE__ */
|
|
1112
|
+
/* @__PURE__ */ jsx4(Button, {
|
|
883
1113
|
type: "submit",
|
|
884
1114
|
disabled: isSubmitting || digits.join("").length !== OTP_LENGTH,
|
|
885
1115
|
className: "skippr:w-full",
|
|
886
|
-
children: isSubmitting ? /* @__PURE__ */
|
|
1116
|
+
children: isSubmitting ? /* @__PURE__ */ jsx4(LoaderCircle, {
|
|
887
1117
|
className: "skippr:size-4 skippr:animate-spin"
|
|
888
1118
|
}) : "Verify"
|
|
889
1119
|
}),
|
|
890
|
-
/* @__PURE__ */
|
|
1120
|
+
/* @__PURE__ */ jsxs3("div", {
|
|
891
1121
|
className: "skippr:flex skippr:items-center skippr:justify-between skippr:text-xs",
|
|
892
1122
|
children: [
|
|
893
|
-
/* @__PURE__ */
|
|
1123
|
+
/* @__PURE__ */ jsx4("button", {
|
|
894
1124
|
type: "button",
|
|
895
1125
|
onClick: onBack,
|
|
896
1126
|
disabled: isSubmitting,
|
|
897
1127
|
className: "skippr:text-muted-foreground hover:skippr:text-foreground skippr:transition-colors disabled:skippr:opacity-50",
|
|
898
1128
|
children: "Change email"
|
|
899
1129
|
}),
|
|
900
|
-
/* @__PURE__ */
|
|
1130
|
+
/* @__PURE__ */ jsx4("button", {
|
|
901
1131
|
type: "button",
|
|
902
1132
|
onClick: handleResend,
|
|
903
1133
|
disabled: isSubmitting || resendCooldown > 0,
|
|
@@ -913,9 +1143,9 @@ function OtpStep({ email, onSubmit, onResend, onBack, error, isSubmitting }) {
|
|
|
913
1143
|
}
|
|
914
1144
|
|
|
915
1145
|
// src/components/MeetingControls.tsx
|
|
916
|
-
import { useLocalParticipant as
|
|
917
|
-
import { ScreenSharePresets } from "livekit-client";
|
|
918
|
-
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";
|
|
919
1149
|
|
|
920
1150
|
// src/lib/format.ts
|
|
921
1151
|
function formatTime(seconds) {
|
|
@@ -929,12 +1159,12 @@ function parseNumber(s) {
|
|
|
929
1159
|
}
|
|
930
1160
|
|
|
931
1161
|
// src/components/SessionWarningBanner.tsx
|
|
932
|
-
import { jsx as
|
|
1162
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
933
1163
|
var SESSION_WARNING_THRESHOLD_SECS = 60;
|
|
934
1164
|
function SessionWarningBanner({ remaining }) {
|
|
935
1165
|
if (remaining === null || remaining <= 0 || remaining > SESSION_WARNING_THRESHOLD_SECS)
|
|
936
1166
|
return null;
|
|
937
|
-
return /* @__PURE__ */
|
|
1167
|
+
return /* @__PURE__ */ jsx5("div", {
|
|
938
1168
|
"data-testid": "session-warning-banner",
|
|
939
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",
|
|
940
1170
|
children: "Session ending soon"
|
|
@@ -942,15 +1172,15 @@ function SessionWarningBanner({ remaining }) {
|
|
|
942
1172
|
}
|
|
943
1173
|
|
|
944
1174
|
// src/components/MeetingControls.tsx
|
|
945
|
-
import { jsx as
|
|
1175
|
+
import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
946
1176
|
function MeetingControls({ onHangUp }) {
|
|
947
1177
|
const maxCallDuration = useAgentState("maxCallDuration", parseNumber, null);
|
|
948
|
-
const { localParticipant } =
|
|
1178
|
+
const { localParticipant } = useLocalParticipant4();
|
|
949
1179
|
const isMuted = !localParticipant.isMicrophoneEnabled;
|
|
950
1180
|
const isScreenSharing = localParticipant.isScreenShareEnabled;
|
|
951
1181
|
const endTimeRef = useRef2(null);
|
|
952
1182
|
const [remaining, setRemaining] = useState5(null);
|
|
953
|
-
|
|
1183
|
+
useEffect5(() => {
|
|
954
1184
|
if (maxCallDuration === null || endTimeRef.current !== null)
|
|
955
1185
|
return;
|
|
956
1186
|
endTimeRef.current = Date.now() + maxCallDuration * 1000;
|
|
@@ -962,72 +1192,72 @@ function MeetingControls({ onHangUp }) {
|
|
|
962
1192
|
const id = setInterval(tick, 1000);
|
|
963
1193
|
return () => clearInterval(id);
|
|
964
1194
|
}, [maxCallDuration]);
|
|
965
|
-
const toggleMute =
|
|
1195
|
+
const toggleMute = useCallback7(async () => {
|
|
966
1196
|
try {
|
|
967
1197
|
await localParticipant.setMicrophoneEnabled(isMuted);
|
|
968
1198
|
} catch (e) {
|
|
969
1199
|
console.error("Failed to toggle microphone:", e);
|
|
970
1200
|
}
|
|
971
1201
|
}, [localParticipant, isMuted]);
|
|
972
|
-
const toggleScreenShare =
|
|
1202
|
+
const toggleScreenShare = useCallback7(async () => {
|
|
973
1203
|
try {
|
|
974
1204
|
await localParticipant.setScreenShareEnabled(!isScreenSharing, {
|
|
975
1205
|
video: { displaySurface: "browser" },
|
|
976
|
-
resolution:
|
|
1206
|
+
resolution: ScreenSharePresets2.h720fps30.resolution,
|
|
977
1207
|
contentHint: "detail"
|
|
978
1208
|
});
|
|
979
1209
|
} catch (e) {
|
|
980
1210
|
console.error("Failed to toggle screen share:", e);
|
|
981
1211
|
}
|
|
982
1212
|
}, [localParticipant, isScreenSharing]);
|
|
983
|
-
|
|
1213
|
+
useEffect5(() => {
|
|
984
1214
|
toggleMute().then(() => toggleScreenShare());
|
|
985
1215
|
}, []);
|
|
986
|
-
return /* @__PURE__ */
|
|
1216
|
+
return /* @__PURE__ */ jsxs4("div", {
|
|
987
1217
|
children: [
|
|
988
|
-
/* @__PURE__ */
|
|
1218
|
+
/* @__PURE__ */ jsx6(SessionWarningBanner, {
|
|
989
1219
|
remaining
|
|
990
1220
|
}),
|
|
991
|
-
/* @__PURE__ */
|
|
1221
|
+
/* @__PURE__ */ jsxs4("div", {
|
|
992
1222
|
className: "skippr:flex skippr:items-center skippr:justify-between skippr:border-b skippr:px-4 skippr:py-3",
|
|
993
1223
|
children: [
|
|
994
|
-
/* @__PURE__ */
|
|
1224
|
+
/* @__PURE__ */ jsxs4("div", {
|
|
995
1225
|
className: "skippr:flex skippr:items-center skippr:gap-2",
|
|
996
1226
|
children: [
|
|
997
|
-
/* @__PURE__ */
|
|
1227
|
+
/* @__PURE__ */ jsx6(Button, {
|
|
998
1228
|
size: "icon-sm",
|
|
999
1229
|
variant: isMuted ? "destructive" : "outline",
|
|
1000
1230
|
onClick: toggleMute,
|
|
1001
1231
|
"aria-label": isMuted ? "Unmute" : "Mute",
|
|
1002
|
-
children: isMuted ? /* @__PURE__ */
|
|
1232
|
+
children: isMuted ? /* @__PURE__ */ jsx6(MicOff, {
|
|
1003
1233
|
className: "skippr:size-4"
|
|
1004
|
-
}) : /* @__PURE__ */
|
|
1234
|
+
}) : /* @__PURE__ */ jsx6(Mic, {
|
|
1005
1235
|
className: "skippr:size-4"
|
|
1006
1236
|
})
|
|
1007
1237
|
}),
|
|
1008
|
-
/* @__PURE__ */
|
|
1238
|
+
/* @__PURE__ */ jsx6(Button, {
|
|
1009
1239
|
size: "icon-sm",
|
|
1010
|
-
variant: isScreenSharing ? "
|
|
1240
|
+
variant: isScreenSharing ? "outline" : "destructive",
|
|
1011
1241
|
onClick: toggleScreenShare,
|
|
1012
1242
|
"aria-label": isScreenSharing ? "Stop sharing" : "Share screen",
|
|
1013
|
-
children: isScreenSharing ? /* @__PURE__ */
|
|
1243
|
+
children: isScreenSharing ? /* @__PURE__ */ jsx6(MonitorOff, {
|
|
1014
1244
|
className: "skippr:size-4"
|
|
1015
|
-
}) : /* @__PURE__ */
|
|
1245
|
+
}) : /* @__PURE__ */ jsx6(Monitor, {
|
|
1016
1246
|
className: "skippr:size-4"
|
|
1017
1247
|
})
|
|
1018
1248
|
})
|
|
1019
1249
|
]
|
|
1020
1250
|
}),
|
|
1021
|
-
remaining !== null && /* @__PURE__ */
|
|
1251
|
+
remaining !== null && /* @__PURE__ */ jsx6("span", {
|
|
1022
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"),
|
|
1023
1253
|
children: formatTime(remaining)
|
|
1024
1254
|
}),
|
|
1025
|
-
/* @__PURE__ */
|
|
1255
|
+
/* @__PURE__ */ jsx6(Button, {
|
|
1026
1256
|
size: "icon-sm",
|
|
1027
1257
|
variant: "destructive",
|
|
1028
1258
|
onClick: onHangUp,
|
|
1029
1259
|
"aria-label": "Hang up",
|
|
1030
|
-
children: /* @__PURE__ */
|
|
1260
|
+
children: /* @__PURE__ */ jsx6(PhoneOff, {
|
|
1031
1261
|
className: "skippr:size-4"
|
|
1032
1262
|
})
|
|
1033
1263
|
})
|
|
@@ -1038,11 +1268,11 @@ function MeetingControls({ onHangUp }) {
|
|
|
1038
1268
|
}
|
|
1039
1269
|
|
|
1040
1270
|
// src/components/MessageList.tsx
|
|
1041
|
-
import { useEffect as
|
|
1271
|
+
import { useEffect as useEffect6, useRef as useRef3 } from "react";
|
|
1042
1272
|
|
|
1043
1273
|
// src/components/ChatInput.tsx
|
|
1044
1274
|
import { useState as useState6 } from "react";
|
|
1045
|
-
import { jsx as
|
|
1275
|
+
import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1046
1276
|
function ChatInput({ sendChatMessage, isSendingChat }) {
|
|
1047
1277
|
const [inputText, setInputText] = useState6("");
|
|
1048
1278
|
const canSend = inputText.trim().length > 0 && !isSendingChat;
|
|
@@ -1054,11 +1284,11 @@ function ChatInput({ sendChatMessage, isSendingChat }) {
|
|
|
1054
1284
|
setInputText("");
|
|
1055
1285
|
sendChatMessage(text).catch(() => setInputText(text));
|
|
1056
1286
|
}
|
|
1057
|
-
return /* @__PURE__ */
|
|
1287
|
+
return /* @__PURE__ */ jsxs5("form", {
|
|
1058
1288
|
onSubmit: handleSubmit,
|
|
1059
1289
|
className: "skippr:flex skippr:items-center skippr:gap-2 skippr:border-t skippr:border-border skippr:px-3 skippr:py-2",
|
|
1060
1290
|
children: [
|
|
1061
|
-
/* @__PURE__ */
|
|
1291
|
+
/* @__PURE__ */ jsx7("input", {
|
|
1062
1292
|
type: "text",
|
|
1063
1293
|
value: inputText,
|
|
1064
1294
|
onChange: (e) => setInputText(e.target.value),
|
|
@@ -1066,12 +1296,12 @@ function ChatInput({ sendChatMessage, isSendingChat }) {
|
|
|
1066
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"),
|
|
1067
1297
|
disabled: isSendingChat
|
|
1068
1298
|
}),
|
|
1069
|
-
/* @__PURE__ */
|
|
1299
|
+
/* @__PURE__ */ jsx7("button", {
|
|
1070
1300
|
type: "submit",
|
|
1071
1301
|
disabled: !canSend,
|
|
1072
1302
|
"aria-label": "Send message",
|
|
1073
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"),
|
|
1074
|
-
children: /* @__PURE__ */
|
|
1304
|
+
children: /* @__PURE__ */ jsx7(SendHorizontal, {
|
|
1075
1305
|
className: "skippr:size-4"
|
|
1076
1306
|
})
|
|
1077
1307
|
})
|
|
@@ -1080,12 +1310,12 @@ function ChatInput({ sendChatMessage, isSendingChat }) {
|
|
|
1080
1310
|
}
|
|
1081
1311
|
|
|
1082
1312
|
// src/components/ChatMessage.tsx
|
|
1083
|
-
import { jsx as
|
|
1313
|
+
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
1084
1314
|
function ChatMessage({ message }) {
|
|
1085
1315
|
const isUser = message.role === "user";
|
|
1086
|
-
return /* @__PURE__ */
|
|
1316
|
+
return /* @__PURE__ */ jsx8("div", {
|
|
1087
1317
|
className: cn("skippr:flex skippr:w-full skippr:px-4 skippr:py-1", isUser ? "skippr:justify-end" : "skippr:justify-start"),
|
|
1088
|
-
children: /* @__PURE__ */
|
|
1318
|
+
children: /* @__PURE__ */ jsx8("div", {
|
|
1089
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"),
|
|
1090
1320
|
children: message.content
|
|
1091
1321
|
})
|
|
@@ -1093,20 +1323,20 @@ function ChatMessage({ message }) {
|
|
|
1093
1323
|
}
|
|
1094
1324
|
|
|
1095
1325
|
// src/components/TypingIndicator.tsx
|
|
1096
|
-
import { jsx as
|
|
1326
|
+
import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1097
1327
|
function TypingIndicator() {
|
|
1098
|
-
return /* @__PURE__ */
|
|
1328
|
+
return /* @__PURE__ */ jsx9("div", {
|
|
1099
1329
|
className: "skippr:flex skippr:items-center skippr:gap-1 skippr:px-4 skippr:py-3",
|
|
1100
|
-
children: /* @__PURE__ */
|
|
1330
|
+
children: /* @__PURE__ */ jsxs6("div", {
|
|
1101
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",
|
|
1102
1332
|
children: [
|
|
1103
|
-
/* @__PURE__ */
|
|
1333
|
+
/* @__PURE__ */ jsx9("span", {
|
|
1104
1334
|
className: "skippr:size-1.5 skippr:animate-bounce skippr:rounded-full skippr:bg-muted-foreground/60 skippr:[animation-delay:0ms]"
|
|
1105
1335
|
}),
|
|
1106
|
-
/* @__PURE__ */
|
|
1336
|
+
/* @__PURE__ */ jsx9("span", {
|
|
1107
1337
|
className: "skippr:size-1.5 skippr:animate-bounce skippr:rounded-full skippr:bg-muted-foreground/60 skippr:[animation-delay:150ms]"
|
|
1108
1338
|
}),
|
|
1109
|
-
/* @__PURE__ */
|
|
1339
|
+
/* @__PURE__ */ jsx9("span", {
|
|
1110
1340
|
className: "skippr:size-1.5 skippr:animate-bounce skippr:rounded-full skippr:bg-muted-foreground/60 skippr:[animation-delay:300ms]"
|
|
1111
1341
|
})
|
|
1112
1342
|
]
|
|
@@ -1115,7 +1345,7 @@ function TypingIndicator() {
|
|
|
1115
1345
|
}
|
|
1116
1346
|
|
|
1117
1347
|
// src/components/MessageList.tsx
|
|
1118
|
-
import { jsx as
|
|
1348
|
+
import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1119
1349
|
function MessageList({
|
|
1120
1350
|
messages,
|
|
1121
1351
|
isStreaming,
|
|
@@ -1124,29 +1354,29 @@ function MessageList({
|
|
|
1124
1354
|
}) {
|
|
1125
1355
|
const scrollRef = useRef3(null);
|
|
1126
1356
|
const lastMessage = messages.length > 0 ? messages[messages.length - 1] : undefined;
|
|
1127
|
-
|
|
1357
|
+
useEffect6(() => {
|
|
1128
1358
|
scrollRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
1129
1359
|
}, [messages.length, lastMessage?.content]);
|
|
1130
1360
|
const showTyping = isStreaming && lastMessage?.role === "assistant" && lastMessage.content === "";
|
|
1131
|
-
return /* @__PURE__ */
|
|
1361
|
+
return /* @__PURE__ */ jsxs7("div", {
|
|
1132
1362
|
className: "skippr:flex skippr:min-h-0 skippr:flex-1 skippr:flex-col",
|
|
1133
1363
|
children: [
|
|
1134
|
-
/* @__PURE__ */
|
|
1364
|
+
/* @__PURE__ */ jsx10("div", {
|
|
1135
1365
|
className: "skippr:min-h-0 skippr:flex-1 skippr:overflow-y-auto",
|
|
1136
|
-
children: /* @__PURE__ */
|
|
1366
|
+
children: /* @__PURE__ */ jsxs7("div", {
|
|
1137
1367
|
className: "skippr:flex skippr:flex-col skippr:gap-1 skippr:py-3",
|
|
1138
1368
|
children: [
|
|
1139
|
-
messages.map((message) => /* @__PURE__ */
|
|
1369
|
+
messages.map((message) => /* @__PURE__ */ jsx10(ChatMessage, {
|
|
1140
1370
|
message
|
|
1141
1371
|
}, message.id)),
|
|
1142
|
-
showTyping && /* @__PURE__ */
|
|
1143
|
-
/* @__PURE__ */
|
|
1372
|
+
showTyping && /* @__PURE__ */ jsx10(TypingIndicator, {}),
|
|
1373
|
+
/* @__PURE__ */ jsx10("div", {
|
|
1144
1374
|
ref: scrollRef
|
|
1145
1375
|
})
|
|
1146
1376
|
]
|
|
1147
1377
|
})
|
|
1148
1378
|
}),
|
|
1149
|
-
/* @__PURE__ */
|
|
1379
|
+
/* @__PURE__ */ jsx10(ChatInput, {
|
|
1150
1380
|
sendChatMessage,
|
|
1151
1381
|
isSendingChat
|
|
1152
1382
|
})
|
|
@@ -1155,30 +1385,30 @@ function MessageList({
|
|
|
1155
1385
|
}
|
|
1156
1386
|
|
|
1157
1387
|
// src/components/QuickActions.tsx
|
|
1158
|
-
import { jsx as
|
|
1388
|
+
import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1159
1389
|
function QuickActions({ onStartSession, isStarting, error }) {
|
|
1160
|
-
return /* @__PURE__ */
|
|
1390
|
+
return /* @__PURE__ */ jsxs8("div", {
|
|
1161
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",
|
|
1162
1392
|
children: [
|
|
1163
|
-
/* @__PURE__ */
|
|
1393
|
+
/* @__PURE__ */ jsx11("p", {
|
|
1164
1394
|
className: "skippr:mb-1 skippr:text-sm skippr:text-muted-foreground",
|
|
1165
1395
|
children: "How can I help you today?"
|
|
1166
1396
|
}),
|
|
1167
|
-
/* @__PURE__ */
|
|
1397
|
+
/* @__PURE__ */ jsxs8(Button, {
|
|
1168
1398
|
variant: "outline",
|
|
1169
1399
|
className: "skippr:h-auto skippr:flex-col skippr:gap-1.5 skippr:whitespace-normal skippr:py-3 skippr:text-xs",
|
|
1170
1400
|
onClick: onStartSession,
|
|
1171
1401
|
disabled: isStarting,
|
|
1172
1402
|
children: [
|
|
1173
|
-
isStarting ? /* @__PURE__ */
|
|
1403
|
+
isStarting ? /* @__PURE__ */ jsx11(LoaderCircle, {
|
|
1174
1404
|
className: "skippr:size-4 skippr:animate-spin skippr:text-primary"
|
|
1175
|
-
}) : /* @__PURE__ */
|
|
1405
|
+
}) : /* @__PURE__ */ jsx11(MessageCircleQuestionMark, {
|
|
1176
1406
|
className: "skippr:size-4 skippr:text-primary"
|
|
1177
1407
|
}),
|
|
1178
1408
|
isStarting ? "Starting..." : "Start Session"
|
|
1179
1409
|
]
|
|
1180
1410
|
}),
|
|
1181
|
-
error && /* @__PURE__ */
|
|
1411
|
+
error && /* @__PURE__ */ jsx11("p", {
|
|
1182
1412
|
className: "skippr:text-xs skippr:text-destructive",
|
|
1183
1413
|
children: error
|
|
1184
1414
|
})
|
|
@@ -1187,52 +1417,52 @@ function QuickActions({ onStartSession, isStarting, error }) {
|
|
|
1187
1417
|
}
|
|
1188
1418
|
|
|
1189
1419
|
// src/components/SessionAgenda.tsx
|
|
1190
|
-
import { jsx as
|
|
1420
|
+
import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1191
1421
|
function SessionAgenda({ phases, questions = [] }) {
|
|
1192
1422
|
if (phases.length === 0) {
|
|
1193
|
-
return /* @__PURE__ */
|
|
1423
|
+
return /* @__PURE__ */ jsxs9("div", {
|
|
1194
1424
|
className: "skippr:flex skippr:flex-col skippr:gap-3 skippr:p-4",
|
|
1195
1425
|
children: [
|
|
1196
|
-
/* @__PURE__ */
|
|
1426
|
+
/* @__PURE__ */ jsx12("h3", {
|
|
1197
1427
|
className: "skippr:text-sm skippr:font-semibold",
|
|
1198
1428
|
children: "Agenda"
|
|
1199
1429
|
}),
|
|
1200
|
-
/* @__PURE__ */
|
|
1430
|
+
/* @__PURE__ */ jsx12("p", {
|
|
1201
1431
|
className: "skippr:text-xs skippr:text-muted-foreground",
|
|
1202
1432
|
children: "Waiting for session..."
|
|
1203
1433
|
})
|
|
1204
1434
|
]
|
|
1205
1435
|
});
|
|
1206
1436
|
}
|
|
1207
|
-
return /* @__PURE__ */
|
|
1437
|
+
return /* @__PURE__ */ jsxs9("div", {
|
|
1208
1438
|
className: "skippr:flex skippr:flex-col skippr:gap-3 skippr:p-4",
|
|
1209
1439
|
children: [
|
|
1210
|
-
/* @__PURE__ */
|
|
1440
|
+
/* @__PURE__ */ jsx12("h3", {
|
|
1211
1441
|
className: "skippr:text-sm skippr:font-semibold",
|
|
1212
1442
|
children: "Agenda"
|
|
1213
1443
|
}),
|
|
1214
|
-
/* @__PURE__ */
|
|
1444
|
+
/* @__PURE__ */ jsx12("ul", {
|
|
1215
1445
|
className: "skippr:flex skippr:flex-col skippr:gap-2",
|
|
1216
1446
|
children: phases.map((phase) => {
|
|
1217
1447
|
const phaseQuestions = questions.filter((q) => q.phaseName === phase.name);
|
|
1218
1448
|
const answeredCount = phaseQuestions.filter((q) => q.status === "answered").length;
|
|
1219
1449
|
const totalCount = phaseQuestions.length;
|
|
1220
|
-
return /* @__PURE__ */
|
|
1450
|
+
return /* @__PURE__ */ jsxs9("li", {
|
|
1221
1451
|
className: "skippr:flex skippr:flex-col skippr:gap-0.5",
|
|
1222
1452
|
children: [
|
|
1223
|
-
/* @__PURE__ */
|
|
1453
|
+
/* @__PURE__ */ jsxs9("div", {
|
|
1224
1454
|
className: "skippr:flex skippr:items-center skippr:gap-2 skippr:text-sm",
|
|
1225
1455
|
children: [
|
|
1226
|
-
/* @__PURE__ */
|
|
1456
|
+
/* @__PURE__ */ jsx12(PhaseIcon, {
|
|
1227
1457
|
status: phase.status
|
|
1228
1458
|
}),
|
|
1229
|
-
/* @__PURE__ */
|
|
1459
|
+
/* @__PURE__ */ jsx12("span", {
|
|
1230
1460
|
className: cn(phase.status === "completed" && "skippr:text-muted-foreground skippr:line-through", phase.status === "active" && "skippr:font-medium skippr:text-primary"),
|
|
1231
1461
|
children: phase.name
|
|
1232
1462
|
})
|
|
1233
1463
|
]
|
|
1234
1464
|
}),
|
|
1235
|
-
totalCount > 0 && /* @__PURE__ */
|
|
1465
|
+
totalCount > 0 && /* @__PURE__ */ jsxs9("span", {
|
|
1236
1466
|
className: "skippr:ml-6 skippr:text-xs skippr:text-muted-foreground",
|
|
1237
1467
|
children: [
|
|
1238
1468
|
answeredCount,
|
|
@@ -1250,35 +1480,110 @@ function SessionAgenda({ phases, questions = [] }) {
|
|
|
1250
1480
|
}
|
|
1251
1481
|
function PhaseIcon({ status }) {
|
|
1252
1482
|
if (status === "completed") {
|
|
1253
|
-
return /* @__PURE__ */
|
|
1483
|
+
return /* @__PURE__ */ jsx12("div", {
|
|
1254
1484
|
className: "skippr:flex skippr:size-4 skippr:shrink-0 skippr:items-center skippr:justify-center skippr:rounded-full skippr:bg-primary",
|
|
1255
|
-
children: /* @__PURE__ */
|
|
1485
|
+
children: /* @__PURE__ */ jsx12(Check, {
|
|
1256
1486
|
className: "skippr:size-2.5 skippr:text-primary-foreground",
|
|
1257
1487
|
strokeWidth: 3
|
|
1258
1488
|
})
|
|
1259
1489
|
});
|
|
1260
1490
|
}
|
|
1261
1491
|
if (status === "active") {
|
|
1262
|
-
return /* @__PURE__ */
|
|
1492
|
+
return /* @__PURE__ */ jsx12(LoaderCircle, {
|
|
1263
1493
|
className: "skippr:size-4 skippr:shrink-0 skippr:text-primary skippr:animate-spin"
|
|
1264
1494
|
});
|
|
1265
1495
|
}
|
|
1266
|
-
return /* @__PURE__ */
|
|
1496
|
+
return /* @__PURE__ */ jsx12(Circle, {
|
|
1267
1497
|
className: "skippr:size-4 skippr:shrink-0 skippr:text-muted-foreground"
|
|
1268
1498
|
});
|
|
1269
1499
|
}
|
|
1270
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
|
+
|
|
1271
1575
|
// src/components/Sidebar.tsx
|
|
1272
|
-
import { jsx as
|
|
1576
|
+
import { jsx as jsx14, jsxs as jsxs11, Fragment as Fragment2 } from "react/jsx-runtime";
|
|
1273
1577
|
function Sidebar() {
|
|
1274
1578
|
const {
|
|
1579
|
+
variant,
|
|
1275
1580
|
isConnected,
|
|
1276
1581
|
isStarting,
|
|
1277
1582
|
error,
|
|
1278
1583
|
startSession,
|
|
1279
1584
|
disconnect,
|
|
1280
1585
|
isPanelOpen,
|
|
1281
|
-
|
|
1586
|
+
position,
|
|
1282
1587
|
isAuthenticated,
|
|
1283
1588
|
isValidating,
|
|
1284
1589
|
authError,
|
|
@@ -1286,42 +1591,53 @@ function Sidebar() {
|
|
|
1286
1591
|
verifyOtp,
|
|
1287
1592
|
isAuthSubmitting
|
|
1288
1593
|
} = useLiveAgent();
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1594
|
+
const [view, setView] = useState7("main");
|
|
1595
|
+
const isFloating = variant === "floating";
|
|
1596
|
+
const isSidebar = variant === "sidebar";
|
|
1597
|
+
useEffect7(() => {
|
|
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` : "";
|
|
1294
1605
|
return () => {
|
|
1295
1606
|
document.body.style.marginRight = "";
|
|
1607
|
+
document.body.style.marginLeft = "";
|
|
1296
1608
|
document.body.style.transition = "";
|
|
1297
1609
|
};
|
|
1298
|
-
}, []);
|
|
1299
|
-
return /* @__PURE__ */
|
|
1300
|
-
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"),
|
|
1301
1613
|
style: { width: isPanelOpen ? SIDEBAR_WIDTH : undefined },
|
|
1302
|
-
children:
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
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
|
|
1313
1638
|
})
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
isStarting,
|
|
1317
|
-
error
|
|
1318
|
-
}) : /* @__PURE__ */ jsx12(LoginFlow, {
|
|
1319
|
-
requestOtp,
|
|
1320
|
-
verifyOtp,
|
|
1321
|
-
error: authError,
|
|
1322
|
-
isSubmitting: isAuthSubmitting
|
|
1323
|
-
})
|
|
1324
|
-
]
|
|
1639
|
+
]
|
|
1640
|
+
})
|
|
1325
1641
|
});
|
|
1326
1642
|
}
|
|
1327
1643
|
function ConnectedContent({ onDisconnect }) {
|
|
@@ -1331,33 +1647,33 @@ function ConnectedContent({ onDisconnect }) {
|
|
|
1331
1647
|
const { phases } = usePhaseUpdates();
|
|
1332
1648
|
const { questions } = useQuestionUpdates();
|
|
1333
1649
|
if (!isConnected) {
|
|
1334
|
-
return /* @__PURE__ */
|
|
1650
|
+
return /* @__PURE__ */ jsx14("div", {
|
|
1335
1651
|
className: "skippr:flex skippr:flex-1 skippr:items-center skippr:justify-center",
|
|
1336
|
-
children: /* @__PURE__ */
|
|
1652
|
+
children: /* @__PURE__ */ jsx14("p", {
|
|
1337
1653
|
className: "skippr:text-sm skippr:text-muted-foreground",
|
|
1338
1654
|
children: "Connecting..."
|
|
1339
1655
|
})
|
|
1340
1656
|
});
|
|
1341
1657
|
}
|
|
1342
1658
|
const isAgentSpeaking = agentState === "speaking";
|
|
1343
|
-
return /* @__PURE__ */
|
|
1659
|
+
return /* @__PURE__ */ jsxs11(Fragment2, {
|
|
1344
1660
|
children: [
|
|
1345
|
-
/* @__PURE__ */
|
|
1661
|
+
/* @__PURE__ */ jsx14(MeetingControls, {
|
|
1346
1662
|
onHangUp: onDisconnect
|
|
1347
1663
|
}),
|
|
1348
|
-
/* @__PURE__ */
|
|
1664
|
+
/* @__PURE__ */ jsxs11("div", {
|
|
1349
1665
|
className: "skippr:flex skippr:min-h-0 skippr:flex-1",
|
|
1350
1666
|
children: [
|
|
1351
|
-
/* @__PURE__ */
|
|
1352
|
-
className: "skippr:w-[
|
|
1353
|
-
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, {
|
|
1354
1670
|
phases,
|
|
1355
1671
|
questions
|
|
1356
1672
|
})
|
|
1357
1673
|
}),
|
|
1358
|
-
/* @__PURE__ */
|
|
1674
|
+
/* @__PURE__ */ jsx14("div", {
|
|
1359
1675
|
className: "skippr:flex skippr:min-w-0 skippr:flex-1 skippr:flex-col",
|
|
1360
|
-
children: /* @__PURE__ */
|
|
1676
|
+
children: /* @__PURE__ */ jsx14(MessageList, {
|
|
1361
1677
|
messages: allMessages,
|
|
1362
1678
|
isStreaming: isAgentSpeaking,
|
|
1363
1679
|
sendChatMessage,
|
|
@@ -1371,32 +1687,34 @@ function ConnectedContent({ onDisconnect }) {
|
|
|
1371
1687
|
}
|
|
1372
1688
|
|
|
1373
1689
|
// src/components/SidebarTrigger.tsx
|
|
1374
|
-
import { jsx as
|
|
1375
|
-
var TRIGGER_GAP = 16;
|
|
1376
|
-
var TRIGGER_DEFAULT_RIGHT = 24;
|
|
1690
|
+
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
1377
1691
|
function SidebarTrigger() {
|
|
1378
|
-
const { isPanelOpen, togglePanel } = useLiveAgent();
|
|
1379
|
-
|
|
1692
|
+
const { isPanelOpen, togglePanel, position, isMinimized, isConnected } = useLiveAgent();
|
|
1693
|
+
if (isMinimized && isConnected)
|
|
1694
|
+
return null;
|
|
1695
|
+
return /* @__PURE__ */ jsx15(Button, {
|
|
1380
1696
|
size: "icon-lg",
|
|
1381
1697
|
onClick: togglePanel,
|
|
1382
|
-
className: "skippr:fixed skippr:bottom-6 skippr:z-[9998] skippr:size-14 skippr:rounded-full skippr:shadow-lg skippr:transition-all skippr:duration-300",
|
|
1383
|
-
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"),
|
|
1384
1699
|
title: isPanelOpen ? "Close chat" : "Chat with us",
|
|
1385
|
-
children: isPanelOpen ? /* @__PURE__ */
|
|
1700
|
+
children: isPanelOpen ? /* @__PURE__ */ jsx15(X, {
|
|
1386
1701
|
className: "skippr:size-6"
|
|
1387
|
-
}) : /* @__PURE__ */
|
|
1702
|
+
}) : /* @__PURE__ */ jsx15(MessageCircle, {
|
|
1388
1703
|
className: "skippr:size-6"
|
|
1389
1704
|
})
|
|
1390
1705
|
});
|
|
1391
1706
|
}
|
|
1392
1707
|
|
|
1393
1708
|
// src/components/LiveAgent.tsx
|
|
1394
|
-
import { jsx as
|
|
1709
|
+
import { jsx as jsx16, jsxs as jsxs12, Fragment as Fragment3 } from "react/jsx-runtime";
|
|
1395
1710
|
function LiveAgent({
|
|
1396
1711
|
agentId,
|
|
1397
1712
|
authToken: authTokenProp,
|
|
1398
1713
|
appKey,
|
|
1399
1714
|
userToken,
|
|
1715
|
+
position = "right",
|
|
1716
|
+
variant = "floating",
|
|
1717
|
+
minimizable = true,
|
|
1400
1718
|
defaultOpen = false,
|
|
1401
1719
|
children
|
|
1402
1720
|
}) {
|
|
@@ -1408,12 +1726,45 @@ function LiveAgent({
|
|
|
1408
1726
|
appKey,
|
|
1409
1727
|
userToken
|
|
1410
1728
|
});
|
|
1411
|
-
const [isPanelOpen, setIsPanelOpen] =
|
|
1412
|
-
const
|
|
1413
|
-
const
|
|
1414
|
-
|
|
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]);
|
|
1415
1758
|
const isConnected = connection !== null;
|
|
1416
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]);
|
|
1417
1768
|
const ctx = useMemo4(() => ({
|
|
1418
1769
|
connection,
|
|
1419
1770
|
shouldConnect,
|
|
@@ -1426,6 +1777,13 @@ function LiveAgent({
|
|
|
1426
1777
|
openPanel,
|
|
1427
1778
|
closePanel,
|
|
1428
1779
|
togglePanel,
|
|
1780
|
+
variant,
|
|
1781
|
+
position: currentPosition,
|
|
1782
|
+
setPosition: setPositionWithPersist,
|
|
1783
|
+
minimizable,
|
|
1784
|
+
isMinimized,
|
|
1785
|
+
expandPanel,
|
|
1786
|
+
minimizePanel,
|
|
1429
1787
|
isAuthenticated,
|
|
1430
1788
|
isValidating: auth.isValidating,
|
|
1431
1789
|
authError: auth.error,
|
|
@@ -1445,6 +1803,13 @@ function LiveAgent({
|
|
|
1445
1803
|
openPanel,
|
|
1446
1804
|
closePanel,
|
|
1447
1805
|
togglePanel,
|
|
1806
|
+
variant,
|
|
1807
|
+
currentPosition,
|
|
1808
|
+
setPositionWithPersist,
|
|
1809
|
+
minimizable,
|
|
1810
|
+
isMinimized,
|
|
1811
|
+
expandPanel,
|
|
1812
|
+
minimizePanel,
|
|
1448
1813
|
isAuthenticated,
|
|
1449
1814
|
auth.isValidating,
|
|
1450
1815
|
auth.error,
|
|
@@ -1453,17 +1818,18 @@ function LiveAgent({
|
|
|
1453
1818
|
auth.logout,
|
|
1454
1819
|
auth.isSubmitting
|
|
1455
1820
|
]);
|
|
1456
|
-
const widgetContent = /* @__PURE__ */
|
|
1821
|
+
const widgetContent = /* @__PURE__ */ jsxs12(Fragment3, {
|
|
1457
1822
|
children: [
|
|
1458
|
-
connection && /* @__PURE__ */
|
|
1459
|
-
/* @__PURE__ */
|
|
1460
|
-
/* @__PURE__ */
|
|
1823
|
+
connection && /* @__PURE__ */ jsx16(RoomAudioRenderer, {}),
|
|
1824
|
+
isMinimized && isConnected && /* @__PURE__ */ jsx16(MinimizedBubble, {}),
|
|
1825
|
+
/* @__PURE__ */ jsx16(SidebarTrigger, {}),
|
|
1826
|
+
/* @__PURE__ */ jsx16(Sidebar, {}),
|
|
1461
1827
|
children
|
|
1462
1828
|
]
|
|
1463
1829
|
});
|
|
1464
|
-
return /* @__PURE__ */
|
|
1830
|
+
return /* @__PURE__ */ jsx16(LiveAgentContext.Provider, {
|
|
1465
1831
|
value: ctx,
|
|
1466
|
-
children: connection ? /* @__PURE__ */
|
|
1832
|
+
children: connection ? /* @__PURE__ */ jsx16(LiveKitRoom, {
|
|
1467
1833
|
serverUrl: connection.livekitUrl,
|
|
1468
1834
|
token: connection.token,
|
|
1469
1835
|
connect: shouldConnect,
|