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