@tbisoftware/phone 1.0.13 → 2.0.4

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.
@@ -0,0 +1,706 @@
1
+ import { defineComponent as re, ref as p, computed as ee, onMounted as X, onUnmounted as Y, createElementBlock as m, openBlock as f, normalizeClass as K, unref as B, createCommentVNode as V, createBlock as ie, createElementVNode as e, withDirectives as ce, vModelText as de, toDisplayString as k, createTextVNode as te, Teleport as ue, Fragment as F, renderList as ve, normalizeStyle as fe, readonly as D, provide as ge, inject as he } from "vue";
2
+ import { d as me, f as G, c as J, J as W, P as pe } from "../index-TymkBND5.js";
3
+ const ye = {
4
+ key: 0,
5
+ class: "flex gap-2 items-center"
6
+ }, Ce = ["placeholder"], xe = ["disabled", "title"], we = {
7
+ key: 0,
8
+ class: "w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin"
9
+ }, be = {
10
+ key: 1,
11
+ class: "w-4 h-4",
12
+ viewBox: "0 0 24 24",
13
+ fill: "currentColor"
14
+ }, Se = {
15
+ key: 1,
16
+ class: "flex flex-col items-center gap-3 py-6"
17
+ }, Ee = { class: "text-center" }, _e = { class: "text-base font-semibold" }, ke = { class: "text-sm text-gray-500" }, ze = {
18
+ key: 2,
19
+ class: "flex flex-col items-center gap-4 py-6"
20
+ }, He = { class: "text-center space-y-1" }, Ue = { class: "text-xl font-bold" }, Me = { class: "text-2xl font-mono text-green-600 tabular-nums" }, De = {
21
+ key: 3,
22
+ class: "flex flex-col items-center gap-3 py-6"
23
+ }, Re = {
24
+ key: 0,
25
+ d: "M6.5 5.5 12 11l7-7-1-1-6 6-4.5-4.5H11V3H5v6h1.5V5.5zm17.21 11.17C20.66 13.78 16.54 12 12 12 7.46 12 3.34 13.78.29 16.67c-.18.18-.29.43-.29.71s.11.53.29.71l2.48 2.48c.18.18.43.29.71.29.27 0 .52-.11.7-.28.79-.74 1.69-1.36 2.66-1.85.33-.16.56-.5.56-.9v-3.1c1.45-.48 3-.73 4.6-.73 1.6 0 3.15.25 4.6.72v3.1c0 .39.23.74.56.9.98.49 1.87 1.12 2.67 1.85.18.18.43.28.7.28.28 0 .53-.11.71-.29l2.48-2.48c.18-.18.29-.43.29-.71s-.12-.52-.3-.7z"
26
+ }, Ne = {
27
+ key: 1,
28
+ d: "M12 9c-1.6 0-3.15.25-4.6.72v3.1c0 .39-.23.74-.56.9-.98.49-1.87 1.12-2.66 1.85-.18.18-.43.28-.7.28-.28 0-.53-.11-.71-.29L.29 13.08a.956.956 0 0 1-.29-.7c0-.28.11-.53.29-.71C3.34 8.78 7.46 7 12 7s8.66 1.78 11.71 4.67c.18.18.29.43.29.71 0 .28-.11.53-.29.71l-2.48 2.48c-.18.18-.43.29-.71.29-.27 0-.52-.11-.7-.28a11.27 11.27 0 0 0-2.67-1.85.996.996 0 0 1-.56-.9v-3.1C15.15 9.25 13.6 9 12 9z"
29
+ }, Ie = { class: "text-center" }, Te = { class: "text-base font-semibold" }, Le = {
30
+ key: 0,
31
+ class: "fixed inset-0 z-50 flex"
32
+ }, Pe = {
33
+ class: "fixed right-0 top-0 h-full w-full max-w-md bg-white shadow-xl",
34
+ style: { "background-color": "white" }
35
+ }, $e = { class: "flex flex-col h-full" }, Be = { class: "flex items-center justify-between p-4 border-b" }, Ve = { class: "text-lg font-semibold" }, je = { class: "text-sm text-gray-500" }, Ae = { class: "flex-1 overflow-y-auto p-4" }, Oe = {
36
+ key: 0,
37
+ class: "text-center py-12 text-gray-500"
38
+ }, Ke = {
39
+ key: 1,
40
+ class: "space-y-2"
41
+ }, Fe = {
42
+ key: 2,
43
+ d: "M6.5 5.5 12 11l7-7-1-1-6 6-4.5-4.5H11V3H5v6h1.5V5.5zm17.21 11.17C20.66 13.78 16.54 12 12 12 7.46 12 3.34 13.78.29 16.67c-.18.18-.29.43-.29.71s.11.53.29.71l2.48 2.48c.18.18.43.29.71.29.27 0 .52-.11.7-.28.79-.74 1.69-1.36 2.66-1.85.33-.16.56-.5.56-.9v-3.1c1.45-.48 3-.73 4.6-.73 1.6 0 3.15.25 4.6.72v3.1c0 .39.23.74.56.9.98.49 1.87 1.12 2.67 1.85.18.18.43.28.7.28.28 0 .53-.11.71-.29l2.48-2.48c.18-.18.29-.43.29-.71s-.12-.52-.3-.7z"
44
+ }, Je = { class: "flex-1 min-w-0" }, We = { class: "font-medium text-sm truncate" }, qe = { class: "flex items-center gap-2 text-xs text-gray-500" }, Ge = { class: "font-mono tabular-nums" }, Qe = ["onClick"], tt = /* @__PURE__ */ re({
45
+ __name: "Phone",
46
+ props: {
47
+ config: {},
48
+ className: { default: "" },
49
+ labels: { default: () => ({}) },
50
+ onCallStart: {},
51
+ onCallEnd: {},
52
+ onStatusChange: {}
53
+ },
54
+ emits: ["callStart", "callEnd", "statusChange"],
55
+ setup(v, { emit: R }) {
56
+ const y = v, C = R;
57
+ let c = null, g = null;
58
+ function w(s) {
59
+ return `${s.websocketUrl}|${s.sipUri}|${s.authorizationUser}`;
60
+ }
61
+ function d(s) {
62
+ const t = w(s);
63
+ if (c && g === t)
64
+ return c;
65
+ if (c && g !== t) {
66
+ try {
67
+ c.ua.stop();
68
+ } catch {
69
+ }
70
+ c = null;
71
+ }
72
+ g = t;
73
+ const E = {
74
+ sockets: [new W.WebSocketInterface(s.websocketUrl)],
75
+ uri: s.sipUri,
76
+ password: s.password,
77
+ registrar_server: s.registrarServer,
78
+ display_name: s.displayName,
79
+ authorization_user: s.authorizationUser,
80
+ connection_recovery_min_interval: 2,
81
+ connection_recovery_max_interval: 30
82
+ }, U = new W.UA(E), Z = document.createElement("audio");
83
+ Z.autoplay = !0;
84
+ const T = {
85
+ ua: U,
86
+ audio: Z,
87
+ isStarted: !1,
88
+ listeners: /* @__PURE__ */ new Set()
89
+ };
90
+ return U.on("connecting", () => {
91
+ T.listeners.forEach((_) => _.onConnecting?.());
92
+ }), U.on("connected", () => {
93
+ T.listeners.forEach((_) => _.onConnected?.());
94
+ }), U.on("disconnected", () => {
95
+ T.listeners.forEach((_) => _.onDisconnected?.());
96
+ }), U.on("registered", () => {
97
+ T.listeners.forEach((_) => _.onRegistered?.());
98
+ }), U.on("unregistered", () => {
99
+ T.listeners.forEach((_) => _.onUnregistered?.());
100
+ }), U.on("registrationFailed", (_) => {
101
+ T.listeners.forEach((P) => P.onRegistrationFailed?.(_?.cause));
102
+ }), U.on("newRTCSession", (_) => {
103
+ const P = _.session;
104
+ P.direction === "outgoing" && (T.listeners.forEach(($) => $.onNewSession?.(P)), P.connection && (P.connection.addEventListener("addstream", ($) => {
105
+ if (!$.streams?.length) return;
106
+ const O = document.createElement("audio");
107
+ O.srcObject = $.streams[0], O.play();
108
+ }), P.connection.addEventListener("track", ($) => {
109
+ const O = document.createElement("audio");
110
+ O.srcObject = $.streams[0], O.play();
111
+ })));
112
+ }), c = T, T;
113
+ }
114
+ const o = p("disconnected"), r = p(""), i = p([]), b = p(0), u = p(!1), x = p("connecting"), S = p(!1);
115
+ let l = null, z = null, M = null, H = null, N = null;
116
+ const n = ee(() => ({ ...me, ...y.labels })), L = ee(() => {
117
+ switch (o.value) {
118
+ case "progress":
119
+ return { text: `${n.value.calling}...`, color: "text-yellow-500", icon: "ring" };
120
+ case "confirmed":
121
+ return { text: `${n.value.inCall} - ${G(b.value)}`, color: "text-green-500", icon: "inTalk" };
122
+ case "failed":
123
+ return { text: n.value.callEnded, color: "text-red-500", icon: "missed" };
124
+ case "ended":
125
+ return { text: n.value.callEnded, color: "text-gray-500", icon: "hangup" };
126
+ default:
127
+ return { text: n.value.inactive, color: "text-gray-300", icon: "phone" };
128
+ }
129
+ });
130
+ function I(s, t, a) {
131
+ const E = {
132
+ id: Date.now().toString(),
133
+ number: s,
134
+ timestamp: Date.now(),
135
+ duration: t,
136
+ status: a
137
+ };
138
+ i.value = [E, ...i.value].slice(0, 50), localStorage.setItem("tbi-phone-call-history", JSON.stringify(i.value));
139
+ }
140
+ function h() {
141
+ z && (z.terminate(), z = null);
142
+ }
143
+ function A(s) {
144
+ if (!s.trim() || !l) return;
145
+ if (!u.value) {
146
+ console.warn("Phone is not ready yet. Please wait for registration.");
147
+ return;
148
+ }
149
+ r.value = s, y.onCallStart?.(s), C("callStart", s);
150
+ const a = {
151
+ eventHandlers: {
152
+ progress: () => {
153
+ o.value = "progress", y.onStatusChange?.("progress"), C("statusChange", "progress");
154
+ },
155
+ failed: (E) => {
156
+ console.error("Call failed:", E?.cause), o.value = "failed", y.onStatusChange?.("failed"), C("statusChange", "failed"), I(s, 0, "failed"), y.onCallEnd?.(s, 0, "failed"), C("callEnd", s, 0, "failed"), z = null, setTimeout(() => {
157
+ o.value = "disconnected", y.onStatusChange?.("disconnected"), C("statusChange", "disconnected");
158
+ }, 3e3);
159
+ },
160
+ ended: () => {
161
+ o.value = "ended", y.onStatusChange?.("ended"), C("statusChange", "ended");
162
+ const E = M ? Math.floor((Date.now() - M) / 1e3) : 0;
163
+ I(s, E, "completed"), y.onCallEnd?.(s, E, "completed"), C("callEnd", s, E, "completed"), z = null, H && (clearInterval(H), H = null), setTimeout(() => {
164
+ o.value = "disconnected", y.onStatusChange?.("disconnected"), C("statusChange", "disconnected"), M = null, b.value = 0;
165
+ }, 2e3);
166
+ },
167
+ confirmed: () => {
168
+ o.value = "confirmed", y.onStatusChange?.("confirmed"), C("statusChange", "confirmed"), M = Date.now(), H = setInterval(() => {
169
+ M && (b.value = Math.floor((Date.now() - M) / 1e3));
170
+ }, 1e3);
171
+ }
172
+ },
173
+ mediaConstraints: { audio: !0, video: !1 }
174
+ };
175
+ o.value = "progress", y.onStatusChange?.("progress"), C("statusChange", "progress");
176
+ try {
177
+ z = l.ua.call(s, a);
178
+ } catch (E) {
179
+ console.error("Failed to start call:", E), o.value = "failed", y.onStatusChange?.("failed"), C("statusChange", "failed"), I(s, 0, "failed"), setTimeout(() => {
180
+ o.value = "disconnected", y.onStatusChange?.("disconnected"), C("statusChange", "disconnected");
181
+ }, 3e3);
182
+ }
183
+ }
184
+ function q(s) {
185
+ s.key === "Enter" && A(r.value);
186
+ }
187
+ function se(s) {
188
+ r.value = s.number, S.value = !1, A(s.number);
189
+ }
190
+ function oe(s) {
191
+ switch (s) {
192
+ case "completed":
193
+ return "bg-green-100";
194
+ case "failed":
195
+ return "bg-red-100";
196
+ case "missed":
197
+ return "bg-yellow-100";
198
+ }
199
+ }
200
+ function le(s) {
201
+ switch (s) {
202
+ case "completed":
203
+ return "text-green-600";
204
+ case "failed":
205
+ return "text-red-600";
206
+ case "missed":
207
+ return "text-yellow-600";
208
+ }
209
+ }
210
+ function ae(s) {
211
+ return new Date(s).toLocaleString("es-ES", {
212
+ day: "2-digit",
213
+ month: "2-digit",
214
+ hour: "2-digit",
215
+ minute: "2-digit"
216
+ });
217
+ }
218
+ return X(() => {
219
+ l = d(y.config), l.ua.isRegistered() ? (u.value = !0, x.value = "connected") : l.ua.isConnected() && (x.value = "connected"), N = {
220
+ onConnecting: () => {
221
+ x.value = "connecting";
222
+ },
223
+ onConnected: () => {
224
+ x.value = "connected";
225
+ },
226
+ onDisconnected: () => {
227
+ x.value = "disconnected", u.value = !1;
228
+ },
229
+ onRegistered: () => {
230
+ u.value = !0, x.value = "connected";
231
+ },
232
+ onUnregistered: () => {
233
+ u.value = !1;
234
+ },
235
+ onRegistrationFailed: (a) => {
236
+ console.error("Registration failed:", a), u.value = !1, x.value = "failed";
237
+ },
238
+ onNewSession: (a) => {
239
+ z = a;
240
+ }
241
+ }, l.listeners.add(N), l.isStarted || (l.ua.start(), l.isStarted = !0);
242
+ const s = localStorage.getItem("tbi-phone-call-history");
243
+ if (s)
244
+ try {
245
+ i.value = JSON.parse(s);
246
+ } catch (a) {
247
+ console.error("Error loading call history", a);
248
+ }
249
+ const t = (a) => {
250
+ const U = a.detail.number;
251
+ o.value === "disconnected" && A(U);
252
+ };
253
+ window.addEventListener("StartCallEvent", t);
254
+ }), Y(() => {
255
+ H && clearInterval(H), l && N && l.listeners.delete(N);
256
+ }), (s, t) => (f(), m("div", {
257
+ class: K(B(J)("tbi-phone w-full max-w-md mx-auto bg-white rounded-2xl shadow-lg border border-gray-200 p-2", v.className))
258
+ }, [
259
+ o.value === "disconnected" ? (f(), m("div", ye, [
260
+ e("button", {
261
+ onClick: t[0] || (t[0] = (a) => S.value = !0),
262
+ class: "h-8 w-8 flex items-center justify-center rounded-xl border border-gray-200 hover:bg-gray-50 transition-colors",
263
+ type: "button"
264
+ }, [...t[5] || (t[5] = [
265
+ e("svg", {
266
+ class: "w-4 h-4",
267
+ viewBox: "0 0 24 24",
268
+ fill: "currentColor"
269
+ }, [
270
+ e("path", { d: "M13 3a9 9 0 0 0-9 9H1l3.89 3.89.07.14L9 12H6c0-3.87 3.13-7 7-7s7 3.13 7 7-3.13 7-7 7c-1.93 0-3.68-.79-4.94-2.06l-1.42 1.42A8.954 8.954 0 0 0 13 21a9 9 0 0 0 0-18zm-1 5v5l4.28 2.54.72-1.21-3.5-2.08V8H12z" })
271
+ ], -1)
272
+ ])]),
273
+ ce(e("input", {
274
+ type: "text",
275
+ "onUpdate:modelValue": t[1] || (t[1] = (a) => r.value = a),
276
+ onKeydown: q,
277
+ placeholder: n.value.placeholder,
278
+ class: "flex-1 w-full h-8 px-3 rounded-xl border border-gray-200 text-sm focus:outline-none focus:ring-2 focus:ring-green-500 focus:border-transparent"
279
+ }, null, 40, Ce), [
280
+ [de, r.value]
281
+ ]),
282
+ e("button", {
283
+ onClick: t[2] || (t[2] = (a) => A(r.value)),
284
+ disabled: r.value.length < 9 || !u.value,
285
+ class: "h-8 w-8 flex items-center justify-center rounded-xl bg-green-500 hover:bg-green-600 disabled:bg-gray-300 disabled:cursor-not-allowed text-white transition-colors",
286
+ type: "button",
287
+ title: u.value ? "Call" : "Connecting..."
288
+ }, [
289
+ x.value === "connecting" ? (f(), m("div", we)) : (f(), m("svg", be, [...t[6] || (t[6] = [
290
+ e("path", { d: "M6.62 10.79c1.44 2.83 3.76 5.14 6.59 6.59l2.2-2.2c.27-.27.67-.36 1.02-.24 1.12.37 2.33.57 3.57.57.55 0 1 .45 1 1V20c0 .55-.45 1-1 1-9.39 0-17-7.61-17-17 0-.55.45-1 1-1h3.5c.55 0 1 .45 1 1 0 1.25.2 2.45.57 3.57.11.35.03.74-.25 1.02l-2.2 2.2z" }, null, -1)
291
+ ])]))
292
+ ], 8, xe)
293
+ ])) : V("", !0),
294
+ o.value === "progress" ? (f(), m("div", Se, [
295
+ t[8] || (t[8] = e("div", { class: "relative" }, [
296
+ e("svg", {
297
+ class: "w-12 h-12 text-yellow-500 animate-pulse",
298
+ viewBox: "0 0 24 24",
299
+ fill: "currentColor"
300
+ }, [
301
+ e("path", { d: "M15.05 5A7 7 0 0 1 19 8.95M15.05 1A11 11 0 0 1 23 8.94m-1 7.98v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z" })
302
+ ]),
303
+ e("div", { class: "absolute inset-0 rounded-full border-4 border-yellow-500/30 animate-ping" })
304
+ ], -1)),
305
+ e("div", Ee, [
306
+ e("p", _e, k(n.value.calling) + " " + k(r.value), 1),
307
+ e("p", ke, k(n.value.waitingResponse), 1)
308
+ ]),
309
+ e("button", {
310
+ onClick: h,
311
+ class: "flex items-center gap-2 px-6 py-2 rounded-full bg-red-500 hover:bg-red-600 text-white text-sm font-medium transition-colors",
312
+ type: "button"
313
+ }, [
314
+ t[7] || (t[7] = e("svg", {
315
+ class: "w-4 h-4",
316
+ viewBox: "0 0 24 24",
317
+ fill: "currentColor"
318
+ }, [
319
+ e("path", { d: "M12 9c-1.6 0-3.15.25-4.6.72v3.1c0 .39-.23.74-.56.9-.98.49-1.87 1.12-2.66 1.85-.18.18-.43.28-.7.28-.28 0-.53-.11-.71-.29L.29 13.08a.956.956 0 0 1-.29-.7c0-.28.11-.53.29-.71C3.34 8.78 7.46 7 12 7s8.66 1.78 11.71 4.67c.18.18.29.43.29.71 0 .28-.11.53-.29.71l-2.48 2.48c-.18.18-.43.29-.71.29-.27 0-.52-.11-.7-.28a11.27 11.27 0 0 0-2.67-1.85.996.996 0 0 1-.56-.9v-3.1C15.15 9.25 13.6 9 12 9z" })
320
+ ], -1)),
321
+ te(" " + k(n.value.cancel), 1)
322
+ ])
323
+ ])) : V("", !0),
324
+ o.value === "confirmed" ? (f(), m("div", ze, [
325
+ t[10] || (t[10] = e("div", { class: "relative" }, [
326
+ e("svg", {
327
+ class: "w-12 h-12 text-green-500",
328
+ viewBox: "0 0 24 24",
329
+ fill: "currentColor"
330
+ }, [
331
+ e("path", { d: "M20 15.5c-1.25 0-2.45-.2-3.57-.57-.35-.12-.74-.03-1.02.24l-2.2 2.2c-2.83-1.45-5.15-3.76-6.59-6.59l2.2-2.21c.28-.26.36-.65.25-1C8.7 6.45 8.5 5.25 8.5 4c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1 0 9.39 7.61 17 17 17 .55 0 1-.45 1-1v-3.5c0-.55-.45-1-1-1zM19 12h2c0-4.97-4.03-9-9-9v2c3.87 0 7 3.13 7 7zm-4 0h2c0-2.76-2.24-5-5-5v2c1.66 0 3 1.34 3 3z" })
332
+ ]),
333
+ e("div", { class: "absolute inset-0 rounded-full bg-green-500/20 animate-pulse" })
334
+ ], -1)),
335
+ e("div", He, [
336
+ e("p", Ue, k(r.value), 1),
337
+ e("p", Me, k(B(G)(b.value)), 1)
338
+ ]),
339
+ e("button", {
340
+ onClick: h,
341
+ class: "flex items-center gap-2 px-6 py-2 rounded-full bg-red-500 hover:bg-red-600 text-white text-sm font-medium transition-colors",
342
+ type: "button"
343
+ }, [
344
+ t[9] || (t[9] = e("svg", {
345
+ class: "w-4 h-4",
346
+ viewBox: "0 0 24 24",
347
+ fill: "currentColor"
348
+ }, [
349
+ e("path", { d: "M12 9c-1.6 0-3.15.25-4.6.72v3.1c0 .39-.23.74-.56.9-.98.49-1.87 1.12-2.66 1.85-.18.18-.43.28-.7.28-.28 0-.53-.11-.71-.29L.29 13.08a.956.956 0 0 1-.29-.7c0-.28.11-.53.29-.71C3.34 8.78 7.46 7 12 7s8.66 1.78 11.71 4.67c.18.18.29.43.29.71 0 .28-.11.53-.29.71l-2.48 2.48c-.18.18-.43.29-.71.29-.27 0-.52-.11-.7-.28a11.27 11.27 0 0 0-2.67-1.85.996.996 0 0 1-.56-.9v-3.1C15.15 9.25 13.6 9 12 9z" })
350
+ ], -1)),
351
+ te(" " + k(n.value.hangUp), 1)
352
+ ])
353
+ ])) : V("", !0),
354
+ o.value === "failed" || o.value === "ended" ? (f(), m("div", De, [
355
+ (f(), m("svg", {
356
+ class: K(B(J)("w-12 h-12", o.value === "failed" ? "text-red-500" : "text-gray-500")),
357
+ viewBox: "0 0 24 24",
358
+ fill: "currentColor"
359
+ }, [
360
+ o.value === "failed" ? (f(), m("path", Re)) : (f(), m("path", Ne))
361
+ ], 2)),
362
+ e("div", Ie, [
363
+ e("p", Te, k(L.value.text), 1)
364
+ ])
365
+ ])) : V("", !0),
366
+ (f(), ie(ue, { to: "body" }, [
367
+ S.value ? (f(), m("div", Le, [
368
+ e("div", {
369
+ class: "fixed inset-0 bg-black/50",
370
+ onClick: t[3] || (t[3] = (a) => S.value = !1)
371
+ }),
372
+ e("div", Pe, [
373
+ e("div", $e, [
374
+ e("div", Be, [
375
+ e("div", null, [
376
+ e("h2", Ve, k(n.value.callHistory), 1),
377
+ e("p", je, k(i.value.length === 0 ? n.value.noCallsRegistered : `${i.value.length} ${n.value.callsRegistered}`), 1)
378
+ ]),
379
+ e("button", {
380
+ onClick: t[4] || (t[4] = (a) => S.value = !1),
381
+ class: "h-8 w-8 flex items-center justify-center rounded-lg hover:bg-gray-100 transition-colors",
382
+ type: "button"
383
+ }, [...t[11] || (t[11] = [
384
+ e("svg", {
385
+ class: "w-5 h-5",
386
+ viewBox: "0 0 24 24",
387
+ fill: "currentColor"
388
+ }, [
389
+ e("path", { d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" })
390
+ ], -1)
391
+ ])])
392
+ ]),
393
+ e("div", Ae, [
394
+ i.value.length === 0 ? (f(), m("div", Oe, [
395
+ t[12] || (t[12] = e("svg", {
396
+ class: "w-12 h-12 mx-auto mb-2 opacity-50",
397
+ viewBox: "0 0 24 24",
398
+ fill: "currentColor"
399
+ }, [
400
+ e("path", { d: "M12 9c-1.6 0-3.15.25-4.6.72v3.1c0 .39-.23.74-.56.9-.98.49-1.87 1.12-2.66 1.85-.18.18-.43.28-.7.28-.28 0-.53-.11-.71-.29L.29 13.08a.956.956 0 0 1-.29-.7c0-.28.11-.53.29-.71C3.34 8.78 7.46 7 12 7s8.66 1.78 11.71 4.67c.18.18.29.43.29.71 0 .28-.11.53-.29.71l-2.48 2.48c-.18.18-.43.29-.71.29-.27 0-.52-.11-.7-.28a11.27 11.27 0 0 0-2.67-1.85.996.996 0 0 1-.56-.9v-3.1C15.15 9.25 13.6 9 12 9z" })
401
+ ], -1)),
402
+ e("p", null, k(n.value.noCalls), 1)
403
+ ])) : (f(), m("div", Ke, [
404
+ (f(!0), m(F, null, ve(i.value, (a, E) => (f(), m("div", {
405
+ key: a.id,
406
+ class: "flex items-center gap-3 p-3 rounded-lg hover:bg-gray-50 transition-colors duration-200",
407
+ style: fe({ animationDelay: `${E * 30}ms` })
408
+ }, [
409
+ e("div", {
410
+ class: K(B(J)("w-9 h-9 rounded-full flex items-center justify-center shrink-0", oe(a.status)))
411
+ }, [
412
+ (f(), m("svg", {
413
+ class: K(B(J)("w-4 h-4", le(a.status))),
414
+ viewBox: "0 0 24 24",
415
+ fill: "currentColor"
416
+ }, [
417
+ a.status === "completed" ? (f(), m(F, { key: 0 }, [
418
+ t[13] || (t[13] = e("path", { d: "M6.62 10.79c1.44 2.83 3.76 5.14 6.59 6.59l2.2-2.2c.27-.27.67-.36 1.02-.24 1.12.37 2.33.57 3.57.57.55 0 1 .45 1 1V20c0 .55-.45 1-1 1-9.39 0-17-7.61-17-17 0-.55.45-1 1-1h3.5c.55 0 1 .45 1 1 0 1.25.2 2.45.57 3.57.11.35.03.74-.25 1.02l-2.2 2.2z" }, null, -1)),
419
+ t[14] || (t[14] = e("path", { d: "M16 3l-5 5-2-2-1.5 1.5L11 11l6.5-6.5z" }, null, -1))
420
+ ], 64)) : a.status === "failed" ? (f(), m(F, { key: 1 }, [
421
+ t[15] || (t[15] = e("path", { d: "M6.62 10.79c1.44 2.83 3.76 5.14 6.59 6.59l2.2-2.2c.27-.27.67-.36 1.02-.24 1.12.37 2.33.57 3.57.57.55 0 1 .45 1 1V20c0 .55-.45 1-1 1-9.39 0-17-7.61-17-17 0-.55.45-1 1-1h3.5c.55 0 1 .45 1 1 0 1.25.2 2.45.57 3.57.11.35.03.74-.25 1.02l-2.2 2.2z" }, null, -1)),
422
+ t[16] || (t[16] = e("path", { d: "M19 6.41L17.59 5 15 7.59 12.41 5 11 6.41 13.59 9 11 11.59 12.41 13 15 10.41 17.59 13 19 11.59 16.41 9z" }, null, -1))
423
+ ], 64)) : (f(), m("path", Fe))
424
+ ], 2))
425
+ ], 2),
426
+ e("div", Je, [
427
+ e("p", We, k(a.number), 1),
428
+ e("div", qe, [
429
+ e("span", null, k(ae(a.timestamp)), 1),
430
+ a.duration > 0 ? (f(), m(F, { key: 0 }, [
431
+ t[17] || (t[17] = e("span", null, "•", -1)),
432
+ e("span", Ge, k(B(G)(a.duration)), 1)
433
+ ], 64)) : V("", !0)
434
+ ])
435
+ ]),
436
+ e("button", {
437
+ onClick: (U) => se(a),
438
+ class: "h-8 w-8 flex items-center justify-center shrink-0 rounded-lg hover:bg-gray-100 transition-colors",
439
+ type: "button"
440
+ }, [...t[18] || (t[18] = [
441
+ e("svg", {
442
+ class: "w-4 h-4",
443
+ viewBox: "0 0 24 24",
444
+ fill: "currentColor"
445
+ }, [
446
+ e("path", { d: "M6.62 10.79c1.44 2.83 3.76 5.14 6.59 6.59l2.2-2.2c.27-.27.67-.36 1.02-.24 1.12.37 2.33.57 3.57.57.55 0 1 .45 1 1V20c0 .55-.45 1-1 1-9.39 0-17-7.61-17-17 0-.55.45-1 1-1h3.5c.55 0 1 .45 1 1 0 1.25.2 2.45.57 3.57.11.35.03.74-.25 1.02l-2.2 2.2z" })
447
+ ], -1)
448
+ ])], 8, Qe)
449
+ ], 4))), 128))
450
+ ]))
451
+ ])
452
+ ])
453
+ ])
454
+ ])) : V("", !0)
455
+ ]))
456
+ ], 2));
457
+ }
458
+ }), ne = /* @__PURE__ */ Symbol("Phone");
459
+ let j = null, Q = null;
460
+ function Xe(v) {
461
+ return `${v.websocketUrl}|${v.sipUri}|${v.authorizationUser}`;
462
+ }
463
+ function Ye(v) {
464
+ const R = Xe(v);
465
+ if (j && Q === R)
466
+ return j;
467
+ if (j && Q !== R) {
468
+ try {
469
+ j.ua.stop();
470
+ } catch {
471
+ }
472
+ j = null;
473
+ }
474
+ Q = R;
475
+ const C = {
476
+ sockets: [new W.WebSocketInterface(v.websocketUrl)],
477
+ uri: v.sipUri,
478
+ password: v.password,
479
+ registrar_server: v.registrarServer,
480
+ display_name: v.displayName,
481
+ authorization_user: v.authorizationUser,
482
+ connection_recovery_min_interval: 2,
483
+ connection_recovery_max_interval: 30
484
+ }, c = new W.UA(C), g = document.createElement("audio");
485
+ g.autoplay = !0;
486
+ const w = {
487
+ ua: c,
488
+ audio: g,
489
+ isStarted: !1,
490
+ listeners: /* @__PURE__ */ new Set()
491
+ };
492
+ return c.on("connecting", () => {
493
+ w.listeners.forEach((d) => d.onConnecting?.());
494
+ }), c.on("connected", () => {
495
+ w.listeners.forEach((d) => d.onConnected?.());
496
+ }), c.on("disconnected", () => {
497
+ w.listeners.forEach((d) => d.onDisconnected?.());
498
+ }), c.on("registered", () => {
499
+ w.listeners.forEach((d) => d.onRegistered?.());
500
+ }), c.on("unregistered", () => {
501
+ w.listeners.forEach((d) => d.onUnregistered?.());
502
+ }), c.on("registrationFailed", (d) => {
503
+ w.listeners.forEach((o) => o.onRegistrationFailed?.(d?.cause));
504
+ }), c.on("newRTCSession", (d) => {
505
+ const o = d.session;
506
+ o.direction === "outgoing" && (w.listeners.forEach((r) => r.onNewSession?.(o)), o.connection && (o.connection.addEventListener("addstream", (r) => {
507
+ if (!r.streams?.length) return;
508
+ const i = document.createElement("audio");
509
+ i.srcObject = r.streams[0], i.play();
510
+ }), o.connection.addEventListener("track", (r) => {
511
+ const i = document.createElement("audio");
512
+ i.srcObject = r.streams[0], i.play();
513
+ })));
514
+ }), j = w, w;
515
+ }
516
+ function nt(v) {
517
+ const { config: R, onCallStart: y, onCallEnd: C, onStatusChange: c } = v, g = p("disconnected"), w = p(""), d = p([]), o = p(0), r = p(!1), i = p("connecting");
518
+ let b = null, u = null, x = null, S = null;
519
+ const l = (n) => {
520
+ w.value = n;
521
+ }, z = (n, L, I) => {
522
+ const h = {
523
+ id: Date.now().toString(),
524
+ number: n,
525
+ timestamp: Date.now(),
526
+ duration: L,
527
+ status: I
528
+ };
529
+ d.value = [h, ...d.value].slice(0, 50), localStorage.setItem("tbi-phone-call-history", JSON.stringify(d.value));
530
+ }, M = () => {
531
+ u && (u.terminate(), u = null);
532
+ }, H = (n) => {
533
+ if (!n.trim() || !b) return;
534
+ if (!r.value) {
535
+ console.warn("Phone is not ready yet. Please wait for registration.");
536
+ return;
537
+ }
538
+ w.value = n, y?.(n);
539
+ const I = {
540
+ eventHandlers: {
541
+ progress: () => {
542
+ g.value = "progress", c?.("progress");
543
+ },
544
+ failed: (h) => {
545
+ console.error("Call failed:", h?.cause), g.value = "failed", c?.("failed"), z(n, 0, "failed"), C?.(n, 0, "failed"), u = null, setTimeout(() => {
546
+ g.value = "disconnected", c?.("disconnected");
547
+ }, 3e3);
548
+ },
549
+ ended: () => {
550
+ g.value = "ended", c?.("ended");
551
+ const h = x ? Math.floor((Date.now() - x) / 1e3) : 0;
552
+ z(n, h, "completed"), C?.(n, h, "completed"), u = null, S && (clearInterval(S), S = null), setTimeout(() => {
553
+ g.value = "disconnected", c?.("disconnected"), x = null, o.value = 0;
554
+ }, 2e3);
555
+ },
556
+ confirmed: () => {
557
+ g.value = "confirmed", c?.("confirmed"), x = Date.now(), S = setInterval(() => {
558
+ x && (o.value = Math.floor((Date.now() - x) / 1e3));
559
+ }, 1e3);
560
+ }
561
+ },
562
+ mediaConstraints: { audio: !0, video: !1 }
563
+ };
564
+ g.value = "progress", c?.("progress");
565
+ try {
566
+ u = b.ua.call(n, I);
567
+ } catch (h) {
568
+ console.error("Failed to start call:", h), g.value = "failed", c?.("failed"), z(n, 0, "failed"), setTimeout(() => {
569
+ g.value = "disconnected", c?.("disconnected");
570
+ }, 3e3);
571
+ }
572
+ };
573
+ X(() => {
574
+ b = Ye(R), b.ua.isRegistered() ? (r.value = !0, i.value = "connected") : b.ua.isConnected() && (i.value = "connected");
575
+ const n = {
576
+ onConnecting: () => {
577
+ i.value = "connecting";
578
+ },
579
+ onConnected: () => {
580
+ i.value = "connected";
581
+ },
582
+ onDisconnected: () => {
583
+ i.value = "disconnected", r.value = !1;
584
+ },
585
+ onRegistered: () => {
586
+ r.value = !0, i.value = "connected";
587
+ },
588
+ onUnregistered: () => {
589
+ r.value = !1;
590
+ },
591
+ onRegistrationFailed: (h) => {
592
+ console.error("Registration failed:", h), r.value = !1, i.value = "failed";
593
+ },
594
+ onNewSession: (h) => {
595
+ u = h;
596
+ }
597
+ };
598
+ b.listeners.add(n), b.isStarted || (b.ua.start(), b.isStarted = !0);
599
+ const L = localStorage.getItem("tbi-phone-call-history");
600
+ if (L)
601
+ try {
602
+ d.value = JSON.parse(L);
603
+ } catch (h) {
604
+ console.error("Error loading call history", h);
605
+ }
606
+ const I = (h) => {
607
+ const q = h.detail.number;
608
+ g.value === "disconnected" && H(q);
609
+ };
610
+ window.addEventListener("StartCallEvent", I);
611
+ }), Y(() => {
612
+ S && clearInterval(S);
613
+ });
614
+ const N = {
615
+ status: D(g),
616
+ callNumber: w,
617
+ setCallNumber: l,
618
+ callHistory: D(d),
619
+ currentCallDuration: D(o),
620
+ startCall: H,
621
+ endCall: M,
622
+ isReady: D(r),
623
+ connectionStatus: D(i)
624
+ };
625
+ return ge(ne, N), N;
626
+ }
627
+ function st() {
628
+ const v = he(ne);
629
+ if (!v)
630
+ throw new Error("usePhone must be used within a component that has called usePhoneProvider");
631
+ return v;
632
+ }
633
+ function ot(v, R = {}) {
634
+ const {
635
+ onCallStart: y,
636
+ onCallEnd: C,
637
+ onStatusChange: c,
638
+ onConnectionChange: g,
639
+ persistHistory: w = !0,
640
+ historyKey: d = "tbi-phone-call-history"
641
+ } = R, o = p("disconnected"), r = p(""), i = p([]), b = p(0), u = p(!1), x = p("connecting"), S = p(null);
642
+ let l = null;
643
+ X(() => {
644
+ l = new pe(
645
+ v,
646
+ {
647
+ onStatusChange: (n) => {
648
+ o.value = n, c?.(n);
649
+ },
650
+ onConnectionChange: (n) => {
651
+ x.value = n, l && (u.value = l.state.isReady), g?.(n);
652
+ },
653
+ onCallStart: y,
654
+ onCallEnd: C,
655
+ onDurationUpdate: (n) => {
656
+ b.value = n;
657
+ },
658
+ onHistoryUpdate: (n) => {
659
+ i.value = n;
660
+ },
661
+ onRegistered: () => {
662
+ u.value = !0;
663
+ },
664
+ onUnregistered: () => {
665
+ u.value = !1;
666
+ }
667
+ },
668
+ {
669
+ persistHistory: w,
670
+ historyKey: d
671
+ }
672
+ ), l.initialize(), o.value = l.state.status, r.value = l.state.callNumber, i.value = l.state.callHistory, u.value = l.state.isReady, x.value = l.state.connectionStatus, S.value = l.ua;
673
+ }), Y(() => {
674
+ l && (l.destroy(), l = null);
675
+ });
676
+ const z = (n) => {
677
+ r.value = n, l?.setCallNumber(n);
678
+ }, M = (n) => {
679
+ l?.startCall(n);
680
+ }, H = () => {
681
+ l?.endCall();
682
+ }, N = () => {
683
+ l?.clearHistory(), i.value = [];
684
+ };
685
+ return {
686
+ status: D(o),
687
+ callNumber: r,
688
+ setCallNumber: z,
689
+ callHistory: D(i),
690
+ clearCallHistory: N,
691
+ currentCallDuration: D(b),
692
+ startCall: M,
693
+ endCall: H,
694
+ isReady: D(u),
695
+ connectionStatus: D(x),
696
+ ua: S
697
+ };
698
+ }
699
+ export {
700
+ tt as Phone,
701
+ ne as PhoneKey,
702
+ tt as default,
703
+ st as usePhone,
704
+ ot as usePhoneManager,
705
+ nt as usePhoneProvider
706
+ };