callix-dialer-widget 2.6.0 → 2.7.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/WIDGET-README.md +22 -10
- package/dist-widget/callix-dialer.css +1 -1
- package/dist-widget/callix-dialer.es.js +693 -100
- package/dist-widget/callix-dialer.es.js.map +1 -1
- package/dist-widget/callix-dialer.umd.js +1 -1
- package/dist-widget/callix-dialer.umd.js.map +1 -1
- package/package.json +1 -1
|
@@ -6,7 +6,7 @@ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read fr
|
|
|
6
6
|
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
7
7
|
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
|
|
8
8
|
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
|
|
9
|
-
import React, { createContext, useMemo,
|
|
9
|
+
import React, { createContext, useMemo, useRef, useEffect, useSyncExternalStore, useCallback, useContext, useState, forwardRef, useLayoutEffect, useId, useImperativeHandle, StrictMode } from "react";
|
|
10
10
|
import require$$0$2, { createPortal } from "react-dom";
|
|
11
11
|
var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {};
|
|
12
12
|
function getAugmentedNamespace(n) {
|
|
@@ -52376,6 +52376,8 @@ function FloatingDialer({
|
|
|
52376
52376
|
sessionStatus = null,
|
|
52377
52377
|
loginConfirmation = null,
|
|
52378
52378
|
onCancelLoginConfirmation,
|
|
52379
|
+
onTakeOverSession,
|
|
52380
|
+
onLogoutAllTabs,
|
|
52379
52381
|
variant = "default",
|
|
52380
52382
|
portalTarget = null
|
|
52381
52383
|
}) {
|
|
@@ -52728,7 +52730,9 @@ function FloatingDialer({
|
|
|
52728
52730
|
error: sessionError,
|
|
52729
52731
|
statusMessage: sessionStatus,
|
|
52730
52732
|
confirmation: loginConfirmation,
|
|
52731
|
-
onCancelConfirmation: onCancelLoginConfirmation
|
|
52733
|
+
onCancelConfirmation: onCancelLoginConfirmation,
|
|
52734
|
+
onTakeOver: onTakeOverSession,
|
|
52735
|
+
onLogoutAll: onLogoutAllTabs
|
|
52732
52736
|
}
|
|
52733
52737
|
);
|
|
52734
52738
|
if (isMiniMode) {
|
|
@@ -52864,7 +52868,7 @@ function FloatingDialer({
|
|
|
52864
52868
|
}
|
|
52865
52869
|
);
|
|
52866
52870
|
}
|
|
52867
|
-
function LoginForm({ defaultValue, onSubmit, isLoading, error: error2, statusMessage, confirmation, onCancelConfirmation }) {
|
|
52871
|
+
function LoginForm({ defaultValue, onSubmit, isLoading, error: error2, statusMessage, confirmation, onCancelConfirmation, onTakeOver, onLogoutAll }) {
|
|
52868
52872
|
const [value, setValue] = useState(defaultValue);
|
|
52869
52873
|
const [touched, setTouched] = useState(false);
|
|
52870
52874
|
useEffect(() => {
|
|
@@ -52895,8 +52899,41 @@ function LoginForm({ defaultValue, onSubmit, isLoading, error: error2, statusMes
|
|
|
52895
52899
|
}
|
|
52896
52900
|
);
|
|
52897
52901
|
}
|
|
52902
|
+
if (confirmation == null ? void 0 : confirmation.elsewhere) {
|
|
52903
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: tw`space-y-4`, "data-login-state": "elsewhere", children: [
|
|
52904
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: tw`space-y-2 text-center`, children: [
|
|
52905
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: tw`text-[11px] font-semibold uppercase tracking-wide text-slate-500`, children: "Discador ativo em outra aba" }),
|
|
52906
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: tw`inline-flex items-center gap-2 rounded-full border border-slate-200 bg-slate-50 px-3 py-1 text-sm font-semibold text-slate-800`, children: [
|
|
52907
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(FiUser, { className: tw`text-primary` }),
|
|
52908
|
+
confirmation.username
|
|
52909
|
+
] })
|
|
52910
|
+
] }),
|
|
52911
|
+
error2 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: tw`text-center text-xs text-red-500`, children: error2 }),
|
|
52912
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
52913
|
+
"button",
|
|
52914
|
+
{
|
|
52915
|
+
type: "button",
|
|
52916
|
+
id: "takeOverBtn",
|
|
52917
|
+
onClick: () => onTakeOver == null ? void 0 : onTakeOver(),
|
|
52918
|
+
className: tw`flex w-full items-center justify-center gap-2 rounded-xl bg-primary px-4 py-2 text-white shadow-lg transition hover:bg-primaryDark`,
|
|
52919
|
+
children: "Usar o discador nesta aba"
|
|
52920
|
+
}
|
|
52921
|
+
),
|
|
52922
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
52923
|
+
"button",
|
|
52924
|
+
{
|
|
52925
|
+
type: "button",
|
|
52926
|
+
id: "logoutAllBtn",
|
|
52927
|
+
onClick: () => onLogoutAll == null ? void 0 : onLogoutAll(),
|
|
52928
|
+
className: tw`w-full text-center text-xs font-semibold text-red-500 transition hover:text-red-600`,
|
|
52929
|
+
children: "Sair em todas as abas"
|
|
52930
|
+
}
|
|
52931
|
+
),
|
|
52932
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: tw`text-center text-[11px] text-slate-400`, children: "O Callix aceita uma conexão por usuário: você já está conectado em outra aba deste navegador e pode continuar por lá." })
|
|
52933
|
+
] });
|
|
52934
|
+
}
|
|
52898
52935
|
if (confirmation) {
|
|
52899
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: tw`space-y-4`, children: [
|
|
52936
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: tw`space-y-4`, "data-login-state": "choose", children: [
|
|
52900
52937
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: tw`space-y-2 text-center`, children: [
|
|
52901
52938
|
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: tw`text-[11px] font-semibold uppercase tracking-wide text-slate-500`, children: "Entrar como" }),
|
|
52902
52939
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: tw`inline-flex items-center gap-2 rounded-full border border-slate-200 bg-slate-50 px-3 py-1 text-sm font-semibold text-slate-800`, children: [
|
|
@@ -52905,10 +52942,12 @@ function LoginForm({ defaultValue, onSubmit, isLoading, error: error2, statusMes
|
|
|
52905
52942
|
] })
|
|
52906
52943
|
] }),
|
|
52907
52944
|
error2 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: tw`text-center text-xs text-red-500`, children: error2 }),
|
|
52945
|
+
!error2 && confirmation.note && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: tw`text-center text-xs text-slate-500`, children: confirmation.note }),
|
|
52908
52946
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
52909
52947
|
"button",
|
|
52910
52948
|
{
|
|
52911
52949
|
type: "button",
|
|
52950
|
+
id: "loginConfirmBtn",
|
|
52912
52951
|
onClick: () => void onSubmit(confirmation.username),
|
|
52913
52952
|
className: tw`flex w-full items-center justify-center gap-2 rounded-xl bg-primary px-4 py-2 text-white shadow-lg transition hover:bg-primaryDark`,
|
|
52914
52953
|
children: "Entrar"
|
|
@@ -52923,7 +52962,7 @@ function LoginForm({ defaultValue, onSubmit, isLoading, error: error2, statusMes
|
|
|
52923
52962
|
children: "Usar outro usuário"
|
|
52924
52963
|
}
|
|
52925
52964
|
),
|
|
52926
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: tw`text-center text-[11px] text-slate-400`, children: "
|
|
52965
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: tw`text-center text-[11px] text-slate-400`, children: "Ao entrar, todas as abas abertas passam a usar o discador. Vai usar o Callix web? Então não entre aqui: nada é conectado sem a sua confirmação." })
|
|
52927
52966
|
] });
|
|
52928
52967
|
}
|
|
52929
52968
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("form", { className: tw`space-y-4`, onSubmit: handleSubmit, children: [
|
|
@@ -58427,6 +58466,8 @@ function MobileDialerLogin({
|
|
|
58427
58466
|
sessionStatus,
|
|
58428
58467
|
loginConfirmation,
|
|
58429
58468
|
onCancelLoginConfirmation,
|
|
58469
|
+
onTakeOverSession,
|
|
58470
|
+
onLogoutAllTabs,
|
|
58430
58471
|
density
|
|
58431
58472
|
}) {
|
|
58432
58473
|
const [loginInput, setLoginInput] = useState(username ?? "");
|
|
@@ -58463,19 +58504,33 @@ function MobileDialerLogin({
|
|
|
58463
58504
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "login-spinner", "aria-hidden": "true" }),
|
|
58464
58505
|
loadingUser && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "login-loading-user", children: loadingUser }),
|
|
58465
58506
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "login-status", children: sessionStatus || "Conectando..." })
|
|
58466
|
-
] }) : showConfirmation && loginConfirmation ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "login-confirm", children: [
|
|
58507
|
+
] }) : showConfirmation && loginConfirmation ? loginConfirmation.elsewhere ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "login-confirm", "data-login-state": "elsewhere", children: [
|
|
58508
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "login-confirm-label", children: "Discador ativo em outra aba" }),
|
|
58509
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "login-user-chip", children: [
|
|
58510
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("i", { className: "fas fa-user-check", "aria-hidden": "true" }),
|
|
58511
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: loginConfirmation.username })
|
|
58512
|
+
] }),
|
|
58513
|
+
sessionError && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "input-error", children: sessionError }),
|
|
58514
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("button", { type: "button", className: "login-confirm-btn login-confirm-btn-blue", id: "takeOverBtn", onClick: () => onTakeOverSession == null ? void 0 : onTakeOverSession(), children: [
|
|
58515
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("i", { className: "fas fa-arrow-down", "aria-hidden": "true" }),
|
|
58516
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Usar o discador nesta aba" })
|
|
58517
|
+
] }),
|
|
58518
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "login-secondary-btn login-secondary-danger", id: "logoutAllBtn", onClick: () => onLogoutAllTabs == null ? void 0 : onLogoutAllTabs(), children: "Sair em todas as abas" }),
|
|
58519
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "login-hint", children: "O Callix aceita uma conexão por usuário: você já está conectado em outra aba deste navegador e pode continuar por lá." })
|
|
58520
|
+
] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "login-confirm", "data-login-state": "choose", children: [
|
|
58467
58521
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "login-confirm-label", children: "Entrar como" }),
|
|
58468
58522
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "login-user-chip", children: [
|
|
58469
58523
|
/* @__PURE__ */ jsxRuntimeExports.jsx("i", { className: "fas fa-user", "aria-hidden": "true" }),
|
|
58470
58524
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: loginConfirmation.username })
|
|
58471
58525
|
] }),
|
|
58472
58526
|
sessionError && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "input-error", children: sessionError }),
|
|
58473
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
58527
|
+
!sessionError && loginConfirmation.note && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "login-note", children: loginConfirmation.note }),
|
|
58528
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("button", { type: "button", className: "login-confirm-btn", id: "loginConfirmBtn", onClick: () => void submitLogin(loginConfirmation.username), children: [
|
|
58474
58529
|
/* @__PURE__ */ jsxRuntimeExports.jsx("i", { className: "fas fa-sign-in-alt", "aria-hidden": "true" }),
|
|
58475
58530
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Entrar" })
|
|
58476
58531
|
] }),
|
|
58477
58532
|
!loginConfirmation.locked && onCancelLoginConfirmation && /* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "login-secondary-btn", onClick: onCancelLoginConfirmation, children: "Usar outro usuário" }),
|
|
58478
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "login-hint", children: "
|
|
58533
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "login-hint", children: "Ao entrar, todas as abas abertas passam a usar o discador. Vai usar o Callix web? Então não entre aqui: nada é conectado sem a sua confirmação." })
|
|
58479
58534
|
] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
58480
58535
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "phone-number-display", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
58481
58536
|
"input",
|
|
@@ -58568,6 +58623,7 @@ Gostaríamos de fazer um *diagnóstico gratuito* para te apresentar os valores r
|
|
|
58568
58623
|
}
|
|
58569
58624
|
function AuthenticatedMobileDialer({
|
|
58570
58625
|
username,
|
|
58626
|
+
onLogout,
|
|
58571
58627
|
showClientInfoModal = false,
|
|
58572
58628
|
density
|
|
58573
58629
|
}) {
|
|
@@ -59334,13 +59390,30 @@ function AuthenticatedMobileDialer({
|
|
|
59334
59390
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "pause-timer", children: pauseDurationLabel })
|
|
59335
59391
|
] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "status-text", children: statusBadgeText })
|
|
59336
59392
|
] }) }),
|
|
59337
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
59338
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
59339
|
-
|
|
59340
|
-
|
|
59341
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
59342
|
-
|
|
59343
|
-
|
|
59393
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "status-actions", children: [
|
|
59394
|
+
isOnBreak ? /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { className: "resume-btn", id: "resumeBtn", onClick: handleGoOffBreak, children: [
|
|
59395
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("i", { className: "fas fa-play" }),
|
|
59396
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Voltar" })
|
|
59397
|
+
] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { className: "pause-btn", id: "pauseBtn", onClick: () => setIsPauseModalOpen(true), children: [
|
|
59398
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("i", { className: "fas fa-pause" }),
|
|
59399
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Pausa" })
|
|
59400
|
+
] }),
|
|
59401
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
59402
|
+
"button",
|
|
59403
|
+
{
|
|
59404
|
+
type: "button",
|
|
59405
|
+
className: "logout-btn",
|
|
59406
|
+
id: "logoutBtn",
|
|
59407
|
+
title: "Sair do discador (todas as abas)",
|
|
59408
|
+
"aria-label": "Sair do discador",
|
|
59409
|
+
onClick: () => {
|
|
59410
|
+
if (typeof window !== "undefined" && !window.confirm("Sair do discador em todas as abas?")) return;
|
|
59411
|
+
onLogout();
|
|
59412
|
+
},
|
|
59413
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx("i", { className: "fas fa-right-from-bracket" })
|
|
59414
|
+
}
|
|
59415
|
+
)
|
|
59416
|
+
] })
|
|
59344
59417
|
] }),
|
|
59345
59418
|
/* @__PURE__ */ jsxRuntimeExports.jsx(DialerNoticeBanner, { notice: dialerNotice, onDismiss: dismissDialerNotice, onRecheck: () => void recheckDevices(), onHeightChange: setNoticeHeight }),
|
|
59346
59419
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "phone-number-display", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
@@ -60176,6 +60249,206 @@ function AuthenticatedMiniDialer({
|
|
|
60176
60249
|
)
|
|
60177
60250
|
] });
|
|
60178
60251
|
}
|
|
60252
|
+
const PROBE_TIMEOUT_MS = 600;
|
|
60253
|
+
const TAKEOVER_GRACE_MS = 3e3;
|
|
60254
|
+
const TAKEOVER_JITTER_MS = 600;
|
|
60255
|
+
const LEADER_HEARTBEAT_MS = 3e3;
|
|
60256
|
+
const LEADER_STALE_MS = 9e3;
|
|
60257
|
+
function channelName(username) {
|
|
60258
|
+
return `callix-dialer:${username.trim().toLowerCase()}`;
|
|
60259
|
+
}
|
|
60260
|
+
function leaderKey(username) {
|
|
60261
|
+
return `callix_dialer_${username}_leader`;
|
|
60262
|
+
}
|
|
60263
|
+
const TAB_ROLE_KEY = "callix_dialer_tab_role";
|
|
60264
|
+
const BUS_FALLBACK_SUFFIX = "_bus";
|
|
60265
|
+
function newTabId() {
|
|
60266
|
+
const cryptoApi = typeof globalThis.crypto !== "undefined" ? globalThis.crypto : void 0;
|
|
60267
|
+
if (cryptoApi && "randomUUID" in cryptoApi) return cryptoApi.randomUUID().slice(0, 8);
|
|
60268
|
+
return Math.random().toString(36).slice(2, 10);
|
|
60269
|
+
}
|
|
60270
|
+
function defaultChannelFactory(name) {
|
|
60271
|
+
if (typeof BroadcastChannel === "undefined") return null;
|
|
60272
|
+
try {
|
|
60273
|
+
return new BroadcastChannel(name);
|
|
60274
|
+
} catch {
|
|
60275
|
+
return null;
|
|
60276
|
+
}
|
|
60277
|
+
}
|
|
60278
|
+
function defaultStorage() {
|
|
60279
|
+
try {
|
|
60280
|
+
return typeof localStorage !== "undefined" ? localStorage : null;
|
|
60281
|
+
} catch {
|
|
60282
|
+
return null;
|
|
60283
|
+
}
|
|
60284
|
+
}
|
|
60285
|
+
class DialerTabBus {
|
|
60286
|
+
constructor(options) {
|
|
60287
|
+
this.listeners = /* @__PURE__ */ new Set();
|
|
60288
|
+
this.storageListener = null;
|
|
60289
|
+
this.closed = false;
|
|
60290
|
+
this.username = options.username;
|
|
60291
|
+
this.tabId = options.tabId ?? newTabId();
|
|
60292
|
+
this.status = options.status;
|
|
60293
|
+
this.storage = options.storage === void 0 ? defaultStorage() : options.storage;
|
|
60294
|
+
const factory = options.channelFactory ?? defaultChannelFactory;
|
|
60295
|
+
this.channel = factory(channelName(this.username));
|
|
60296
|
+
if (this.channel) {
|
|
60297
|
+
this.channel.onmessage = (event) => this.receive(event.data);
|
|
60298
|
+
} else if (typeof window !== "undefined" && this.storage) {
|
|
60299
|
+
const key = this.fallbackKey();
|
|
60300
|
+
this.storageListener = (event) => {
|
|
60301
|
+
if (event.key !== key || !event.newValue) return;
|
|
60302
|
+
try {
|
|
60303
|
+
const parsed = JSON.parse(event.newValue);
|
|
60304
|
+
this.receive(parsed.message);
|
|
60305
|
+
} catch {
|
|
60306
|
+
}
|
|
60307
|
+
};
|
|
60308
|
+
window.addEventListener("storage", this.storageListener);
|
|
60309
|
+
}
|
|
60310
|
+
}
|
|
60311
|
+
fallbackKey() {
|
|
60312
|
+
return `callix_dialer_${this.username}${BUS_FALLBACK_SUFFIX}`;
|
|
60313
|
+
}
|
|
60314
|
+
on(listener) {
|
|
60315
|
+
this.listeners.add(listener);
|
|
60316
|
+
return () => {
|
|
60317
|
+
this.listeners.delete(listener);
|
|
60318
|
+
};
|
|
60319
|
+
}
|
|
60320
|
+
post(message) {
|
|
60321
|
+
if (this.closed) return;
|
|
60322
|
+
const full = { ...message, from: this.tabId };
|
|
60323
|
+
if (this.channel) {
|
|
60324
|
+
try {
|
|
60325
|
+
this.channel.postMessage(full);
|
|
60326
|
+
} catch {
|
|
60327
|
+
}
|
|
60328
|
+
return;
|
|
60329
|
+
}
|
|
60330
|
+
if (this.storage) {
|
|
60331
|
+
try {
|
|
60332
|
+
this.storage.setItem(this.fallbackKey(), JSON.stringify({ nonce: Math.random(), at: Date.now(), message: full }));
|
|
60333
|
+
} catch {
|
|
60334
|
+
}
|
|
60335
|
+
}
|
|
60336
|
+
}
|
|
60337
|
+
receive(data) {
|
|
60338
|
+
if (this.closed || !data || typeof data !== "object") return;
|
|
60339
|
+
const message = data;
|
|
60340
|
+
if (typeof message.type !== "string" || typeof message.from !== "string" || message.from === this.tabId) return;
|
|
60341
|
+
if (message.type === "ping") {
|
|
60342
|
+
const status = this.status();
|
|
60343
|
+
this.post({ type: "pong", role: status.role, authenticated: status.authenticated });
|
|
60344
|
+
}
|
|
60345
|
+
for (const listener of this.listeners) listener(message);
|
|
60346
|
+
}
|
|
60347
|
+
/** pergunta quem está aí; devolve as abas que responderam dentro do prazo */
|
|
60348
|
+
probe(timeoutMs = PROBE_TIMEOUT_MS) {
|
|
60349
|
+
return new Promise((resolve) => {
|
|
60350
|
+
const found = /* @__PURE__ */ new Map();
|
|
60351
|
+
const off = this.on((message) => {
|
|
60352
|
+
if (message.type === "pong") found.set(message.from, { tabId: message.from, role: message.role, authenticated: message.authenticated });
|
|
60353
|
+
});
|
|
60354
|
+
this.post({ type: "ping" });
|
|
60355
|
+
setTimeout(() => {
|
|
60356
|
+
off();
|
|
60357
|
+
resolve([...found.values()]);
|
|
60358
|
+
}, timeoutMs);
|
|
60359
|
+
});
|
|
60360
|
+
}
|
|
60361
|
+
close() {
|
|
60362
|
+
this.closed = true;
|
|
60363
|
+
this.listeners.clear();
|
|
60364
|
+
if (this.channel) {
|
|
60365
|
+
this.channel.onmessage = null;
|
|
60366
|
+
try {
|
|
60367
|
+
this.channel.close();
|
|
60368
|
+
} catch {
|
|
60369
|
+
}
|
|
60370
|
+
}
|
|
60371
|
+
if (this.storageListener && typeof window !== "undefined") {
|
|
60372
|
+
window.removeEventListener("storage", this.storageListener);
|
|
60373
|
+
this.storageListener = null;
|
|
60374
|
+
}
|
|
60375
|
+
}
|
|
60376
|
+
}
|
|
60377
|
+
function findLeader(pongs) {
|
|
60378
|
+
return pongs.find((pong) => pong.role === "leader" && pong.authenticated) ?? null;
|
|
60379
|
+
}
|
|
60380
|
+
function anyDialerTab(pongs) {
|
|
60381
|
+
return pongs.some((pong) => pong.role !== null);
|
|
60382
|
+
}
|
|
60383
|
+
function readLeader(username, storage = defaultStorage(), now = Date.now()) {
|
|
60384
|
+
if (!storage) return null;
|
|
60385
|
+
try {
|
|
60386
|
+
const raw = storage.getItem(leaderKey(username));
|
|
60387
|
+
if (!raw) return null;
|
|
60388
|
+
const parsed = JSON.parse(raw);
|
|
60389
|
+
if (typeof parsed.tabId !== "string" || typeof parsed.at !== "number") return null;
|
|
60390
|
+
if (now - parsed.at > LEADER_STALE_MS) return null;
|
|
60391
|
+
return { tabId: parsed.tabId, at: parsed.at };
|
|
60392
|
+
} catch {
|
|
60393
|
+
return null;
|
|
60394
|
+
}
|
|
60395
|
+
}
|
|
60396
|
+
function claimLeader(username, tabId, storage = defaultStorage(), now = Date.now()) {
|
|
60397
|
+
if (!storage) return true;
|
|
60398
|
+
const current = readLeader(username, storage, now);
|
|
60399
|
+
if (current && current.tabId !== tabId) return false;
|
|
60400
|
+
try {
|
|
60401
|
+
storage.setItem(leaderKey(username), JSON.stringify({ tabId, at: now }));
|
|
60402
|
+
} catch {
|
|
60403
|
+
}
|
|
60404
|
+
return true;
|
|
60405
|
+
}
|
|
60406
|
+
function releaseLeader(username, tabId, storage = defaultStorage()) {
|
|
60407
|
+
if (!storage) return;
|
|
60408
|
+
try {
|
|
60409
|
+
const raw = storage.getItem(leaderKey(username));
|
|
60410
|
+
if (!raw) return;
|
|
60411
|
+
const parsed = JSON.parse(raw);
|
|
60412
|
+
if (parsed.tabId === tabId) storage.removeItem(leaderKey(username));
|
|
60413
|
+
} catch {
|
|
60414
|
+
}
|
|
60415
|
+
}
|
|
60416
|
+
function defaultSessionStorage() {
|
|
60417
|
+
try {
|
|
60418
|
+
return typeof sessionStorage !== "undefined" ? sessionStorage : null;
|
|
60419
|
+
} catch {
|
|
60420
|
+
return null;
|
|
60421
|
+
}
|
|
60422
|
+
}
|
|
60423
|
+
function saveTabRole(username, role, storage = defaultSessionStorage()) {
|
|
60424
|
+
if (!storage) return;
|
|
60425
|
+
try {
|
|
60426
|
+
storage.setItem(TAB_ROLE_KEY, JSON.stringify({ username, role, at: Date.now() }));
|
|
60427
|
+
} catch {
|
|
60428
|
+
}
|
|
60429
|
+
}
|
|
60430
|
+
function readTabRole(username, storage = defaultSessionStorage()) {
|
|
60431
|
+
if (!storage) return null;
|
|
60432
|
+
try {
|
|
60433
|
+
const raw = storage.getItem(TAB_ROLE_KEY);
|
|
60434
|
+
if (!raw) return null;
|
|
60435
|
+
const parsed = JSON.parse(raw);
|
|
60436
|
+
if (parsed.username !== username) return null;
|
|
60437
|
+
return parsed.role === "leader" || parsed.role === "member" ? parsed.role : null;
|
|
60438
|
+
} catch {
|
|
60439
|
+
return null;
|
|
60440
|
+
}
|
|
60441
|
+
}
|
|
60442
|
+
function clearTabRole(storage = defaultSessionStorage()) {
|
|
60443
|
+
if (!storage) return;
|
|
60444
|
+
try {
|
|
60445
|
+
storage.removeItem(TAB_ROLE_KEY);
|
|
60446
|
+
} catch {
|
|
60447
|
+
}
|
|
60448
|
+
}
|
|
60449
|
+
function takeoverDelayMs(random = Math.random()) {
|
|
60450
|
+
return TAKEOVER_GRACE_MS + Math.floor(random * TAKEOVER_JITTER_MS);
|
|
60451
|
+
}
|
|
60179
60452
|
const DEFAULT_CLICK_TO_CALL_INTERVAL_MS = 4e3;
|
|
60180
60453
|
const BUSY_INTERVAL_FACTOR = 3;
|
|
60181
60454
|
const DISPATCH_COOLDOWN_MS = 6e3;
|
|
@@ -60398,7 +60671,7 @@ function ClickToCallAgent({ enabled = true, pollIntervalMs, sessionToken, onTask
|
|
|
60398
60671
|
}, [enabled, pollIntervalMs, sessionToken]);
|
|
60399
60672
|
return null;
|
|
60400
60673
|
}
|
|
60401
|
-
const WIDGET_VERSION = "2.
|
|
60674
|
+
const WIDGET_VERSION = "2.7.0";
|
|
60402
60675
|
let currentSipWebSocket = null;
|
|
60403
60676
|
function sendSipUnregisterIfPossible(ws) {
|
|
60404
60677
|
if (ws.readyState !== WebSocket.OPEN) return;
|
|
@@ -60524,9 +60797,23 @@ function useDialerConfig() {
|
|
|
60524
60797
|
return context;
|
|
60525
60798
|
}
|
|
60526
60799
|
const SdkCleanupManager = forwardRef(
|
|
60527
|
-
function SdkCleanupManager2({ children: children2 }, ref) {
|
|
60800
|
+
function SdkCleanupManager2({ children: children2, onSessionDropped }, ref) {
|
|
60528
60801
|
const operator = useCallOperator();
|
|
60529
60802
|
const controls = useCallOperatorControls();
|
|
60803
|
+
const operatorState = useCallOperatorState();
|
|
60804
|
+
const droppedRef = useRef(onSessionDropped);
|
|
60805
|
+
droppedRef.current = onSessionDropped;
|
|
60806
|
+
useCallOperatorEventListener("userSessionDropped", (data) => {
|
|
60807
|
+
var _a2;
|
|
60808
|
+
const originator = (data == null ? void 0 : data.originator) ?? null;
|
|
60809
|
+
(_a2 = droppedRef.current) == null ? void 0 : _a2.call(droppedRef, originator, describeSessionDrop(originator));
|
|
60810
|
+
});
|
|
60811
|
+
const startupError = (operatorState == null ? void 0 : operatorState.state) === "startupError" ? operatorState.error ?? null : null;
|
|
60812
|
+
useEffect(() => {
|
|
60813
|
+
var _a2;
|
|
60814
|
+
if (startupError !== "userIsAlreadyConnectedOnAnotherDevice") return;
|
|
60815
|
+
(_a2 = droppedRef.current) == null ? void 0 : _a2.call(droppedRef, "anotherDevice", describeStartupError(startupError));
|
|
60816
|
+
}, [startupError]);
|
|
60530
60817
|
useImperativeHandle(ref, () => ({
|
|
60531
60818
|
goOffline: () => {
|
|
60532
60819
|
console.log("[Callix Dialer] 📴 Chamando goOffline() para enviar SIP UNREGISTER...");
|
|
@@ -60547,16 +60834,18 @@ const SdkCleanupManager = forwardRef(
|
|
|
60547
60834
|
}
|
|
60548
60835
|
}
|
|
60549
60836
|
}), [operator, controls]);
|
|
60837
|
+
const controlsRef = useRef(controls);
|
|
60838
|
+
controlsRef.current = controls;
|
|
60550
60839
|
useEffect(() => {
|
|
60551
60840
|
return () => {
|
|
60552
60841
|
console.log("[Callix Dialer] 🔌 SdkCleanupManager desmontando, chamando goOffline()...");
|
|
60553
60842
|
try {
|
|
60554
|
-
|
|
60843
|
+
controlsRef.current.goOffline();
|
|
60555
60844
|
} catch (err) {
|
|
60556
60845
|
console.warn("[Callix Dialer] ⚠️ Erro no cleanup automático:", err);
|
|
60557
60846
|
}
|
|
60558
60847
|
};
|
|
60559
|
-
}, [
|
|
60848
|
+
}, []);
|
|
60560
60849
|
return /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: children2 });
|
|
60561
60850
|
}
|
|
60562
60851
|
);
|
|
@@ -60695,6 +60984,13 @@ const getStorageKeys = (username) => ({
|
|
|
60695
60984
|
SKIP_MANUAL_QUALIFICATION: `callix_dialer_${username}_skip_manual_qualification`
|
|
60696
60985
|
});
|
|
60697
60986
|
const LAST_USERNAME_KEY = "callix_dialer_last_username";
|
|
60987
|
+
function readStoredToken(user) {
|
|
60988
|
+
try {
|
|
60989
|
+
return localStorage.getItem(getStorageKeys(user).SESSION_TOKEN);
|
|
60990
|
+
} catch {
|
|
60991
|
+
return null;
|
|
60992
|
+
}
|
|
60993
|
+
}
|
|
60698
60994
|
async function fetchSkipQualification(domain, token) {
|
|
60699
60995
|
var _a2, _b;
|
|
60700
60996
|
try {
|
|
@@ -60724,10 +61020,35 @@ function DialerWrapper({ options, containerEl }) {
|
|
|
60724
61020
|
const [isDisconnecting, setIsDisconnecting] = useState(false);
|
|
60725
61021
|
const presetUsername = options.presetUsername ? options.presetUsername.trim() : null;
|
|
60726
61022
|
const uiVariant = options.uiVariant ?? "default";
|
|
60727
|
-
const autoLogin = options.autoLogin === true;
|
|
60728
61023
|
const portalTarget = useMemo(() => options.portalTarget ?? containerEl ?? null, [options.portalTarget, containerEl]);
|
|
60729
|
-
const
|
|
60730
|
-
|
|
61024
|
+
const tabIdRef = useRef("");
|
|
61025
|
+
if (!tabIdRef.current) tabIdRef.current = newTabId();
|
|
61026
|
+
const [tabRole, setTabRole] = useState(null);
|
|
61027
|
+
const tabRoleRef = useRef(null);
|
|
61028
|
+
tabRoleRef.current = tabRole;
|
|
61029
|
+
const [tabDecided, setTabDecided] = useState(false);
|
|
61030
|
+
const [tabNote, setTabNote] = useState(null);
|
|
61031
|
+
const [engineWaiting, setEngineWaiting] = useState(false);
|
|
61032
|
+
const busRef = useRef(null);
|
|
61033
|
+
const takeoverTimerRef = useRef(null);
|
|
61034
|
+
const isAuthenticatedRef = useRef(false);
|
|
61035
|
+
isAuthenticatedRef.current = isAuthenticated;
|
|
61036
|
+
const isLoadingRef = useRef(false);
|
|
61037
|
+
isLoadingRef.current = isLoading;
|
|
61038
|
+
const logoffPendingRef = useRef(false);
|
|
61039
|
+
const handleLoginRef = useRef(async () => void 0);
|
|
61040
|
+
const handleLogoutRef = useRef(async () => void 0);
|
|
61041
|
+
const cancelTakeover = useCallback(() => {
|
|
61042
|
+
if (takeoverTimerRef.current) {
|
|
61043
|
+
clearTimeout(takeoverTimerRef.current);
|
|
61044
|
+
takeoverTimerRef.current = null;
|
|
61045
|
+
}
|
|
61046
|
+
}, []);
|
|
61047
|
+
useEffect(() => {
|
|
61048
|
+
if (options.autoLogin) {
|
|
61049
|
+
console.info("[Callix Dialer] autoLogin: desde a 2.7.0 o widget não cria sessão sem confirmação; ele entra sozinho só quando já existe uma conexão ativa deste usuário (outra aba ou o motor).");
|
|
61050
|
+
}
|
|
61051
|
+
}, [options.autoLogin]);
|
|
60731
61052
|
const currentSessionRef = useRef({
|
|
60732
61053
|
apiUrl: options.apiUrl || "/api/user-sdk-session",
|
|
60733
61054
|
token: null
|
|
@@ -60759,7 +61080,7 @@ function DialerWrapper({ options, containerEl }) {
|
|
|
60759
61080
|
setError(`${notice.title}: ${notice.detail}${notice.action ? ` ${notice.action}` : ""}`);
|
|
60760
61081
|
setIsAuthenticated(false);
|
|
60761
61082
|
setSessionToken(null);
|
|
60762
|
-
|
|
61083
|
+
setTabNote(null);
|
|
60763
61084
|
});
|
|
60764
61085
|
client2.connect();
|
|
60765
61086
|
engineRef.current = client2;
|
|
@@ -60776,9 +61097,19 @@ function DialerWrapper({ options, containerEl }) {
|
|
|
60776
61097
|
[]
|
|
60777
61098
|
);
|
|
60778
61099
|
useEffect(() => {
|
|
61100
|
+
let unloadHandled = false;
|
|
60779
61101
|
const handleBeforeUnload = () => {
|
|
60780
|
-
|
|
61102
|
+
var _a2;
|
|
61103
|
+
if (engineModeRef.current || unloadHandled) return;
|
|
61104
|
+
unloadHandled = true;
|
|
61105
|
+
setTimeout(() => {
|
|
61106
|
+
unloadHandled = false;
|
|
61107
|
+
}, 2e3);
|
|
60781
61108
|
const { apiUrl, token } = currentSessionRef.current;
|
|
61109
|
+
if (tabRoleRef.current === "leader") {
|
|
61110
|
+
(_a2 = busRef.current) == null ? void 0 : _a2.post({ type: "leaving" });
|
|
61111
|
+
if (busRef.current) releaseLeader(busRef.current.username, tabIdRef.current);
|
|
61112
|
+
}
|
|
60782
61113
|
if (token) {
|
|
60783
61114
|
const data = JSON.stringify({ logout: true });
|
|
60784
61115
|
const logoutUrl = `${apiUrl}?logout=true`;
|
|
@@ -60797,8 +61128,10 @@ function DialerWrapper({ options, containerEl }) {
|
|
|
60797
61128
|
}
|
|
60798
61129
|
};
|
|
60799
61130
|
window.addEventListener("beforeunload", handleBeforeUnload);
|
|
61131
|
+
window.addEventListener("pagehide", handleBeforeUnload);
|
|
60800
61132
|
return () => {
|
|
60801
61133
|
window.removeEventListener("beforeunload", handleBeforeUnload);
|
|
61134
|
+
window.removeEventListener("pagehide", handleBeforeUnload);
|
|
60802
61135
|
};
|
|
60803
61136
|
}, []);
|
|
60804
61137
|
useEffect(() => {
|
|
@@ -60836,8 +61169,239 @@ function DialerWrapper({ options, containerEl }) {
|
|
|
60836
61169
|
setUsername(presetUsername);
|
|
60837
61170
|
}
|
|
60838
61171
|
}, [presetUsername, username]);
|
|
61172
|
+
const engineDomain = useCallback(
|
|
61173
|
+
() => options.domain || new URL(options.apiUrl || "/api/user-sdk-session", window.location.href).host,
|
|
61174
|
+
[options.domain, options.apiUrl]
|
|
61175
|
+
);
|
|
61176
|
+
const enterEngine = useCallback(async (user, domain, token) => {
|
|
61177
|
+
if (token) {
|
|
61178
|
+
const skip = await fetchSkipQualification(domain, token);
|
|
61179
|
+
if (skip !== null) {
|
|
61180
|
+
setSkipManualQualification(skip);
|
|
61181
|
+
try {
|
|
61182
|
+
localStorage.setItem(getStorageKeys(user).SKIP_MANUAL_QUALIFICATION, String(skip));
|
|
61183
|
+
} catch {
|
|
61184
|
+
}
|
|
61185
|
+
}
|
|
61186
|
+
}
|
|
61187
|
+
try {
|
|
61188
|
+
localStorage.setItem(LAST_USERNAME_KEY, user);
|
|
61189
|
+
if (token) {
|
|
61190
|
+
const STORAGE_KEYS = getStorageKeys(user);
|
|
61191
|
+
localStorage.setItem(STORAGE_KEYS.SESSION_TOKEN, token);
|
|
61192
|
+
localStorage.setItem(STORAGE_KEYS.DOMAIN, domain);
|
|
61193
|
+
localStorage.setItem(STORAGE_KEYS.TIMESTAMP, Date.now().toString());
|
|
61194
|
+
}
|
|
61195
|
+
} catch {
|
|
61196
|
+
}
|
|
61197
|
+
setSessionToken(token);
|
|
61198
|
+
setCallixDomain(domain);
|
|
61199
|
+
setUsername(user);
|
|
61200
|
+
setIsAuthenticated(true);
|
|
61201
|
+
setError(null);
|
|
61202
|
+
setTabNote(null);
|
|
61203
|
+
setProviderKey(Date.now());
|
|
61204
|
+
}, []);
|
|
61205
|
+
const joinEngine = useCallback(
|
|
61206
|
+
async (user) => {
|
|
61207
|
+
setIsLoading(true);
|
|
61208
|
+
setError(null);
|
|
61209
|
+
setLoginStatus("Entrando na sessão do motor...");
|
|
61210
|
+
try {
|
|
61211
|
+
await enterEngine(user, engineDomain(), readStoredToken(user));
|
|
61212
|
+
console.log("[Callix Dialer] Conectado ao motor como", user);
|
|
61213
|
+
} catch (err) {
|
|
61214
|
+
console.error("[Callix Dialer] Erro ao entrar na sessão do motor:", err);
|
|
61215
|
+
setError(err instanceof Error ? err.message : "Erro ao conectar ao motor");
|
|
61216
|
+
} finally {
|
|
61217
|
+
setIsLoading(false);
|
|
61218
|
+
setLoginStatus(null);
|
|
61219
|
+
}
|
|
61220
|
+
},
|
|
61221
|
+
[enterEngine, engineDomain]
|
|
61222
|
+
);
|
|
61223
|
+
useEffect(() => {
|
|
61224
|
+
if (!engineMode || !username || isRestoringSession) return;
|
|
61225
|
+
const user = username;
|
|
61226
|
+
const client2 = ensureEngine(user);
|
|
61227
|
+
setEngineWaiting(!client2.getState().view);
|
|
61228
|
+
const fallback = setTimeout(() => setEngineWaiting(false), 15e3);
|
|
61229
|
+
let joining = false;
|
|
61230
|
+
const sync = () => {
|
|
61231
|
+
const { view, sessionLost } = client2.getState();
|
|
61232
|
+
if (!view) return;
|
|
61233
|
+
setEngineWaiting(false);
|
|
61234
|
+
if (view.engine === "stopped" || view.engine === "crashed") logoffPendingRef.current = false;
|
|
61235
|
+
const hasSession = (view.engine === "running" || view.engine === "starting") && !sessionLost;
|
|
61236
|
+
if (hasSession && !logoffPendingRef.current && !isAuthenticatedRef.current && !isLoadingRef.current && !joining) {
|
|
61237
|
+
joining = true;
|
|
61238
|
+
console.log("[Callix Dialer] o motor já segura a sessão deste agente; entrando por aqui também");
|
|
61239
|
+
void joinEngine(user).finally(() => {
|
|
61240
|
+
joining = false;
|
|
61241
|
+
});
|
|
61242
|
+
} else if (view.engine === "stopped" && isAuthenticatedRef.current && !isLoadingRef.current) {
|
|
61243
|
+
console.log("[Callix Dialer] o motor desligou (Sair em outra aba ou servidor reiniciado); voltando à tela de login");
|
|
61244
|
+
setIsAuthenticated(false);
|
|
61245
|
+
setSessionToken(null);
|
|
61246
|
+
setCallixDomain(null);
|
|
61247
|
+
setTabNote("O discador foi encerrado em outra aba ou o motor foi reiniciado.");
|
|
61248
|
+
}
|
|
61249
|
+
};
|
|
61250
|
+
sync();
|
|
61251
|
+
const off = client2.subscribe(sync);
|
|
61252
|
+
return () => {
|
|
61253
|
+
off();
|
|
61254
|
+
clearTimeout(fallback);
|
|
61255
|
+
};
|
|
61256
|
+
}, [engineMode, username, isRestoringSession, ensureEngine, joinEngine]);
|
|
61257
|
+
const scheduleTakeoverRef = useRef(null);
|
|
61258
|
+
useEffect(() => {
|
|
61259
|
+
if (engineMode || !username) {
|
|
61260
|
+
setTabDecided(true);
|
|
61261
|
+
return;
|
|
61262
|
+
}
|
|
61263
|
+
setTabDecided(false);
|
|
61264
|
+
const user = username;
|
|
61265
|
+
const bus = new DialerTabBus({
|
|
61266
|
+
username: user,
|
|
61267
|
+
tabId: tabIdRef.current,
|
|
61268
|
+
status: () => ({ role: tabRoleRef.current, authenticated: isAuthenticatedRef.current })
|
|
61269
|
+
});
|
|
61270
|
+
busRef.current = bus;
|
|
61271
|
+
const becomeMember = () => {
|
|
61272
|
+
if (isAuthenticatedRef.current || tabRoleRef.current === "leader") return;
|
|
61273
|
+
setTabRole("member");
|
|
61274
|
+
saveTabRole(user, "member");
|
|
61275
|
+
setTabNote(null);
|
|
61276
|
+
setError(null);
|
|
61277
|
+
setTabDecided(true);
|
|
61278
|
+
};
|
|
61279
|
+
const scheduleTakeover = () => {
|
|
61280
|
+
cancelTakeover();
|
|
61281
|
+
takeoverTimerRef.current = setTimeout(() => {
|
|
61282
|
+
takeoverTimerRef.current = null;
|
|
61283
|
+
if (tabRoleRef.current !== "member" || isAuthenticatedRef.current || isLoadingRef.current) return;
|
|
61284
|
+
const current = readLeader(user);
|
|
61285
|
+
if (current && current.tabId !== tabIdRef.current) return;
|
|
61286
|
+
if (!claimLeader(user, tabIdRef.current)) return;
|
|
61287
|
+
bus.post({ type: "claim" });
|
|
61288
|
+
console.log("[Callix Dialer] a aba com o discador fechou; esta aba assume a conexão");
|
|
61289
|
+
void handleLoginRef.current(user);
|
|
61290
|
+
}, takeoverDelayMs());
|
|
61291
|
+
};
|
|
61292
|
+
scheduleTakeoverRef.current = scheduleTakeover;
|
|
61293
|
+
const off = bus.on((message) => {
|
|
61294
|
+
switch (message.type) {
|
|
61295
|
+
case "login":
|
|
61296
|
+
case "claim":
|
|
61297
|
+
cancelTakeover();
|
|
61298
|
+
becomeMember();
|
|
61299
|
+
break;
|
|
61300
|
+
case "leaving":
|
|
61301
|
+
if (tabRoleRef.current === "member" && !isAuthenticatedRef.current) scheduleTakeover();
|
|
61302
|
+
break;
|
|
61303
|
+
case "takeover":
|
|
61304
|
+
if (tabRoleRef.current === "leader") {
|
|
61305
|
+
console.log("[Callix Dialer] outra aba pediu o discador; soltando a conexão");
|
|
61306
|
+
void handleLogoutRef.current({ broadcast: false, keepDecision: true });
|
|
61307
|
+
}
|
|
61308
|
+
break;
|
|
61309
|
+
case "logout":
|
|
61310
|
+
cancelTakeover();
|
|
61311
|
+
void handleLogoutRef.current({ broadcast: false });
|
|
61312
|
+
setTabNote("Você saiu do discador em outra aba.");
|
|
61313
|
+
break;
|
|
61314
|
+
case "dropped": {
|
|
61315
|
+
cancelTakeover();
|
|
61316
|
+
releaseLeader(user, tabIdRef.current);
|
|
61317
|
+
setTabRole(null);
|
|
61318
|
+
clearTabRole();
|
|
61319
|
+
const notice = describeSessionDrop(message.originator);
|
|
61320
|
+
setError(`${notice.title}: ${notice.detail}${notice.action ? ` ${notice.action}` : ""}`);
|
|
61321
|
+
break;
|
|
61322
|
+
}
|
|
61323
|
+
}
|
|
61324
|
+
});
|
|
61325
|
+
return () => {
|
|
61326
|
+
off();
|
|
61327
|
+
bus.close();
|
|
61328
|
+
cancelTakeover();
|
|
61329
|
+
scheduleTakeoverRef.current = null;
|
|
61330
|
+
if (busRef.current === bus) busRef.current = null;
|
|
61331
|
+
setTabDecided(false);
|
|
61332
|
+
};
|
|
61333
|
+
}, [engineMode, username, cancelTakeover]);
|
|
61334
|
+
useEffect(() => {
|
|
61335
|
+
if (engineMode || !username || isAuthenticated || tabDecided || isRestoringSession || isLoading) return;
|
|
61336
|
+
const bus = busRef.current;
|
|
61337
|
+
if (!bus) return;
|
|
61338
|
+
const user = username;
|
|
61339
|
+
const stored = readTabRole(user);
|
|
61340
|
+
if (stored === "leader") {
|
|
61341
|
+
cancelTakeover();
|
|
61342
|
+
setTabDecided(true);
|
|
61343
|
+
if (claimLeader(user, tabIdRef.current)) {
|
|
61344
|
+
bus.post({ type: "claim" });
|
|
61345
|
+
console.log("[Callix Dialer] esta aba segurava o discador antes de recarregar; reconectando");
|
|
61346
|
+
void handleLoginRef.current(user);
|
|
61347
|
+
} else {
|
|
61348
|
+
setTabRole("member");
|
|
61349
|
+
saveTabRole(user, "member");
|
|
61350
|
+
}
|
|
61351
|
+
return;
|
|
61352
|
+
}
|
|
61353
|
+
let cancelled = false;
|
|
61354
|
+
void bus.probe().then((pongs) => {
|
|
61355
|
+
var _a2;
|
|
61356
|
+
if (cancelled) return;
|
|
61357
|
+
setTabDecided(true);
|
|
61358
|
+
const leaderLock = readLeader(user);
|
|
61359
|
+
if (findLeader(pongs) || leaderLock && leaderLock.tabId !== tabIdRef.current || stored === "member" && anyDialerTab(pongs)) {
|
|
61360
|
+
setTabRole("member");
|
|
61361
|
+
saveTabRole(user, "member");
|
|
61362
|
+
} else if (stored === "member") {
|
|
61363
|
+
setTabRole("member");
|
|
61364
|
+
(_a2 = scheduleTakeoverRef.current) == null ? void 0 : _a2.call(scheduleTakeoverRef);
|
|
61365
|
+
} else {
|
|
61366
|
+
setTabRole(null);
|
|
61367
|
+
clearTabRole();
|
|
61368
|
+
}
|
|
61369
|
+
});
|
|
61370
|
+
return () => {
|
|
61371
|
+
cancelled = true;
|
|
61372
|
+
};
|
|
61373
|
+
}, [engineMode, username, isAuthenticated, tabDecided, isRestoringSession, isLoading, cancelTakeover]);
|
|
61374
|
+
useEffect(() => {
|
|
61375
|
+
if (engineMode || tabRole !== "leader" || !username) return;
|
|
61376
|
+
const user = username;
|
|
61377
|
+
claimLeader(user, tabIdRef.current);
|
|
61378
|
+
const timer = setInterval(() => claimLeader(user, tabIdRef.current), LEADER_HEARTBEAT_MS);
|
|
61379
|
+
return () => clearInterval(timer);
|
|
61380
|
+
}, [engineMode, tabRole, username]);
|
|
61381
|
+
useEffect(() => {
|
|
61382
|
+
if (engineMode || tabRole !== "member" || !username) return;
|
|
61383
|
+
const user = username;
|
|
61384
|
+
const check = () => {
|
|
61385
|
+
if (document.visibilityState !== "visible" || takeoverTimerRef.current) return;
|
|
61386
|
+
const bus = busRef.current;
|
|
61387
|
+
if (!bus) return;
|
|
61388
|
+
void bus.probe().then((pongs) => {
|
|
61389
|
+
var _a2;
|
|
61390
|
+
if (tabRoleRef.current !== "member" || isAuthenticatedRef.current || takeoverTimerRef.current) return;
|
|
61391
|
+
if (findLeader(pongs) || readLeader(user)) return;
|
|
61392
|
+
console.log("[Callix Dialer] a aba com o discador não responde; esta aba vai assumir");
|
|
61393
|
+
(_a2 = scheduleTakeoverRef.current) == null ? void 0 : _a2.call(scheduleTakeoverRef);
|
|
61394
|
+
});
|
|
61395
|
+
};
|
|
61396
|
+
document.addEventListener("visibilitychange", check);
|
|
61397
|
+
window.addEventListener("focus", check);
|
|
61398
|
+
return () => {
|
|
61399
|
+
document.removeEventListener("visibilitychange", check);
|
|
61400
|
+
window.removeEventListener("focus", check);
|
|
61401
|
+
};
|
|
61402
|
+
}, [engineMode, tabRole, username]);
|
|
60839
61403
|
const handleLogin = useCallback(async (user) => {
|
|
60840
|
-
var _a2, _b;
|
|
61404
|
+
var _a2, _b, _c, _d;
|
|
60841
61405
|
setIsLoading(true);
|
|
60842
61406
|
setError(null);
|
|
60843
61407
|
setLoginStatus("Preparando login...");
|
|
@@ -60846,17 +61410,14 @@ function DialerWrapper({ options, containerEl }) {
|
|
|
60846
61410
|
const engineApiUrl = options.apiUrl || "/api/user-sdk-session";
|
|
60847
61411
|
try {
|
|
60848
61412
|
setLoginStatus("Conectando ao motor...");
|
|
61413
|
+
logoffPendingRef.current = false;
|
|
60849
61414
|
const client2 = ensureEngine(user);
|
|
60850
61415
|
const view = await client2.waitForView(15e3);
|
|
60851
|
-
const domain =
|
|
61416
|
+
const domain = engineDomain();
|
|
60852
61417
|
const engineHasSession = (view.engine === "running" || view.engine === "starting") && !view.sessionLost;
|
|
60853
61418
|
let token = null;
|
|
60854
61419
|
if (engineHasSession) {
|
|
60855
|
-
|
|
60856
|
-
token = localStorage.getItem(getStorageKeys(user).SESSION_TOKEN);
|
|
60857
|
-
} catch {
|
|
60858
|
-
token = null;
|
|
60859
|
-
}
|
|
61420
|
+
token = readStoredToken(user);
|
|
60860
61421
|
console.log("[Callix Dialer] motor já tem a sessão do agente; entrando sem novo login");
|
|
60861
61422
|
} else {
|
|
60862
61423
|
setLoginStatus("Autenticando no Callix...");
|
|
@@ -60875,32 +61436,7 @@ function DialerWrapper({ options, containerEl }) {
|
|
|
60875
61436
|
client2.setSession({ domain, userSessionToken: token });
|
|
60876
61437
|
setLoginStatus("Subindo o motor...");
|
|
60877
61438
|
}
|
|
60878
|
-
|
|
60879
|
-
const skip = await fetchSkipQualification(domain, token);
|
|
60880
|
-
if (skip !== null) {
|
|
60881
|
-
setSkipManualQualification(skip);
|
|
60882
|
-
try {
|
|
60883
|
-
localStorage.setItem(getStorageKeys(user).SKIP_MANUAL_QUALIFICATION, String(skip));
|
|
60884
|
-
} catch {
|
|
60885
|
-
}
|
|
60886
|
-
}
|
|
60887
|
-
}
|
|
60888
|
-
try {
|
|
60889
|
-
localStorage.setItem(LAST_USERNAME_KEY, user);
|
|
60890
|
-
if (token) {
|
|
60891
|
-
const STORAGE_KEYS = getStorageKeys(user);
|
|
60892
|
-
localStorage.setItem(STORAGE_KEYS.SESSION_TOKEN, token);
|
|
60893
|
-
localStorage.setItem(STORAGE_KEYS.DOMAIN, domain);
|
|
60894
|
-
localStorage.setItem(STORAGE_KEYS.TIMESTAMP, Date.now().toString());
|
|
60895
|
-
}
|
|
60896
|
-
} catch {
|
|
60897
|
-
}
|
|
60898
|
-
setSessionToken(token);
|
|
60899
|
-
setCallixDomain(domain);
|
|
60900
|
-
setUsername(user);
|
|
60901
|
-
setIsAuthenticated(true);
|
|
60902
|
-
setError(null);
|
|
60903
|
-
setProviderKey(Date.now());
|
|
61439
|
+
await enterEngine(user, domain, token);
|
|
60904
61440
|
console.log("[Callix Dialer] Conectado ao motor como", user);
|
|
60905
61441
|
} catch (err) {
|
|
60906
61442
|
console.error("[Callix Dialer] Erro ao entrar pelo motor:", err);
|
|
@@ -60913,6 +61449,20 @@ function DialerWrapper({ options, containerEl }) {
|
|
|
60913
61449
|
}
|
|
60914
61450
|
return;
|
|
60915
61451
|
}
|
|
61452
|
+
if (!claimLeader(user, tabIdRef.current)) {
|
|
61453
|
+
console.log("[Callix Dialer] outra aba já segura a conexão deste usuário; esta aba vira membro");
|
|
61454
|
+
setTabRole("member");
|
|
61455
|
+
saveTabRole(user, "member");
|
|
61456
|
+
setTabDecided(true);
|
|
61457
|
+
setUsername(user);
|
|
61458
|
+
setIsLoading(false);
|
|
61459
|
+
setLoginStatus(null);
|
|
61460
|
+
return;
|
|
61461
|
+
}
|
|
61462
|
+
(_a2 = busRef.current) == null ? void 0 : _a2.post({ type: "claim" });
|
|
61463
|
+
cancelTakeover();
|
|
61464
|
+
setTabRole("leader");
|
|
61465
|
+
saveTabRole(user, "leader");
|
|
60916
61466
|
const apiUrl = options.apiUrl || "/api/user-sdk-session";
|
|
60917
61467
|
let previousToken;
|
|
60918
61468
|
if (typeof window !== "undefined") {
|
|
@@ -61007,6 +61557,9 @@ function DialerWrapper({ options, containerEl }) {
|
|
|
61007
61557
|
setError(null);
|
|
61008
61558
|
setProviderKey(Date.now());
|
|
61009
61559
|
console.log("[Callix Dialer] Nova providerKey gerada para forçar recriação do SDK");
|
|
61560
|
+
setTabNote(null);
|
|
61561
|
+
setTabDecided(true);
|
|
61562
|
+
(_b = busRef.current) == null ? void 0 : _b.post({ type: "login" });
|
|
61010
61563
|
try {
|
|
61011
61564
|
const configUrl = `https://${resolvedDomain}/sdk/v1/client/user-service/config`;
|
|
61012
61565
|
setLoginStatus("Carregando configurações...");
|
|
@@ -61021,7 +61574,7 @@ function DialerWrapper({ options, containerEl }) {
|
|
|
61021
61574
|
if (configResponse.ok) {
|
|
61022
61575
|
const configData = await configResponse.json();
|
|
61023
61576
|
console.log("[Callix Dialer] 📦 Dados da config recebidos:", JSON.stringify(configData, null, 2));
|
|
61024
|
-
const shouldSkipQualification = ((
|
|
61577
|
+
const shouldSkipQualification = ((_d = (_c = configData == null ? void 0 : configData.service) == null ? void 0 : _c.outboundOptions) == null ? void 0 : _d.skipQualification) === true;
|
|
61025
61578
|
console.log("[Callix Dialer] ✅ skipQualification configurado:", shouldSkipQualification);
|
|
61026
61579
|
setSkipManualQualification(shouldSkipQualification);
|
|
61027
61580
|
if (typeof window !== "undefined") {
|
|
@@ -61055,53 +61608,52 @@ function DialerWrapper({ options, containerEl }) {
|
|
|
61055
61608
|
setError(err instanceof Error ? err.message : "Erro ao autenticar");
|
|
61056
61609
|
setIsAuthenticated(false);
|
|
61057
61610
|
setSessionToken(null);
|
|
61611
|
+
releaseLeader(user, tabIdRef.current);
|
|
61612
|
+
setTabRole(null);
|
|
61613
|
+
clearTabRole();
|
|
61058
61614
|
} finally {
|
|
61059
61615
|
setIsLoading(false);
|
|
61060
61616
|
setLoginStatus(null);
|
|
61061
61617
|
}
|
|
61062
|
-
}, [options.apiUrl, options.domain, options.engineUrl, isAuthenticated, sessionToken, ensureEngine]);
|
|
61063
|
-
useEffect(() => {
|
|
61064
|
-
if (lastPresetRef.current !== presetUsername) {
|
|
61065
|
-
lastPresetRef.current = presetUsername;
|
|
61066
|
-
autoLoginAttemptedRef.current = false;
|
|
61067
|
-
}
|
|
61068
|
-
if (!presetUsername || !autoLogin) {
|
|
61069
|
-
return;
|
|
61070
|
-
}
|
|
61071
|
-
if (isAuthenticated || isLoading || isRestoringSession || error2 || autoLoginAttemptedRef.current) {
|
|
61072
|
-
return;
|
|
61073
|
-
}
|
|
61074
|
-
autoLoginAttemptedRef.current = true;
|
|
61075
|
-
void handleLogin(presetUsername);
|
|
61076
|
-
}, [presetUsername, autoLogin, isAuthenticated, isLoading, isRestoringSession, error2, handleLogin]);
|
|
61618
|
+
}, [options.apiUrl, options.domain, options.engineUrl, isAuthenticated, sessionToken, ensureEngine, enterEngine, engineDomain, cancelTakeover]);
|
|
61077
61619
|
useEffect(() => {
|
|
61078
|
-
|
|
61079
|
-
|
|
61080
|
-
|
|
61081
|
-
|
|
61082
|
-
|
|
61083
|
-
void
|
|
61084
|
-
}, [autoLogin, presetUsername, username, isAuthenticated, isLoading, isRestoringSession, error2, handleLogin]);
|
|
61085
|
-
const handleLogout = useCallback(async () => {
|
|
61086
|
-
var _a2;
|
|
61620
|
+
handleLoginRef.current = handleLogin;
|
|
61621
|
+
}, [handleLogin]);
|
|
61622
|
+
const handleLogout = useCallback(async (opts) => {
|
|
61623
|
+
var _a2, _b;
|
|
61624
|
+
const broadcast = (opts == null ? void 0 : opts.broadcast) !== false;
|
|
61625
|
+
const keepDecision = (opts == null ? void 0 : opts.keepDecision) === true;
|
|
61087
61626
|
const currentUsername = username;
|
|
61627
|
+
cancelTakeover();
|
|
61088
61628
|
if (options.engineUrl) {
|
|
61089
|
-
(
|
|
61090
|
-
|
|
61091
|
-
|
|
61092
|
-
|
|
61093
|
-
|
|
61094
|
-
|
|
61095
|
-
cleanupRef.current
|
|
61096
|
-
|
|
61629
|
+
if (isAuthenticatedRef.current) {
|
|
61630
|
+
logoffPendingRef.current = true;
|
|
61631
|
+
(_a2 = engineRef.current) == null ? void 0 : _a2.command({ name: "logoff" });
|
|
61632
|
+
}
|
|
61633
|
+
} else {
|
|
61634
|
+
if (broadcast) (_b = busRef.current) == null ? void 0 : _b.post({ type: "logout" });
|
|
61635
|
+
if (cleanupRef.current) {
|
|
61636
|
+
console.log("[Callix Dialer] 📴 Logout: Chamando goOffline()...");
|
|
61637
|
+
cleanupRef.current.goOffline();
|
|
61638
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
61639
|
+
console.log("[Callix Dialer] 🛑 Logout: Chamando stop()...");
|
|
61640
|
+
cleanupRef.current.stop();
|
|
61641
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
61642
|
+
}
|
|
61643
|
+
if (currentUsername) releaseLeader(currentUsername, tabIdRef.current);
|
|
61097
61644
|
}
|
|
61098
|
-
setUsername(presetUsername ?? null);
|
|
61099
61645
|
setIsAuthenticated(false);
|
|
61100
61646
|
setSessionToken(null);
|
|
61101
61647
|
setCallixDomain(null);
|
|
61102
61648
|
setError(null);
|
|
61103
|
-
|
|
61104
|
-
|
|
61649
|
+
if (keepDecision) {
|
|
61650
|
+
setTabRole("member");
|
|
61651
|
+
if (currentUsername) saveTabRole(currentUsername, "member");
|
|
61652
|
+
return;
|
|
61653
|
+
}
|
|
61654
|
+
setTabRole(null);
|
|
61655
|
+
clearTabRole();
|
|
61656
|
+
setUsername(presetUsername ?? null);
|
|
61105
61657
|
if (typeof window !== "undefined" && currentUsername) {
|
|
61106
61658
|
try {
|
|
61107
61659
|
const STORAGE_KEYS = getStorageKeys(currentUsername);
|
|
@@ -61114,14 +61666,53 @@ function DialerWrapper({ options, containerEl }) {
|
|
|
61114
61666
|
console.warn("[Callix Dialer] Não foi possível limpar sessão:", err);
|
|
61115
61667
|
}
|
|
61116
61668
|
}
|
|
61117
|
-
}, [username, presetUsername, options.engineUrl]);
|
|
61118
|
-
|
|
61669
|
+
}, [username, presetUsername, options.engineUrl, cancelTakeover]);
|
|
61670
|
+
useEffect(() => {
|
|
61671
|
+
handleLogoutRef.current = handleLogout;
|
|
61672
|
+
}, [handleLogout]);
|
|
61673
|
+
const handleTakeOver = useCallback(async () => {
|
|
61674
|
+
const user = username;
|
|
61675
|
+
const bus = busRef.current;
|
|
61676
|
+
if (!user || !bus) return;
|
|
61677
|
+
setIsLoading(true);
|
|
61678
|
+
setError(null);
|
|
61679
|
+
setLoginStatus("Trazendo o discador para esta aba...");
|
|
61680
|
+
bus.post({ type: "takeover" });
|
|
61681
|
+
await new Promise((resolve) => setTimeout(resolve, 1500));
|
|
61682
|
+
const current = readLeader(user);
|
|
61683
|
+
if (current && current.tabId !== tabIdRef.current) {
|
|
61684
|
+
console.log("[Callix Dialer] a outra aba não soltou a conexão; continuando como membro");
|
|
61685
|
+
setIsLoading(false);
|
|
61686
|
+
setLoginStatus(null);
|
|
61687
|
+
return;
|
|
61688
|
+
}
|
|
61689
|
+
await handleLoginRef.current(user);
|
|
61690
|
+
}, [username]);
|
|
61691
|
+
const handleLogoutAll = useCallback(() => {
|
|
61692
|
+
void handleLogoutRef.current();
|
|
61693
|
+
}, []);
|
|
61694
|
+
const handleSdkSessionDropped = useCallback(
|
|
61695
|
+
(originator, notice) => {
|
|
61696
|
+
var _a2;
|
|
61697
|
+
const user = username;
|
|
61698
|
+
if (user) releaseLeader(user, tabIdRef.current);
|
|
61699
|
+
(_a2 = busRef.current) == null ? void 0 : _a2.post({ type: "dropped", originator });
|
|
61700
|
+
setTabRole(null);
|
|
61701
|
+
clearTabRole();
|
|
61702
|
+
setError(`${notice.title}: ${notice.detail}${notice.action ? ` ${notice.action}` : ""}`);
|
|
61703
|
+
setIsAuthenticated(false);
|
|
61704
|
+
setSessionToken(null);
|
|
61705
|
+
setCallixDomain(null);
|
|
61706
|
+
},
|
|
61707
|
+
[username]
|
|
61708
|
+
);
|
|
61709
|
+
const deciding = Boolean(username) && !isAuthenticated && (engineMode ? engineWaiting : !tabDecided);
|
|
61119
61710
|
const loginConfirmation = useMemo(() => {
|
|
61120
|
-
if (isAuthenticated || isLoading || isRestoringSession || isDisconnecting || !username ||
|
|
61711
|
+
if (isAuthenticated || isLoading || isRestoringSession || isDisconnecting || !username || deciding) {
|
|
61121
61712
|
return null;
|
|
61122
61713
|
}
|
|
61123
|
-
return { username, locked: Boolean(presetUsername) };
|
|
61124
|
-
}, [isAuthenticated, isLoading, isRestoringSession, isDisconnecting, username, presetUsername,
|
|
61714
|
+
return { username, locked: Boolean(presetUsername), elsewhere: !engineMode && tabRole === "member", note: tabNote };
|
|
61715
|
+
}, [isAuthenticated, isLoading, isRestoringSession, isDisconnecting, username, presetUsername, deciding, engineMode, tabRole, tabNote]);
|
|
61125
61716
|
const handleCancelLoginConfirmation = useCallback(() => {
|
|
61126
61717
|
setUsername(null);
|
|
61127
61718
|
setError(null);
|
|
@@ -61161,11 +61752,13 @@ function DialerWrapper({ options, containerEl }) {
|
|
|
61161
61752
|
username,
|
|
61162
61753
|
onLogin: handleLogin,
|
|
61163
61754
|
onLogout: handleLogout,
|
|
61164
|
-
isLoadingSession: isLoading || isRestoringSession ||
|
|
61755
|
+
isLoadingSession: isLoading || isRestoringSession || deciding,
|
|
61165
61756
|
sessionError: error2,
|
|
61166
61757
|
sessionStatus: loginStatus,
|
|
61167
61758
|
loginConfirmation,
|
|
61168
61759
|
onCancelLoginConfirmation: handleCancelLoginConfirmation,
|
|
61760
|
+
onTakeOverSession: handleTakeOver,
|
|
61761
|
+
onLogoutAllTabs: handleLogoutAll,
|
|
61169
61762
|
variant: uiVariant,
|
|
61170
61763
|
portalTarget,
|
|
61171
61764
|
density: options.density,
|
|
@@ -61210,7 +61803,7 @@ function DialerWrapper({ options, containerEl }) {
|
|
|
61210
61803
|
{
|
|
61211
61804
|
domain: callixDomain,
|
|
61212
61805
|
userSessionToken: sessionToken,
|
|
61213
|
-
children: /* @__PURE__ */ jsxRuntimeExports.jsxs(SdkCleanupManager, { ref: cleanupRef, children: [
|
|
61806
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsxs(SdkCleanupManager, { ref: cleanupRef, onSessionDropped: handleSdkSessionDropped, children: [
|
|
61214
61807
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
61215
61808
|
DialerComponent,
|
|
61216
61809
|
{
|