call-control-sdk 1.0.0 → 2.1.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/index.mjs ADDED
@@ -0,0 +1,1131 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
+
5
+ // src/lib/hooks/eventsTracker.ts
6
+ var EventTrackerSDK = class {
7
+ constructor() {
8
+ __publicField(this, "config", null);
9
+ __publicField(this, "ticketId", null);
10
+ __publicField(this, "baseUrl", "");
11
+ __publicField(this, "eventQueue", []);
12
+ __publicField(this, "isOnline", true);
13
+ __publicField(this, "retryQueue", []);
14
+ __publicField(this, "flushTimer", null);
15
+ }
16
+ /**
17
+ * Initialize the EventTracker SDK
18
+ * @param config Configuration object
19
+ */
20
+ async init(config) {
21
+ this.config = {
22
+ autoTrack: true,
23
+ retryAttempts: 3,
24
+ queueSize: 100,
25
+ flushInterval: 5e3,
26
+ ...config
27
+ };
28
+ this.baseUrl = config.baseUrl || (typeof window !== "undefined" ? window.location.origin : "");
29
+ this.setupNetworkDetection();
30
+ const ticket = await this.createTicket();
31
+ this.startPeriodicFlush();
32
+ console.log("EventTracker SDK initialized successfully");
33
+ return ticket;
34
+ }
35
+ /**
36
+ * Check if the SDK is initialized
37
+ */
38
+ isInitialized() {
39
+ return this.config !== null && this.ticketId !== null;
40
+ }
41
+ /**
42
+ * Get the current configuration
43
+ */
44
+ getConfig() {
45
+ return this.config;
46
+ }
47
+ /**
48
+ * Get the current ticket ID
49
+ */
50
+ getTicketId() {
51
+ return this.ticketId;
52
+ }
53
+ /**
54
+ * Create a new ticket
55
+ */
56
+ async createTicket() {
57
+ if (!this.config) {
58
+ throw new Error("EventTracker not initialized");
59
+ }
60
+ try {
61
+ const response = await this.makeRequest("/api/v1/et/init", {
62
+ method: "POST",
63
+ headers: {
64
+ "Content-Type": "application/json",
65
+ "X-API-Key": this.config.apiKey
66
+ },
67
+ body: JSON.stringify({
68
+ agentId: this.config.agentId,
69
+ sessionId: this.config.sessionId
70
+ })
71
+ });
72
+ if (!response.ok) {
73
+ throw new Error(
74
+ `Failed to initialize: ${response.status} ${response.statusText}`
75
+ );
76
+ }
77
+ const data = await response.json();
78
+ this.ticketId = data.ticketId;
79
+ if (this.config.autoTrack) {
80
+ this.setupAutoTracking();
81
+ }
82
+ return this.ticketId;
83
+ } catch (error) {
84
+ console.error("EventTracker initialization failed:", error);
85
+ throw error;
86
+ }
87
+ }
88
+ /**
89
+ * Log an event
90
+ * @param eventType The type of event
91
+ * @param eventData Optional event data
92
+ */
93
+ async logEvent(eventType, eventData) {
94
+ if (!this.config || !this.ticketId) {
95
+ console.warn("EventTracker not initialized, skipping event:", eventType);
96
+ return;
97
+ }
98
+ const event = {
99
+ eventType,
100
+ eventData,
101
+ timestamp: Date.now()
102
+ };
103
+ this.eventQueue.push(event);
104
+ if (this.eventQueue.length > (this.config.queueSize || 100)) {
105
+ this.eventQueue.shift();
106
+ }
107
+ if (this.isOnline) {
108
+ try {
109
+ await this.sendEvent(event);
110
+ } catch (error) {
111
+ console.warn("Failed to send event, will retry later:", error);
112
+ }
113
+ }
114
+ }
115
+ /**
116
+ * Send an event to the server
117
+ */
118
+ async sendEvent(event) {
119
+ if (!this.config || !this.ticketId) return;
120
+ try {
121
+ const response = await this.makeRequest("/api/v1/et/event", {
122
+ method: "POST",
123
+ headers: {
124
+ "Content-Type": "application/json",
125
+ "X-API-Key": this.config.apiKey
126
+ },
127
+ body: JSON.stringify({
128
+ ticketId: this.ticketId,
129
+ eventType: event.eventType,
130
+ eventData: event.eventData
131
+ })
132
+ });
133
+ if (!response.ok) {
134
+ throw new Error(
135
+ `Failed to log event: ${response.status} ${response.statusText}`
136
+ );
137
+ }
138
+ const index = this.eventQueue.findIndex(
139
+ (e) => e.timestamp === event.timestamp
140
+ );
141
+ if (index > -1) {
142
+ this.eventQueue.splice(index, 1);
143
+ }
144
+ } catch (error) {
145
+ console.error("Event logging failed:", error);
146
+ this.retryQueue.push(() => this.sendEvent(event));
147
+ }
148
+ }
149
+ /**
150
+ * Close the current ticket
151
+ */
152
+ async closeTicket() {
153
+ if (!this.config || !this.ticketId) {
154
+ throw new Error("EventTracker not initialized");
155
+ }
156
+ await this.flush();
157
+ try {
158
+ const response = await this.makeRequest("/api/v1/et/close", {
159
+ method: "POST",
160
+ headers: {
161
+ "Content-Type": "application/json",
162
+ "X-API-Key": this.config.apiKey
163
+ },
164
+ body: JSON.stringify({
165
+ ticketId: this.ticketId
166
+ })
167
+ });
168
+ if (!response.ok) {
169
+ throw new Error(
170
+ `Failed to close ticket: ${response.status} ${response.statusText}`
171
+ );
172
+ }
173
+ this.ticketId = null;
174
+ this.stopPeriodicFlush();
175
+ console.log("Ticket closed successfully");
176
+ } catch (error) {
177
+ console.error("Ticket close failed:", error);
178
+ throw error;
179
+ }
180
+ }
181
+ /**
182
+ * Flush all pending events
183
+ */
184
+ async flush() {
185
+ if (!this.isOnline || this.eventQueue.length === 0) return;
186
+ const eventsToFlush = [...this.eventQueue];
187
+ for (const event of eventsToFlush) {
188
+ await this.sendEvent(event);
189
+ }
190
+ const retryItems = [...this.retryQueue];
191
+ this.retryQueue = [];
192
+ for (const retryFn of retryItems) {
193
+ try {
194
+ await retryFn();
195
+ } catch (error) {
196
+ console.error("Retry failed:", error);
197
+ }
198
+ }
199
+ }
200
+ /**
201
+ * Make an HTTP request with retry logic
202
+ */
203
+ async makeRequest(url, options) {
204
+ const fullUrl = `${this.baseUrl}${url}`;
205
+ const maxRetries = this.config?.retryAttempts || 3;
206
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
207
+ try {
208
+ const response = await fetch(fullUrl, options);
209
+ return response;
210
+ } catch (error) {
211
+ if (attempt === maxRetries) {
212
+ throw error;
213
+ }
214
+ const delay = Math.min(1e3 * Math.pow(2, attempt - 1), 1e4);
215
+ await new Promise((resolve) => setTimeout(resolve, delay));
216
+ }
217
+ }
218
+ throw new Error("Max retries exceeded");
219
+ }
220
+ /**
221
+ * Set up automatic event tracking
222
+ */
223
+ setupAutoTracking() {
224
+ if (typeof window === "undefined" || !this.config?.autoTrack) return;
225
+ const autoTrackConfig = this.config.autoTrack === true ? {} : this.config.autoTrack;
226
+ if (autoTrackConfig.pageVisits !== false) {
227
+ this.logEvent("pageVisit", {
228
+ url: window.location.href,
229
+ title: document.title,
230
+ referrer: document.referrer,
231
+ userAgent: navigator.userAgent,
232
+ viewport: {
233
+ width: window.innerWidth,
234
+ height: window.innerHeight
235
+ },
236
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
237
+ }).catch((error) => console.warn("Failed to track page visit:", error));
238
+ }
239
+ if (autoTrackConfig.clicks !== false) {
240
+ document.addEventListener("click", (event) => {
241
+ const target = event.target;
242
+ if (target.tagName === "BUTTON" || target.tagName === "A" || target.onclick || target.getAttribute("role") === "button") {
243
+ this.logEvent("click", {
244
+ element: target.tagName,
245
+ text: target.textContent?.trim().substring(0, 100),
246
+ // Limit text length
247
+ href: target.getAttribute("href"),
248
+ id: target.id,
249
+ className: target.className,
250
+ role: target.getAttribute("role"),
251
+ position: {
252
+ x: event.clientX,
253
+ y: event.clientY
254
+ },
255
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
256
+ }).catch((error) => console.warn("Failed to track click:", error));
257
+ }
258
+ });
259
+ }
260
+ if (autoTrackConfig.forms !== false) {
261
+ document.addEventListener("submit", (event) => {
262
+ const target = event.target;
263
+ const formData = new FormData(target);
264
+ const formFields = {};
265
+ formData.forEach((value, key) => {
266
+ formFields[key] = value.toString();
267
+ });
268
+ this.logEvent("formSubmission", {
269
+ formId: target.id,
270
+ action: target.action,
271
+ method: target.method,
272
+ fields: Object.keys(formFields),
273
+ fieldCount: Object.keys(formFields).length,
274
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
275
+ }).catch(
276
+ (error) => console.warn("Failed to track form submission:", error)
277
+ );
278
+ });
279
+ }
280
+ if (autoTrackConfig.inputs !== false) {
281
+ let inputTimer;
282
+ document.addEventListener("input", (event) => {
283
+ const target = event.target;
284
+ if (target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.tagName === "SELECT") {
285
+ clearTimeout(inputTimer);
286
+ inputTimer = setTimeout(() => {
287
+ this.logEvent("fieldChange", {
288
+ element: target.tagName,
289
+ type: target.getAttribute("type"),
290
+ name: target.getAttribute("name"),
291
+ id: target.id,
292
+ valueLength: target.value?.length || 0,
293
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
294
+ }).catch(
295
+ (error) => console.warn("Failed to track field change:", error)
296
+ );
297
+ }, 1e3);
298
+ }
299
+ });
300
+ }
301
+ const sessionStartTime = Date.now();
302
+ window.addEventListener("beforeunload", () => {
303
+ const sessionDuration = Date.now() - sessionStartTime;
304
+ this.logEvent("pageUnload", {
305
+ url: window.location.href,
306
+ sessionDuration,
307
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
308
+ });
309
+ if (this.ticketId) {
310
+ navigator.sendBeacon(
311
+ `${this.baseUrl}/api/v1/et/close`,
312
+ JSON.stringify({
313
+ ticketId: this.ticketId
314
+ })
315
+ );
316
+ }
317
+ });
318
+ if (autoTrackConfig.visibility !== false) {
319
+ document.addEventListener("visibilitychange", () => {
320
+ this.logEvent("visibilityChange", {
321
+ hidden: document.hidden,
322
+ visibilityState: document.visibilityState,
323
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
324
+ });
325
+ });
326
+ }
327
+ if (autoTrackConfig.errors !== false) {
328
+ window.addEventListener("error", (event) => {
329
+ this.logEvent("jsError", {
330
+ message: event.message,
331
+ filename: event.filename,
332
+ lineno: event.lineno,
333
+ colno: event.colno,
334
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
335
+ });
336
+ });
337
+ window.addEventListener("unhandledrejection", (event) => {
338
+ this.logEvent("unhandledRejection", {
339
+ reason: event.reason?.toString(),
340
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
341
+ });
342
+ });
343
+ }
344
+ if (autoTrackConfig.performance !== false && typeof window.performance !== "undefined" && window.performance.navigation) {
345
+ window.addEventListener("load", () => {
346
+ setTimeout(() => {
347
+ const navigation = window.performance.navigation;
348
+ const timing = window.performance.timing;
349
+ this.logEvent("performanceMetrics", {
350
+ navigationTime: timing.navigationStart,
351
+ loadTime: timing.loadEventEnd - timing.navigationStart,
352
+ domReady: timing.domContentLoadedEventEnd - timing.navigationStart,
353
+ renderTime: timing.loadEventEnd - timing.domContentLoadedEventEnd,
354
+ navigationType: navigation.type,
355
+ redirectCount: navigation.redirectCount,
356
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
357
+ });
358
+ }, 1e3);
359
+ });
360
+ }
361
+ }
362
+ /**
363
+ * Set up network detection
364
+ */
365
+ setupNetworkDetection() {
366
+ if (typeof window === "undefined") return;
367
+ this.isOnline = navigator.onLine;
368
+ window.addEventListener("online", () => {
369
+ this.isOnline = true;
370
+ console.log("EventTracker: Back online, flushing queued events");
371
+ this.flush();
372
+ });
373
+ window.addEventListener("offline", () => {
374
+ this.isOnline = false;
375
+ console.log("EventTracker: Offline, queueing events");
376
+ });
377
+ }
378
+ /**
379
+ * Start periodic flush timer
380
+ */
381
+ startPeriodicFlush() {
382
+ if (this.flushTimer) {
383
+ clearInterval(this.flushTimer);
384
+ }
385
+ const interval = this.config?.flushInterval || 5e3;
386
+ this.flushTimer = setInterval(() => {
387
+ this.flush();
388
+ }, interval);
389
+ }
390
+ /**
391
+ * Stop periodic flush timer
392
+ */
393
+ stopPeriodicFlush() {
394
+ if (this.flushTimer) {
395
+ clearInterval(this.flushTimer);
396
+ this.flushTimer = null;
397
+ }
398
+ }
399
+ };
400
+ var eventTracker = new EventTrackerSDK();
401
+ if (typeof window !== "undefined") {
402
+ window.EventTracker = eventTracker;
403
+ }
404
+
405
+ // src/lib/hooks/sdk-state.ts
406
+ var SDKStateManager = class {
407
+ constructor() {
408
+ __publicField(this, "state");
409
+ __publicField(this, "listeners", []);
410
+ __publicField(this, "STORAGE_KEY", "call-control-sdk-state");
411
+ this.state = this.getInitialState();
412
+ this.loadFromStorage();
413
+ }
414
+ getInitialState() {
415
+ return {
416
+ apiKey: null,
417
+ isInitialized: false,
418
+ isHolding: false,
419
+ isMuted: false,
420
+ status: "idle",
421
+ callStartTime: null,
422
+ position: { x: 50, y: 50 },
423
+ callData: {
424
+ mobileNumber: "",
425
+ callReferenceId: "",
426
+ agentLoginId: ""
427
+ }
428
+ };
429
+ }
430
+ loadFromStorage() {
431
+ try {
432
+ const stored = localStorage.getItem(this.STORAGE_KEY);
433
+ if (stored) {
434
+ const parsedState = JSON.parse(stored);
435
+ this.state = {
436
+ ...this.state,
437
+ isHolding: parsedState.isHolding || false,
438
+ isMuted: parsedState.isMuted || false,
439
+ status: parsedState.status || "idle",
440
+ position: parsedState.position || { x: 50, y: 50 },
441
+ callStartTime: parsedState.callStartTime || null
442
+ };
443
+ }
444
+ } catch (error) {
445
+ console.warn("Failed to load SDK state from localStorage:", error);
446
+ }
447
+ }
448
+ saveToStorage() {
449
+ try {
450
+ const persistentState = {
451
+ isHolding: this.state.isHolding,
452
+ isMuted: this.state.isMuted,
453
+ status: this.state.status,
454
+ position: this.state.position,
455
+ callStartTime: this.state.callStartTime
456
+ };
457
+ localStorage.setItem(this.STORAGE_KEY, JSON.stringify(persistentState));
458
+ } catch (error) {
459
+ console.warn("Failed to save SDK state to localStorage:", error);
460
+ }
461
+ }
462
+ notifyListeners() {
463
+ this.listeners.forEach((listener) => listener());
464
+ }
465
+ initialize(apiKey) {
466
+ if (!apiKey || typeof apiKey !== "string" || apiKey.trim().length === 0) {
467
+ throw new Error("API key not available");
468
+ }
469
+ this.state.apiKey = apiKey;
470
+ this.state.isInitialized = true;
471
+ this.notifyListeners();
472
+ }
473
+ getState() {
474
+ return { ...this.state };
475
+ }
476
+ subscribe(listener) {
477
+ this.listeners.push(listener);
478
+ return () => {
479
+ const index = this.listeners.indexOf(listener);
480
+ if (index > -1) {
481
+ this.listeners.splice(index, 1);
482
+ }
483
+ };
484
+ }
485
+ setHolding(isHolding) {
486
+ this.state.isHolding = isHolding;
487
+ this.saveToStorage();
488
+ this.notifyListeners();
489
+ }
490
+ setMuted(isMuted) {
491
+ this.state.isMuted = isMuted;
492
+ this.saveToStorage();
493
+ this.notifyListeners();
494
+ }
495
+ setStatus(status) {
496
+ this.state.status = status;
497
+ this.saveToStorage();
498
+ this.notifyListeners();
499
+ }
500
+ setPosition(position) {
501
+ this.state.position = position;
502
+ this.saveToStorage();
503
+ this.notifyListeners();
504
+ }
505
+ startCall() {
506
+ this.state.callStartTime = Date.now();
507
+ this.state.status = "ready";
508
+ this.saveToStorage();
509
+ this.notifyListeners();
510
+ }
511
+ endCall() {
512
+ this.state.callStartTime = null;
513
+ this.state.status = "idle";
514
+ this.state.isHolding = false;
515
+ this.state.isMuted = false;
516
+ this.saveToStorage();
517
+ this.notifyListeners();
518
+ }
519
+ updateCallData(data) {
520
+ this.state.callData = { ...this.state.callData, ...data };
521
+ this.notifyListeners();
522
+ }
523
+ };
524
+ var sdkStateManager = new SDKStateManager();
525
+
526
+ // src/lib/components/CallControlPanel.tsx
527
+ import { useEffect as useEffect2, useState as useState3, useCallback as useCallback2 } from "react";
528
+ import {
529
+ Paper,
530
+ IconButton,
531
+ Typography,
532
+ Menu,
533
+ MenuItem,
534
+ Box,
535
+ Tooltip,
536
+ Fade,
537
+ useTheme,
538
+ Button,
539
+ Badge,
540
+ Chip,
541
+ Avatar,
542
+ TextField
543
+ } from "@mui/material";
544
+ import {
545
+ PauseCircle,
546
+ PlayCircle,
547
+ Mic,
548
+ MicOff,
549
+ MoreVert,
550
+ CallEnd,
551
+ Cached,
552
+ FreeBreakfast,
553
+ AirlineSeatIndividualSuite,
554
+ TransferWithinAStation,
555
+ Groups,
556
+ DragIndicator,
557
+ WifiCalling3,
558
+ Layers,
559
+ Phone
560
+ } from "@mui/icons-material";
561
+
562
+ // src/lib/hooks/useSDKState.ts
563
+ import { useState, useEffect } from "react";
564
+ function useSDKState() {
565
+ const [state, setState] = useState(sdkStateManager.getState());
566
+ useEffect(() => {
567
+ const unsubscribe = sdkStateManager.subscribe(() => {
568
+ setState(sdkStateManager.getState());
569
+ });
570
+ return unsubscribe;
571
+ }, []);
572
+ return state;
573
+ }
574
+
575
+ // src/lib/hooks/useDraggable.ts
576
+ import {
577
+ useState as useState2,
578
+ useRef,
579
+ useCallback
580
+ } from "react";
581
+ function useDraggable(initialPosition, onPositionChange) {
582
+ const [position, setPosition] = useState2(initialPosition);
583
+ const [isDragging, setIsDragging] = useState2(false);
584
+ const dragRef = useRef(null);
585
+ const dragStart = useRef({ x: 0, y: 0 });
586
+ const elementStart = useRef({ x: 0, y: 0 });
587
+ const updatePosition = useCallback(
588
+ (newPosition) => {
589
+ const element = dragRef.current;
590
+ if (!element) return;
591
+ const rect = element.getBoundingClientRect();
592
+ const viewportWidth = window.innerWidth;
593
+ const viewportHeight = window.innerHeight;
594
+ const constrainedPosition = {
595
+ x: Math.max(0, Math.min(newPosition.x, viewportWidth - rect.width)),
596
+ y: Math.max(0, Math.min(newPosition.y, viewportHeight - rect.height))
597
+ };
598
+ setPosition(constrainedPosition);
599
+ onPositionChange?.(constrainedPosition);
600
+ },
601
+ [onPositionChange]
602
+ );
603
+ const handleStart = useCallback(
604
+ (clientX, clientY) => {
605
+ setIsDragging(true);
606
+ dragStart.current = { x: clientX, y: clientY };
607
+ elementStart.current = position;
608
+ const handleMove = (moveClientX, moveClientY) => {
609
+ const deltaX = moveClientX - dragStart.current.x;
610
+ const deltaY = moveClientY - dragStart.current.y;
611
+ updatePosition({
612
+ x: elementStart.current.x + deltaX,
613
+ y: elementStart.current.y + deltaY
614
+ });
615
+ };
616
+ const handleMouseMove = (e) => {
617
+ e.preventDefault();
618
+ handleMove(e.clientX, e.clientY);
619
+ };
620
+ const handleTouchMove = (e) => {
621
+ e.preventDefault();
622
+ const touch = e.touches[0];
623
+ if (touch) {
624
+ handleMove(touch.clientX, touch.clientY);
625
+ }
626
+ };
627
+ const handleEnd = () => {
628
+ setIsDragging(false);
629
+ document.removeEventListener("mousemove", handleMouseMove);
630
+ document.removeEventListener("mouseup", handleEnd);
631
+ document.removeEventListener("touchmove", handleTouchMove);
632
+ document.removeEventListener("touchend", handleEnd);
633
+ };
634
+ document.addEventListener("mousemove", handleMouseMove);
635
+ document.addEventListener("mouseup", handleEnd);
636
+ document.addEventListener("touchmove", handleTouchMove, {
637
+ passive: false
638
+ });
639
+ document.addEventListener("touchend", handleEnd);
640
+ },
641
+ [position, updatePosition]
642
+ );
643
+ const handleMouseDown = useCallback(
644
+ (e) => {
645
+ e.preventDefault();
646
+ handleStart(e.clientX, e.clientY);
647
+ },
648
+ [handleStart]
649
+ );
650
+ const handleTouchStart = useCallback(
651
+ (e) => {
652
+ e.preventDefault();
653
+ const touch = e.touches[0];
654
+ if (touch) {
655
+ handleStart(touch.clientX, touch.clientY);
656
+ }
657
+ },
658
+ [handleStart]
659
+ );
660
+ return {
661
+ position,
662
+ isDragging,
663
+ dragRef,
664
+ handleMouseDown,
665
+ handleTouchStart
666
+ };
667
+ }
668
+
669
+ // src/lib/components/CallControlPanel.tsx
670
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
671
+ function CallControlPanel({ onDataChange }) {
672
+ const theme = useTheme();
673
+ const state = useSDKState();
674
+ const [anchorEl, setAnchorEl] = useState3(null);
675
+ const [phoneNumber, setPhoneNumber] = useState3("");
676
+ const [dialerAnchorEl, setDialerAnchorEl] = useState3(
677
+ null
678
+ );
679
+ const [moreOptionsAnchorEl, setMoreOptionsAnchorEl] = useState3(null);
680
+ const [callDuration, setCallDuration] = useState3(0);
681
+ const { position, isDragging, dragRef, handleMouseDown, handleTouchStart } = useDraggable(
682
+ state.position,
683
+ (newPosition) => sdkStateManager.setPosition(newPosition)
684
+ );
685
+ useEffect2(() => {
686
+ let interval;
687
+ if (state.callStartTime) {
688
+ interval = setInterval(() => {
689
+ const elapsed = Math.floor((Date.now() - state.callStartTime) / 1e3);
690
+ setCallDuration(elapsed);
691
+ }, 1e3);
692
+ } else {
693
+ setCallDuration(0);
694
+ }
695
+ return () => {
696
+ if (interval) clearInterval(interval);
697
+ };
698
+ }, [state.callStartTime]);
699
+ useEffect2(() => {
700
+ if (onDataChange) {
701
+ onDataChange(state.callData);
702
+ }
703
+ }, [state.callData, onDataChange]);
704
+ const formatDuration = useCallback2((seconds) => {
705
+ const mins = Math.floor(seconds / 60);
706
+ const secs = seconds % 60;
707
+ return `${mins.toString().padStart(2, "0")}:${secs.toString().padStart(2, "0")}`;
708
+ }, []);
709
+ const getStatusColor = useCallback2((status) => {
710
+ switch (status) {
711
+ case "ready":
712
+ return "success";
713
+ case "break":
714
+ return "warning";
715
+ case "idle":
716
+ return "info";
717
+ default:
718
+ return "info";
719
+ }
720
+ }, []);
721
+ const handleHoldToggle = () => {
722
+ sdkStateManager.setHolding(!state.isHolding);
723
+ };
724
+ const handleMuteToggle = () => {
725
+ sdkStateManager.setMuted(!state.isMuted);
726
+ };
727
+ const handleStatusChange = (newStatus) => {
728
+ sdkStateManager.setStatus(newStatus);
729
+ setMoreOptionsAnchorEl(null);
730
+ };
731
+ const handleEndCall = () => {
732
+ sdkStateManager.endCall();
733
+ };
734
+ const handleStartCall = (number) => {
735
+ if (number.length !== 10) {
736
+ alert("Invalid phone number");
737
+ } else {
738
+ sdkStateManager.startCall();
739
+ }
740
+ };
741
+ const handleMoreClick = (event) => {
742
+ setAnchorEl(event.currentTarget);
743
+ };
744
+ const handleMoreOptions = (event) => {
745
+ setMoreOptionsAnchorEl(event.currentTarget);
746
+ };
747
+ const handleMoreClose = () => {
748
+ setAnchorEl(null);
749
+ };
750
+ const handleMoreOptionsClose = () => {
751
+ setMoreOptionsAnchorEl(null);
752
+ };
753
+ const handleOpenDialer = (event) => {
754
+ setDialerAnchorEl(event.currentTarget);
755
+ };
756
+ const handleCloseDialer = () => {
757
+ setDialerAnchorEl(null);
758
+ };
759
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
760
+ /* @__PURE__ */ jsx(Fade, { in: true, timeout: 300, children: /* @__PURE__ */ jsx(
761
+ Paper,
762
+ {
763
+ ref: dragRef,
764
+ elevation: isDragging ? 2 : 1,
765
+ sx: {
766
+ position: "fixed",
767
+ left: position.x,
768
+ top: position.y,
769
+ p: 1,
770
+ borderRadius: 3,
771
+ bgcolor: "background.paper",
772
+ cursor: isDragging ? "grabbing" : "grab",
773
+ transition: theme.transitions.create(["box-shadow", "transform"], {
774
+ duration: theme.transitions.duration.short
775
+ }),
776
+ // transform: isDragging ? "scale(1.01)" : "scale(1)",
777
+ minWidth: 320,
778
+ userSelect: "none"
779
+ },
780
+ onMouseDown: handleMouseDown,
781
+ onTouchStart: handleTouchStart,
782
+ children: /* @__PURE__ */ jsxs(
783
+ Box,
784
+ {
785
+ sx: {
786
+ display: "flex",
787
+ alignItems: "center"
788
+ },
789
+ children: [
790
+ /* @__PURE__ */ jsxs(
791
+ Box,
792
+ {
793
+ sx: {
794
+ display: "flex",
795
+ justifyContent: "space-between",
796
+ alignItems: "center"
797
+ },
798
+ children: [
799
+ /* @__PURE__ */ jsxs(
800
+ Typography,
801
+ {
802
+ variant: "h6",
803
+ sx: {
804
+ color: state.callStartTime ? "success.main" : "text.secondary",
805
+ marginRight: "8px",
806
+ display: "flex",
807
+ justifyContent: "space-between",
808
+ alignItems: "center"
809
+ },
810
+ children: [
811
+ /* @__PURE__ */ jsx(DragIndicator, {}),
812
+ " ",
813
+ /* @__PURE__ */ jsx(
814
+ Box,
815
+ {
816
+ sx: {
817
+ marginRight: "10px"
818
+ },
819
+ children: /* @__PURE__ */ jsx(Tooltip, { title: "Dial", children: /* @__PURE__ */ jsx(
820
+ IconButton,
821
+ {
822
+ onClick: (e) => {
823
+ handleOpenDialer(e);
824
+ },
825
+ children: /* @__PURE__ */ jsx(WifiCalling3, { color: "success" })
826
+ }
827
+ ) })
828
+ }
829
+ ),
830
+ formatDuration(callDuration)
831
+ ]
832
+ }
833
+ ),
834
+ /* @__PURE__ */ jsx(Tooltip, { title: "Status", children: /* @__PURE__ */ jsx(
835
+ Button,
836
+ {
837
+ sx: {
838
+ fontWeight: "bold",
839
+ borderRadius: "16px",
840
+ display: "flex",
841
+ alignItems: "center",
842
+ justifyContent: "space-between",
843
+ marginRight: "8px"
844
+ },
845
+ color: getStatusColor(state.status),
846
+ variant: "outlined",
847
+ children: /* @__PURE__ */ jsx(
848
+ Typography,
849
+ {
850
+ width: 50,
851
+ variant: "body2",
852
+ sx: {
853
+ color: getStatusColor(state.status),
854
+ fontWeight: "bold"
855
+ },
856
+ children: state.status.toUpperCase()
857
+ }
858
+ )
859
+ }
860
+ ) })
861
+ ]
862
+ }
863
+ ),
864
+ /* @__PURE__ */ jsxs(
865
+ Box,
866
+ {
867
+ sx: {
868
+ display: "flex",
869
+ gap: 1,
870
+ justifyContent: "center",
871
+ alignItems: "center"
872
+ },
873
+ children: [
874
+ /* @__PURE__ */ jsx(Tooltip, { title: "Redial", children: /* @__PURE__ */ jsx(
875
+ IconButton,
876
+ {
877
+ onClick: (e) => {
878
+ e.stopPropagation();
879
+ },
880
+ color: "default",
881
+ sx: {
882
+ bgcolor: "action.hover",
883
+ "&:hover": {
884
+ bgcolor: "warning"
885
+ }
886
+ },
887
+ children: /* @__PURE__ */ jsx(Cached, {})
888
+ }
889
+ ) }),
890
+ /* @__PURE__ */ jsx(Tooltip, { title: state.isHolding ? "Resume" : "Hold", children: /* @__PURE__ */ jsx(
891
+ IconButton,
892
+ {
893
+ onClick: (e) => {
894
+ e.stopPropagation();
895
+ handleHoldToggle();
896
+ },
897
+ color: state.isHolding ? "warning" : "default",
898
+ sx: {
899
+ bgcolor: state.isHolding ? "warning.info" : "action.hover"
900
+ },
901
+ children: state.isHolding ? /* @__PURE__ */ jsx(PlayCircle, {}) : /* @__PURE__ */ jsx(PauseCircle, {})
902
+ }
903
+ ) }),
904
+ /* @__PURE__ */ jsx(Tooltip, { title: state.isMuted ? "Unmute" : "Mute", children: /* @__PURE__ */ jsx(
905
+ IconButton,
906
+ {
907
+ onClick: (e) => {
908
+ e.stopPropagation();
909
+ handleMuteToggle();
910
+ },
911
+ color: state.isMuted ? "error" : "default",
912
+ sx: {
913
+ bgcolor: state.isMuted ? "error.info" : "action.hover"
914
+ },
915
+ children: state.isMuted ? /* @__PURE__ */ jsx(MicOff, {}) : /* @__PURE__ */ jsx(Mic, {})
916
+ }
917
+ ) }),
918
+ /* @__PURE__ */ jsx(Tooltip, { title: "Queue", children: /* @__PURE__ */ jsx(
919
+ IconButton,
920
+ {
921
+ onClick: (e) => {
922
+ e.stopPropagation();
923
+ handleMoreClick(e);
924
+ },
925
+ color: "default",
926
+ sx: {
927
+ bgcolor: "action.hover",
928
+ "&:hover": {
929
+ bgcolor: "warning"
930
+ }
931
+ },
932
+ children: /* @__PURE__ */ jsx(Layers, {})
933
+ }
934
+ ) }),
935
+ /* @__PURE__ */ jsx(Tooltip, { title: "More Options", children: /* @__PURE__ */ jsx(
936
+ IconButton,
937
+ {
938
+ onClick: (e) => {
939
+ e.stopPropagation();
940
+ handleMoreOptions(e);
941
+ },
942
+ sx: {
943
+ bgcolor: "action.hover",
944
+ "&:hover": { bgcolor: "action.selected" }
945
+ },
946
+ children: /* @__PURE__ */ jsx(MoreVert, {})
947
+ }
948
+ ) }),
949
+ /* @__PURE__ */ jsx(Tooltip, { title: state.callStartTime ? "End Call" : "Start Call", children: /* @__PURE__ */ jsx(
950
+ IconButton,
951
+ {
952
+ onClick: (e) => {
953
+ e.stopPropagation();
954
+ if (state.callStartTime) {
955
+ handleEndCall();
956
+ }
957
+ },
958
+ color: "error",
959
+ sx: {
960
+ bgcolor: state.callStartTime ? "error.main" : "gray",
961
+ color: "white",
962
+ "&:hover": {
963
+ bgcolor: state.callStartTime ? "error.light" : "gray"
964
+ }
965
+ },
966
+ children: /* @__PURE__ */ jsx(CallEnd, {})
967
+ }
968
+ ) })
969
+ ]
970
+ }
971
+ )
972
+ ]
973
+ }
974
+ )
975
+ }
976
+ ) }),
977
+ /* @__PURE__ */ jsx(
978
+ Menu,
979
+ {
980
+ anchorEl: dialerAnchorEl,
981
+ open: Boolean(dialerAnchorEl),
982
+ onClose: handleCloseDialer,
983
+ onClick: (e) => e.stopPropagation(),
984
+ children: /* @__PURE__ */ jsxs(
985
+ Box,
986
+ {
987
+ sx: {
988
+ all: "unset",
989
+ padding: "10px",
990
+ "&hover": {
991
+ backgroundColor: "white"
992
+ }
993
+ },
994
+ children: [
995
+ /* @__PURE__ */ jsx(
996
+ TextField,
997
+ {
998
+ size: "small",
999
+ value: phoneNumber,
1000
+ placeholder: "Enter Mobile No.",
1001
+ onChange: (e) => {
1002
+ setPhoneNumber(e.target.value);
1003
+ }
1004
+ }
1005
+ ),
1006
+ /* @__PURE__ */ jsx(
1007
+ IconButton,
1008
+ {
1009
+ color: "info",
1010
+ onClick: () => {
1011
+ handleStartCall(phoneNumber);
1012
+ },
1013
+ children: /* @__PURE__ */ jsx(Phone, { color: "success" })
1014
+ }
1015
+ )
1016
+ ]
1017
+ }
1018
+ )
1019
+ }
1020
+ ),
1021
+ /* @__PURE__ */ jsx(
1022
+ Menu,
1023
+ {
1024
+ anchorEl,
1025
+ open: Boolean(anchorEl),
1026
+ onClose: handleMoreClose,
1027
+ onClick: (e) => e.stopPropagation(),
1028
+ children: /* @__PURE__ */ jsxs(
1029
+ Box,
1030
+ {
1031
+ sx: {
1032
+ all: "unset",
1033
+ padding: "0px 10px",
1034
+ "&hover": {
1035
+ backgroundColor: "white"
1036
+ }
1037
+ },
1038
+ children: [
1039
+ /* @__PURE__ */ jsx(Badge, { badgeContent: 100, color: "secondary", children: /* @__PURE__ */ jsx(
1040
+ Chip,
1041
+ {
1042
+ avatar: /* @__PURE__ */ jsx(Avatar, { children: "Q" }),
1043
+ variant: "outlined",
1044
+ label: "Waiting"
1045
+ }
1046
+ ) }),
1047
+ /* @__PURE__ */ jsx(
1048
+ Badge,
1049
+ {
1050
+ badgeContent: 100,
1051
+ color: "warning",
1052
+ sx: {
1053
+ margin: "10px"
1054
+ },
1055
+ children: /* @__PURE__ */ jsx(
1056
+ Chip,
1057
+ {
1058
+ avatar: /* @__PURE__ */ jsx(Avatar, { children: "C" }),
1059
+ label: "Pending",
1060
+ variant: "outlined"
1061
+ }
1062
+ )
1063
+ }
1064
+ ),
1065
+ /* @__PURE__ */ jsx(
1066
+ Badge,
1067
+ {
1068
+ badgeContent: 100,
1069
+ color: "info",
1070
+ sx: {
1071
+ margin: "10px"
1072
+ },
1073
+ children: /* @__PURE__ */ jsx(
1074
+ Chip,
1075
+ {
1076
+ avatar: /* @__PURE__ */ jsx(Avatar, { children: "C" }),
1077
+ variant: "outlined",
1078
+ label: "Upcoming"
1079
+ }
1080
+ )
1081
+ }
1082
+ )
1083
+ ]
1084
+ }
1085
+ )
1086
+ }
1087
+ ),
1088
+ /* @__PURE__ */ jsxs(
1089
+ Menu,
1090
+ {
1091
+ anchorEl: moreOptionsAnchorEl,
1092
+ open: Boolean(moreOptionsAnchorEl),
1093
+ onClose: handleMoreOptionsClose,
1094
+ onClick: (e) => e.stopPropagation(),
1095
+ children: [
1096
+ /* @__PURE__ */ jsx(MenuItem, { onClick: () => setMoreOptionsAnchorEl(null), children: /* @__PURE__ */ jsxs(Box, { sx: { display: "flex", alignItems: "center", gap: 1 }, children: [
1097
+ /* @__PURE__ */ jsx(TransferWithinAStation, { color: "secondary" }),
1098
+ /* @__PURE__ */ jsx(Typography, { children: "Call Transfer" })
1099
+ ] }) }),
1100
+ /* @__PURE__ */ jsx(MenuItem, { onClick: () => setMoreOptionsAnchorEl(null), children: /* @__PURE__ */ jsxs(Box, { sx: { display: "flex", alignItems: "center", gap: 1 }, children: [
1101
+ /* @__PURE__ */ jsx(Groups, { color: "secondary" }),
1102
+ /* @__PURE__ */ jsx(Typography, { children: "Conference Call" })
1103
+ ] }) }),
1104
+ /* @__PURE__ */ jsx(MenuItem, { onClick: () => handleStatusChange("break"), children: /* @__PURE__ */ jsxs(Box, { sx: { display: "flex", alignItems: "center", gap: 1 }, children: [
1105
+ /* @__PURE__ */ jsx(FreeBreakfast, { color: "secondary" }),
1106
+ /* @__PURE__ */ jsx(Typography, { children: "Break" })
1107
+ ] }) }),
1108
+ /* @__PURE__ */ jsx(MenuItem, { onClick: () => handleStatusChange("idle"), children: /* @__PURE__ */ jsxs(Box, { sx: { display: "flex", alignItems: "center", gap: 1 }, children: [
1109
+ /* @__PURE__ */ jsx(AirlineSeatIndividualSuite, { color: "secondary" }),
1110
+ /* @__PURE__ */ jsx(Typography, { children: "Idle" })
1111
+ ] }) })
1112
+ ]
1113
+ }
1114
+ )
1115
+ ] });
1116
+ }
1117
+
1118
+ // src/index.ts
1119
+ function initSDK(sdkApiKey, tenantId, agentId, baseUrl) {
1120
+ sdkStateManager.initialize(sdkApiKey);
1121
+ eventTracker.init({
1122
+ apiKey: sdkApiKey,
1123
+ tenantId,
1124
+ agentId,
1125
+ baseUrl
1126
+ });
1127
+ }
1128
+ export {
1129
+ CallControlPanel,
1130
+ initSDK
1131
+ };