@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,3 @@
1
+ import type { PhoneProps } from '../types';
2
+ export default function Phone({ config, className, onCallStart, onCallEnd, onStatusChange, labels }: PhoneProps): import("react/jsx-runtime").JSX.Element;
3
+ //# sourceMappingURL=Phone.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Phone.d.ts","sourceRoot":"","sources":["../../src/react/Phone.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAoB,MAAM,UAAU,CAAC;AAwV7D,MAAM,CAAC,OAAO,UAAU,KAAK,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,EAAE,EAAE,UAAU,2CAW9G"}
@@ -0,0 +1,23 @@
1
+ import type { PhoneConfig, PhoneStatus, CallHistoryEntry } from '../types';
2
+ interface PhoneContextValue {
3
+ status: PhoneStatus;
4
+ callNumber: string;
5
+ setCallNumber: (number: string) => void;
6
+ callHistory: CallHistoryEntry[];
7
+ currentCallDuration: number;
8
+ startCall: (number: string) => void;
9
+ endCall: () => void;
10
+ isReady: boolean;
11
+ connectionStatus: 'connecting' | 'connected' | 'disconnected' | 'failed';
12
+ }
13
+ interface PhoneProviderProps {
14
+ config: PhoneConfig;
15
+ children: React.ReactNode;
16
+ onCallStart?: (number: string) => void;
17
+ onCallEnd?: (number: string, duration: number, status: 'completed' | 'failed') => void;
18
+ onStatusChange?: (status: PhoneStatus) => void;
19
+ }
20
+ export declare function PhoneProvider({ config, children, onCallStart, onCallEnd, onStatusChange }: PhoneProviderProps): import("react/jsx-runtime").JSX.Element;
21
+ export declare function usePhone(): PhoneContextValue;
22
+ export {};
23
+ //# sourceMappingURL=PhoneContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PhoneContext.d.ts","sourceRoot":"","sources":["../../src/react/PhoneContext.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AA0J3E,UAAU,iBAAiB;IACvB,MAAM,EAAE,WAAW,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,WAAW,EAAE,gBAAgB,EAAE,CAAC;IAChC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,gBAAgB,EAAE,YAAY,GAAG,WAAW,GAAG,cAAc,GAAG,QAAQ,CAAC;CAC5E;AAID,UAAU,kBAAkB;IACxB,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,QAAQ,KAAK,IAAI,CAAC;IACvF,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,CAAC;CAClD;AAED,wBAAgB,aAAa,CAAC,EAC1B,MAAM,EACN,QAAQ,EACR,WAAW,EACX,SAAS,EACT,cAAc,EACjB,EAAE,kBAAkB,2CAoNpB;AAED,wBAAgB,QAAQ,sBAMvB"}
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("../usePhoneManager-uj2opBKT.cjs");exports.Phone=e.Phone;exports.PhoneProvider=e.PhoneProvider;exports.default=e.Phone;exports.usePhone=e.usePhone;exports.usePhoneManager=e.usePhoneManager;
@@ -0,0 +1,7 @@
1
+ import Phone from './Phone';
2
+ export { Phone };
3
+ export { PhoneProvider, usePhone } from './PhoneContext';
4
+ export { usePhoneManager } from './usePhoneManager';
5
+ export type { UsePhoneManagerOptions, UsePhoneManagerReturn, ConnectionStatus } from './usePhoneManager';
6
+ export default Phone;
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,SAAS,CAAC;AAE5B,OAAO,EAAE,KAAK,EAAE,CAAC;AACjB,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,YAAY,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAEzG,eAAe,KAAK,CAAC"}
@@ -0,0 +1,9 @@
1
+ import { P as o } from "../usePhoneManager-OZM1GaNS.js";
2
+ import { a as s, u as P, b as n } from "../usePhoneManager-OZM1GaNS.js";
3
+ export {
4
+ o as Phone,
5
+ s as PhoneProvider,
6
+ o as default,
7
+ P as usePhone,
8
+ n as usePhoneManager
9
+ };
@@ -0,0 +1,67 @@
1
+ import type { PhoneConfig, PhoneStatus, CallHistoryEntry, ConnectionStatus } from '../types';
2
+ export type { ConnectionStatus };
3
+ export interface UsePhoneManagerOptions {
4
+ /** Callback when a call starts */
5
+ onCallStart?: (number: string) => void;
6
+ /** Callback when a call ends */
7
+ onCallEnd?: (number: string, duration: number, status: 'completed' | 'failed') => void;
8
+ /** Callback when call status changes */
9
+ onStatusChange?: (status: PhoneStatus) => void;
10
+ /** Callback when connection status changes */
11
+ onConnectionChange?: (status: ConnectionStatus) => void;
12
+ /** Enable call history persistence in localStorage */
13
+ persistHistory?: boolean;
14
+ /** localStorage key for call history */
15
+ historyKey?: string;
16
+ }
17
+ export interface UsePhoneManagerReturn {
18
+ /** Current call status */
19
+ status: PhoneStatus;
20
+ /** Current phone number being called or in the input */
21
+ callNumber: string;
22
+ /** Set the phone number */
23
+ setCallNumber: (number: string) => void;
24
+ /** Call history */
25
+ callHistory: CallHistoryEntry[];
26
+ /** Clear call history */
27
+ clearCallHistory: () => void;
28
+ /** Current call duration in seconds */
29
+ currentCallDuration: number;
30
+ /** Start a call to the given number */
31
+ startCall: (number: string) => void;
32
+ /** End the current call */
33
+ endCall: () => void;
34
+ /** Whether the phone is registered and ready to make calls */
35
+ isReady: boolean;
36
+ /** Current connection status */
37
+ connectionStatus: ConnectionStatus;
38
+ /** The raw JsSIP UA instance (for advanced usage) */
39
+ ua: any | null;
40
+ }
41
+ /**
42
+ * React hook to manage a SIP phone connection.
43
+ * This hook wraps the framework-agnostic PhoneManager class.
44
+ *
45
+ * @example
46
+ * ```tsx
47
+ * const {
48
+ * status,
49
+ * callNumber,
50
+ * setCallNumber,
51
+ * startCall,
52
+ * endCall,
53
+ * isReady,
54
+ * connectionStatus,
55
+ * } = usePhoneManager({
56
+ * websocketUrl: 'wss://sip-server.com:8989',
57
+ * sipUri: 'sip:user@domain.com',
58
+ * password: 'password',
59
+ * registrarServer: 'sip:domain.com',
60
+ * displayName: 'User',
61
+ * authorizationUser: 'user',
62
+ * });
63
+ * ```
64
+ */
65
+ export declare function usePhoneManager(config: PhoneConfig, options?: UsePhoneManagerOptions): UsePhoneManagerReturn;
66
+ export default usePhoneManager;
67
+ //# sourceMappingURL=usePhoneManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePhoneManager.d.ts","sourceRoot":"","sources":["../../src/react/usePhoneManager.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAE7F,YAAY,EAAE,gBAAgB,EAAE,CAAC;AAEjC,MAAM,WAAW,sBAAsB;IACnC,kCAAkC;IAClC,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,gCAAgC;IAChC,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,QAAQ,KAAK,IAAI,CAAC;IACvF,wCAAwC;IACxC,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,CAAC;IAC/C,8CAA8C;IAC9C,kBAAkB,CAAC,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACxD,sDAAsD;IACtD,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,wCAAwC;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,qBAAqB;IAClC,0BAA0B;IAC1B,MAAM,EAAE,WAAW,CAAC;IACpB,wDAAwD;IACxD,UAAU,EAAE,MAAM,CAAC;IACnB,2BAA2B;IAC3B,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,mBAAmB;IACnB,WAAW,EAAE,gBAAgB,EAAE,CAAC;IAChC,yBAAyB;IACzB,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,uCAAuC;IACvC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,uCAAuC;IACvC,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,2BAA2B;IAC3B,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,8DAA8D;IAC9D,OAAO,EAAE,OAAO,CAAC;IACjB,gCAAgC;IAChC,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,qDAAqD;IACrD,EAAE,EAAE,GAAG,GAAG,IAAI,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,eAAe,CAC3B,MAAM,EAAE,WAAW,EACnB,OAAO,GAAE,sBAA2B,GACrC,qBAAqB,CA0HvB;AAED,eAAe,eAAe,CAAC"}
@@ -0,0 +1,536 @@
1
+ import { jsx as t, jsxs as o, Fragment as W } from "react/jsx-runtime";
2
+ import { useState as p, useRef as j, useEffect as I, useCallback as k, createContext as q, useContext as G } from "react";
3
+ import { J as F, d as Q, c as _, f as $, P as X } from "./index-TymkBND5.js";
4
+ let z = null, B = null;
5
+ function Y(e) {
6
+ return `${e.websocketUrl}|${e.sipUri}|${e.authorizationUser}`;
7
+ }
8
+ function Z(e) {
9
+ const m = Y(e);
10
+ if (z && B === m)
11
+ return z;
12
+ if (z && B !== m) {
13
+ try {
14
+ z.ua.stop();
15
+ } catch {
16
+ }
17
+ z = null;
18
+ }
19
+ B = m;
20
+ const i = {
21
+ sockets: [new F.WebSocketInterface(e.websocketUrl)],
22
+ uri: e.sipUri,
23
+ password: e.password,
24
+ registrar_server: e.registrarServer,
25
+ display_name: e.displayName,
26
+ authorization_user: e.authorizationUser,
27
+ connection_recovery_min_interval: 2,
28
+ connection_recovery_max_interval: 30
29
+ }, a = new F.UA(i), g = document.createElement("audio");
30
+ g.autoplay = !0;
31
+ const h = {
32
+ ua: a,
33
+ audio: g,
34
+ isStarted: !1,
35
+ listeners: /* @__PURE__ */ new Set()
36
+ };
37
+ return a.on("connecting", () => {
38
+ h.listeners.forEach((r) => r.onConnecting?.());
39
+ }), a.on("connected", () => {
40
+ h.listeners.forEach((r) => r.onConnected?.());
41
+ }), a.on("disconnected", () => {
42
+ h.listeners.forEach((r) => r.onDisconnected?.());
43
+ }), a.on("registered", () => {
44
+ h.listeners.forEach((r) => r.onRegistered?.());
45
+ }), a.on("unregistered", () => {
46
+ h.listeners.forEach((r) => r.onUnregistered?.());
47
+ }), a.on("registrationFailed", (r) => {
48
+ h.listeners.forEach((l) => l.onRegistrationFailed?.(r?.cause));
49
+ }), a.on("newRTCSession", (r) => {
50
+ const l = r.session;
51
+ l.direction === "outgoing" && (h.listeners.forEach((d) => d.onNewSession?.(l)), l.connection && (l.connection.addEventListener("addstream", (d) => {
52
+ var x = document.createElement("audio");
53
+ d.streams !== void 0 && d.streams.length !== 0 && (x.srcObject = d.streams[0], x.play());
54
+ }), l.connection.addEventListener("track", (d) => {
55
+ var x = document.createElement("audio");
56
+ x.srcObject = d.streams[0], x.play();
57
+ })));
58
+ }), z = h, h;
59
+ }
60
+ function ee(e) {
61
+ e.isStarted || (e.ua.start(), e.isStarted = !0);
62
+ }
63
+ function te(e, m) {
64
+ e.listeners.add(m);
65
+ }
66
+ function ne(e, m) {
67
+ e.listeners.delete(m);
68
+ }
69
+ function re(e) {
70
+ return {
71
+ isReady: e.ua.isRegistered(),
72
+ isConnected: e.ua.isConnected()
73
+ };
74
+ }
75
+ const K = q(null);
76
+ function se({
77
+ config: e,
78
+ children: m,
79
+ onCallStart: u,
80
+ onCallEnd: i,
81
+ onStatusChange: a
82
+ }) {
83
+ const [g, h] = p(""), [r, l] = p("disconnected"), [d, x] = p(null), [P, N] = p(0), [s, M] = p([]), [b, f] = p(!1), [H, S] = p("connecting"), y = j(null), v = j(null), D = j(null);
84
+ I(() => {
85
+ v.current = d;
86
+ }, [d]), I(() => {
87
+ const n = Z(e);
88
+ D.current = n;
89
+ const C = re(n);
90
+ C.isReady ? (f(!0), S("connected")) : C.isConnected && S("connected");
91
+ const R = {
92
+ onConnecting: () => S("connecting"),
93
+ onConnected: () => S("connected"),
94
+ onDisconnected: () => {
95
+ S("disconnected"), f(!1);
96
+ },
97
+ onRegistered: () => {
98
+ f(!0), S("connected");
99
+ },
100
+ onUnregistered: () => f(!1),
101
+ onRegistrationFailed: (E) => {
102
+ console.error("Registration failed:", E), f(!1), S("failed");
103
+ },
104
+ onNewSession: (E) => {
105
+ y.current = E;
106
+ }
107
+ };
108
+ return te(n, R), ee(n), () => {
109
+ ne(n, R);
110
+ };
111
+ }, [e.websocketUrl, e.sipUri, e.password, e.registrarServer, e.displayName, e.authorizationUser]), I(() => {
112
+ a?.(r);
113
+ }, [r, a]), I(() => {
114
+ const n = localStorage.getItem("tbi-phone-call-history");
115
+ if (n)
116
+ try {
117
+ M(JSON.parse(n));
118
+ } catch (C) {
119
+ console.error("Error loading call history", C);
120
+ }
121
+ }, []), I(() => {
122
+ s.length > 0 && localStorage.setItem("tbi-phone-call-history", JSON.stringify(s));
123
+ }, [s]), I(() => {
124
+ if (r === "confirmed" && d) {
125
+ const n = setInterval(() => {
126
+ N(Math.floor((Date.now() - d) / 1e3));
127
+ }, 1e3);
128
+ return () => clearInterval(n);
129
+ } else
130
+ N(0);
131
+ }, [r, d]), I(() => {
132
+ const n = (C) => {
133
+ const R = C.detail.number;
134
+ r === "disconnected" && L(R);
135
+ };
136
+ return window.addEventListener("StartCallEvent", n), () => {
137
+ window.removeEventListener("StartCallEvent", n);
138
+ };
139
+ }, [r]);
140
+ const U = k((n, C, R) => {
141
+ const E = {
142
+ id: Date.now().toString(),
143
+ number: n,
144
+ timestamp: Date.now(),
145
+ duration: C,
146
+ status: R
147
+ };
148
+ M((w) => [E, ...w].slice(0, 50));
149
+ }, []), A = k(() => {
150
+ y.current && (y.current.terminate(), y.current = null);
151
+ }, []), L = k((n) => {
152
+ const C = D.current;
153
+ if (!n.trim() || !C) return;
154
+ if (!b) {
155
+ console.warn("Phone is not ready yet. Please wait for registration.");
156
+ return;
157
+ }
158
+ h(n), u?.(n);
159
+ const E = {
160
+ eventHandlers: {
161
+ progress: () => {
162
+ l("progress");
163
+ },
164
+ failed: (w) => {
165
+ console.error("Call failed:", w?.cause), l("failed"), U(n, 0, "failed"), i?.(n, 0, "failed"), y.current = null, setTimeout(() => l("disconnected"), 3e3);
166
+ },
167
+ ended: () => {
168
+ l("ended");
169
+ const w = v.current, V = w ? Math.floor((Date.now() - w) / 1e3) : 0;
170
+ U(n, V, "completed"), i?.(n, V, "completed"), y.current = null, setTimeout(() => {
171
+ l("disconnected"), x(null);
172
+ }, 2e3);
173
+ },
174
+ confirmed: () => {
175
+ l("confirmed"), x(Date.now());
176
+ }
177
+ },
178
+ mediaConstraints: { audio: !0, video: !1 }
179
+ };
180
+ l("progress");
181
+ try {
182
+ const w = C.ua.call(n, E);
183
+ y.current = w;
184
+ } catch (w) {
185
+ console.error("Failed to start call:", w), l("failed"), U(n, 0, "failed"), setTimeout(() => l("disconnected"), 3e3);
186
+ }
187
+ }, [U, u, i, b]), c = {
188
+ status: r,
189
+ callNumber: g,
190
+ setCallNumber: h,
191
+ callHistory: s,
192
+ currentCallDuration: P,
193
+ startCall: L,
194
+ endCall: A,
195
+ isReady: b,
196
+ connectionStatus: H
197
+ };
198
+ return /* @__PURE__ */ t(K.Provider, { value: c, children: m });
199
+ }
200
+ function oe() {
201
+ const e = G(K);
202
+ if (!e)
203
+ throw new Error("usePhone must be used within a PhoneProvider");
204
+ return e;
205
+ }
206
+ const O = ({ className: e }) => /* @__PURE__ */ t("svg", { className: e, viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ t("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" }) }), ae = ({ className: e }) => /* @__PURE__ */ t("svg", { className: e, viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ t("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" }) }), le = ({ className: e }) => /* @__PURE__ */ t("svg", { className: e, viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ t("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" }) }), T = ({ className: e }) => /* @__PURE__ */ t("svg", { className: e, viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ t("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" }) }), J = ({ className: e }) => /* @__PURE__ */ t("svg", { className: e, viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ t("path", { 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" }) }), ce = ({ className: e }) => /* @__PURE__ */ o("svg", { className: e, viewBox: "0 0 24 24", fill: "currentColor", children: [
207
+ /* @__PURE__ */ t("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" }),
208
+ /* @__PURE__ */ t("path", { d: "M16 3l-5 5-2-2-1.5 1.5L11 11l6.5-6.5z" })
209
+ ] }), ie = ({ className: e }) => /* @__PURE__ */ o("svg", { className: e, viewBox: "0 0 24 24", fill: "currentColor", children: [
210
+ /* @__PURE__ */ t("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" }),
211
+ /* @__PURE__ */ t("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" })
212
+ ] }), de = ({ className: e }) => /* @__PURE__ */ t("svg", { className: e, viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ t("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" }) }), ue = ({ className: e }) => /* @__PURE__ */ t("svg", { className: e, viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ t("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" }) });
213
+ function he({ className: e, labels: m }) {
214
+ const {
215
+ status: u,
216
+ callNumber: i,
217
+ setCallNumber: a,
218
+ callHistory: g,
219
+ currentCallDuration: h,
220
+ startCall: r,
221
+ endCall: l,
222
+ isReady: d,
223
+ connectionStatus: x
224
+ } = oe(), [P, N] = p(!1), s = { ...Q, ...m }, b = (() => {
225
+ switch (u) {
226
+ case "progress":
227
+ return { text: `${s.calling}...`, color: "text-yellow-500", Icon: ae };
228
+ case "confirmed":
229
+ return { text: `${s.inCall} - ${$(h)}`, color: "text-green-500", Icon: le };
230
+ case "failed":
231
+ return { text: s.callEnded, color: "text-red-500", Icon: J };
232
+ case "ended":
233
+ return { text: s.callEnded, color: "text-gray-500", Icon: T };
234
+ default:
235
+ return { text: s.inactive, color: "text-gray-300", Icon: O };
236
+ }
237
+ })();
238
+ return /* @__PURE__ */ o("div", { className: _(
239
+ "tbi-phone w-full max-w-md mx-auto bg-white rounded-2xl shadow-lg border border-gray-200 p-2",
240
+ e
241
+ ), children: [
242
+ u === "disconnected" && /* @__PURE__ */ o("div", { className: "flex gap-2 items-center", children: [
243
+ /* @__PURE__ */ t(
244
+ "button",
245
+ {
246
+ onClick: () => N(!0),
247
+ className: "h-8 w-8 flex items-center justify-center rounded-xl border border-gray-200 hover:bg-gray-50 transition-colors",
248
+ type: "button",
249
+ children: /* @__PURE__ */ t(de, { className: "w-4 h-4" })
250
+ }
251
+ ),
252
+ /* @__PURE__ */ t(
253
+ "input",
254
+ {
255
+ type: "text",
256
+ value: i,
257
+ onChange: (f) => a(f.target.value),
258
+ onKeyDown: (f) => {
259
+ f.key === "Enter" && r(i);
260
+ },
261
+ placeholder: s.placeholder,
262
+ className: "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"
263
+ }
264
+ ),
265
+ /* @__PURE__ */ t(
266
+ "button",
267
+ {
268
+ onClick: () => r(i),
269
+ disabled: i.length < 9 || !d,
270
+ className: "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",
271
+ type: "button",
272
+ title: d ? "Call" : "Connecting...",
273
+ children: x === "connecting" ? /* @__PURE__ */ t("div", { className: "w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin" }) : /* @__PURE__ */ t(O, { className: "w-4 h-4" })
274
+ }
275
+ )
276
+ ] }),
277
+ u === "progress" && /* @__PURE__ */ o("div", { className: "flex flex-col items-center gap-3 py-6", children: [
278
+ /* @__PURE__ */ o("div", { className: "relative", children: [
279
+ /* @__PURE__ */ t(b.Icon, { className: "w-12 h-12 text-yellow-500 animate-pulse" }),
280
+ /* @__PURE__ */ t("div", { className: "absolute inset-0 rounded-full border-4 border-yellow-500/30 animate-ping" })
281
+ ] }),
282
+ /* @__PURE__ */ o("div", { className: "text-center", children: [
283
+ /* @__PURE__ */ o("p", { className: "text-base font-semibold", children: [
284
+ s.calling,
285
+ " ",
286
+ i
287
+ ] }),
288
+ /* @__PURE__ */ t("p", { className: "text-sm text-gray-500", children: s.waitingResponse })
289
+ ] }),
290
+ /* @__PURE__ */ o(
291
+ "button",
292
+ {
293
+ onClick: l,
294
+ className: "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",
295
+ type: "button",
296
+ children: [
297
+ /* @__PURE__ */ t(T, { className: "w-4 h-4" }),
298
+ s.cancel
299
+ ]
300
+ }
301
+ )
302
+ ] }),
303
+ u === "confirmed" && /* @__PURE__ */ o("div", { className: "flex flex-col items-center gap-4 py-6", children: [
304
+ /* @__PURE__ */ o("div", { className: "relative", children: [
305
+ /* @__PURE__ */ t(b.Icon, { className: "w-12 h-12 text-green-500" }),
306
+ /* @__PURE__ */ t("div", { className: "absolute inset-0 rounded-full bg-green-500/20 animate-pulse" })
307
+ ] }),
308
+ /* @__PURE__ */ o("div", { className: "text-center space-y-1", children: [
309
+ /* @__PURE__ */ t("p", { className: "text-xl font-bold", children: i }),
310
+ /* @__PURE__ */ t("p", { className: "text-2xl font-mono text-green-600 tabular-nums", children: $(h) })
311
+ ] }),
312
+ /* @__PURE__ */ o(
313
+ "button",
314
+ {
315
+ onClick: l,
316
+ className: "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",
317
+ type: "button",
318
+ children: [
319
+ /* @__PURE__ */ t(T, { className: "w-4 h-4" }),
320
+ s.hangUp
321
+ ]
322
+ }
323
+ )
324
+ ] }),
325
+ (u === "failed" || u === "ended") && /* @__PURE__ */ o("div", { className: "flex flex-col items-center gap-3 py-6", children: [
326
+ /* @__PURE__ */ t(
327
+ b.Icon,
328
+ {
329
+ className: _(
330
+ "w-12 h-12",
331
+ u === "failed" ? "text-red-500" : "text-gray-500"
332
+ )
333
+ }
334
+ ),
335
+ /* @__PURE__ */ t("div", { className: "text-center", children: /* @__PURE__ */ t("p", { className: "text-base font-semibold", children: b.text }) })
336
+ ] }),
337
+ P && /* @__PURE__ */ o("div", { className: "fixed inset-0 z-50 flex", children: [
338
+ /* @__PURE__ */ t(
339
+ "div",
340
+ {
341
+ className: "fixed inset-0 bg-black/50",
342
+ onClick: () => N(!1)
343
+ }
344
+ ),
345
+ /* @__PURE__ */ t("div", { className: "fixed right-0 top-0 h-full w-full max-w-md bg-white shadow-xl", style: { backgroundColor: "white" }, children: /* @__PURE__ */ o("div", { className: "flex flex-col h-full", children: [
346
+ /* @__PURE__ */ o("div", { className: "flex items-center justify-between p-4 border-b", children: [
347
+ /* @__PURE__ */ o("div", { children: [
348
+ /* @__PURE__ */ t("h2", { className: "text-lg font-semibold", children: s.callHistory }),
349
+ /* @__PURE__ */ t("p", { className: "text-sm text-gray-500", children: g.length === 0 ? s.noCallsRegistered : `${g.length} ${s.callsRegistered}` })
350
+ ] }),
351
+ /* @__PURE__ */ t(
352
+ "button",
353
+ {
354
+ onClick: () => N(!1),
355
+ className: "h-8 w-8 flex items-center justify-center rounded-lg hover:bg-gray-100 transition-colors",
356
+ type: "button",
357
+ children: /* @__PURE__ */ t(ue, { className: "w-5 h-5" })
358
+ }
359
+ )
360
+ ] }),
361
+ /* @__PURE__ */ t("div", { className: "flex-1 overflow-y-auto p-4", children: g.length === 0 ? /* @__PURE__ */ o("div", { className: "text-center py-12 text-gray-500", children: [
362
+ /* @__PURE__ */ t(T, { className: "w-12 h-12 mx-auto mb-2 opacity-50" }),
363
+ /* @__PURE__ */ t("p", { children: s.noCalls })
364
+ ] }) : /* @__PURE__ */ t("div", { className: "space-y-2", children: g.map((f, H) => /* @__PURE__ */ t(
365
+ me,
366
+ {
367
+ entry: f,
368
+ index: H,
369
+ onCall: () => {
370
+ a(f.number), N(!1), r(f.number);
371
+ }
372
+ },
373
+ f.id
374
+ )) }) })
375
+ ] }) })
376
+ ] })
377
+ ] });
378
+ }
379
+ function me({
380
+ entry: e,
381
+ index: m,
382
+ onCall: u
383
+ }) {
384
+ const i = () => {
385
+ switch (e.status) {
386
+ case "completed":
387
+ return /* @__PURE__ */ t(ce, { className: "w-4 h-4 text-green-600" });
388
+ case "failed":
389
+ return /* @__PURE__ */ t(ie, { className: "w-4 h-4 text-red-600" });
390
+ case "missed":
391
+ return /* @__PURE__ */ t(J, { className: "w-4 h-4 text-yellow-600" });
392
+ }
393
+ }, a = () => {
394
+ switch (e.status) {
395
+ case "completed":
396
+ return "bg-green-100";
397
+ case "failed":
398
+ return "bg-red-100";
399
+ case "missed":
400
+ return "bg-yellow-100";
401
+ }
402
+ };
403
+ return /* @__PURE__ */ o(
404
+ "div",
405
+ {
406
+ className: "flex items-center gap-3 p-3 rounded-lg hover:bg-gray-50 transition-colors duration-200",
407
+ style: { animationDelay: `${m * 30}ms` },
408
+ children: [
409
+ /* @__PURE__ */ t("div", { className: _(
410
+ "w-9 h-9 rounded-full flex items-center justify-center shrink-0",
411
+ a()
412
+ ), children: i() }),
413
+ /* @__PURE__ */ o("div", { className: "flex-1 min-w-0", children: [
414
+ /* @__PURE__ */ t("p", { className: "font-medium text-sm truncate", children: e.number }),
415
+ /* @__PURE__ */ o("div", { className: "flex items-center gap-2 text-xs text-gray-500", children: [
416
+ /* @__PURE__ */ t("span", { children: new Date(e.timestamp).toLocaleString("es-ES", {
417
+ day: "2-digit",
418
+ month: "2-digit",
419
+ hour: "2-digit",
420
+ minute: "2-digit"
421
+ }) }),
422
+ e.duration > 0 && /* @__PURE__ */ o(W, { children: [
423
+ /* @__PURE__ */ t("span", { children: "•" }),
424
+ /* @__PURE__ */ t("span", { className: "font-mono tabular-nums", children: $(e.duration) })
425
+ ] })
426
+ ] })
427
+ ] }),
428
+ /* @__PURE__ */ t(
429
+ "button",
430
+ {
431
+ onClick: u,
432
+ className: "h-8 w-8 flex items-center justify-center shrink-0 rounded-lg hover:bg-gray-100 transition-colors",
433
+ type: "button",
434
+ children: /* @__PURE__ */ t(O, { className: "w-4 h-4" })
435
+ }
436
+ )
437
+ ]
438
+ }
439
+ );
440
+ }
441
+ function xe({ config: e, className: m, onCallStart: u, onCallEnd: i, onStatusChange: a, labels: g }) {
442
+ return /* @__PURE__ */ t(
443
+ se,
444
+ {
445
+ config: e,
446
+ onCallStart: u,
447
+ onCallEnd: i,
448
+ onStatusChange: a,
449
+ children: /* @__PURE__ */ t(he, { className: m, labels: g })
450
+ }
451
+ );
452
+ }
453
+ function ve(e, m = {}) {
454
+ const {
455
+ onCallStart: u,
456
+ onCallEnd: i,
457
+ onStatusChange: a,
458
+ onConnectionChange: g,
459
+ persistHistory: h = !0,
460
+ historyKey: r = "tbi-phone-call-history"
461
+ } = m, [l, d] = p("disconnected"), [x, P] = p(""), [N, s] = p([]), [M, b] = p(0), [f, H] = p(!1), [S, y] = p("connecting"), v = j(null);
462
+ I(() => {
463
+ const c = new X(
464
+ e,
465
+ {
466
+ onStatusChange: (n) => {
467
+ d(n), a?.(n);
468
+ },
469
+ onConnectionChange: (n) => {
470
+ y(n), (n === "connected" || n === "disconnected" || n === "failed") && H(c.state.isReady), g?.(n);
471
+ },
472
+ onCallStart: u,
473
+ onCallEnd: i,
474
+ onDurationUpdate: b,
475
+ onHistoryUpdate: s,
476
+ onRegistered: () => H(!0),
477
+ onUnregistered: () => H(!1)
478
+ },
479
+ {
480
+ persistHistory: h,
481
+ historyKey: r
482
+ }
483
+ );
484
+ return c.initialize(), v.current = c, d(c.state.status), P(c.state.callNumber), s(c.state.callHistory), H(c.state.isReady), y(c.state.connectionStatus), () => {
485
+ c.destroy(), v.current = null;
486
+ };
487
+ }, [
488
+ e.websocketUrl,
489
+ e.sipUri,
490
+ e.password,
491
+ e.registrarServer,
492
+ e.displayName,
493
+ e.authorizationUser,
494
+ h,
495
+ r
496
+ ]), I(() => {
497
+ v.current && v.current.setEvents({
498
+ onCallStart: u,
499
+ onCallEnd: i,
500
+ onStatusChange: (c) => {
501
+ d(c), a?.(c);
502
+ },
503
+ onConnectionChange: (c) => {
504
+ y(c), g?.(c);
505
+ }
506
+ });
507
+ }, [u, i, a, g]);
508
+ const D = k((c) => {
509
+ P(c), v.current?.setCallNumber(c);
510
+ }, []), U = k((c) => {
511
+ v.current?.startCall(c);
512
+ }, []), A = k(() => {
513
+ v.current?.endCall();
514
+ }, []), L = k(() => {
515
+ v.current?.clearHistory(), s([]);
516
+ }, []);
517
+ return {
518
+ status: l,
519
+ callNumber: x,
520
+ setCallNumber: D,
521
+ callHistory: N,
522
+ clearCallHistory: L,
523
+ currentCallDuration: M,
524
+ startCall: U,
525
+ endCall: A,
526
+ isReady: f,
527
+ connectionStatus: S,
528
+ ua: v.current?.ua ?? null
529
+ };
530
+ }
531
+ export {
532
+ xe as P,
533
+ se as a,
534
+ ve as b,
535
+ oe as u
536
+ };