callix-dialer-widget 2.8.1 → 2.8.3
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
CHANGED
|
@@ -145,7 +145,20 @@ Pausas no modo motor (2.8.1): a lista de pausas é a do serviço no Callix, traz
|
|
|
145
145
|
do motor; a pausa escolhida vai no comando `pause` e o discador mostra o nome dela. Com um
|
|
146
146
|
motor anterior ao 2.8.1 a lista cai numa pausa única ("Pausa") e o motor usa a configurada
|
|
147
147
|
nele. O widget também informa a própria versão ao host, que a registra no log: é o jeito de
|
|
148
|
-
achar navegadores com um build antigo em cache.
|
|
148
|
+
achar navegadores com um build antigo em cache. No console da página, `CallixDialer.version`
|
|
149
|
+
diz qual build está carregado.
|
|
150
|
+
|
|
151
|
+
Comandos durante uma queda da conexão (2.8.2): um clique dado enquanto a conexão com o host
|
|
152
|
+
está caída ou reconectando (rede instável) não se perde mais em silêncio. O comando fica
|
|
153
|
+
guardado, a tela avisa que a conexão está voltando, e ele é enviado no reconectar, se ainda
|
|
154
|
+
tiver menos de 15 s; mais velho que isso é descartado, para não atingir outra chamada. Antes,
|
|
155
|
+
um "encerrar" dado nesse momento deixava a chamada ativa no motor.
|
|
156
|
+
|
|
157
|
+
Espelho e F5 no meio da chamada (2.8.3): a tela de chamada mostra o número da chamada em
|
|
158
|
+
curso informado pelo SDK ou pelo motor quando ninguém digitou nada naquele teclado (antes
|
|
159
|
+
aparecia "(--) ----- ----" na aba espelho). Click-to-call com o agente em pausa (2.8.3): o
|
|
160
|
+
agente sai da pausa, espera o Callix liberá-lo (até 8 s) e disca; se não liberar, a tarefa
|
|
161
|
+
volta à fila. No modo motor, um `dial` recebido em pausa faz o mesmo dentro do motor.
|
|
149
162
|
|
|
150
163
|
Sem `engineUrl` nada muda: o SDK continua rodando no navegador como sempre.
|
|
151
164
|
|
|
@@ -43754,6 +43754,8 @@ const INITIAL_TRANSCRIPT = { segments: [], status: null, insight: null, interims
|
|
|
43754
43754
|
const MAX_SEGMENTS = 300;
|
|
43755
43755
|
const RECONNECT_MIN_MS = 500;
|
|
43756
43756
|
const RECONNECT_MAX_MS = 5e3;
|
|
43757
|
+
const PENDING_COMMANDS_MAX = 10;
|
|
43758
|
+
const PENDING_COMMANDS_TTL_MS = 15e3;
|
|
43757
43759
|
function engineWsUrl(baseUrl) {
|
|
43758
43760
|
const url = new URL(baseUrl, typeof window !== "undefined" ? window.location.href : "http://localhost");
|
|
43759
43761
|
url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
|
|
@@ -43771,6 +43773,7 @@ class EngineClient {
|
|
|
43771
43773
|
this.viewWaiters = [];
|
|
43772
43774
|
this.ws = null;
|
|
43773
43775
|
this.reconnectDelay = RECONNECT_MIN_MS;
|
|
43776
|
+
this.pendingCommands = [];
|
|
43774
43777
|
this.reconnectTimer = null;
|
|
43775
43778
|
this.closed = false;
|
|
43776
43779
|
this.iceServers = [{ urls: "stun:stun.l.google.com:19302" }];
|
|
@@ -43921,6 +43924,7 @@ class EngineClient {
|
|
|
43921
43924
|
case "welcome": {
|
|
43922
43925
|
if (Array.isArray(message.iceServers) && message.iceServers.length > 0) this.iceServers = message.iceServers;
|
|
43923
43926
|
this.setState({ tabId: message.tabId, rejected: null });
|
|
43927
|
+
this.flushPendingCommands();
|
|
43924
43928
|
this.applyView(message.view);
|
|
43925
43929
|
this.log(`sou a aba ${message.tabId}`);
|
|
43926
43930
|
if (this.options.autoEngage !== false && message.view.engagedTabId !== message.tabId) this.engage();
|
|
@@ -44039,8 +44043,29 @@ class EngineClient {
|
|
|
44039
44043
|
this.send({ type: "release" });
|
|
44040
44044
|
}
|
|
44041
44045
|
command(command) {
|
|
44042
|
-
this.
|
|
44043
|
-
|
|
44046
|
+
if (this.ws && this.ws.readyState === WebSocket.OPEN && this.state.tabId) {
|
|
44047
|
+
this.send({ type: "command", command });
|
|
44048
|
+
this.log(`comando: ${command.name}${command.phone ? ` ${command.phone}` : ""}`);
|
|
44049
|
+
return;
|
|
44050
|
+
}
|
|
44051
|
+
this.pendingCommands.push({ command, at: Date.now() });
|
|
44052
|
+
if (this.pendingCommands.length > PENDING_COMMANDS_MAX) this.pendingCommands.shift();
|
|
44053
|
+
this.log(`comando: ${command.name} guardado até a conexão com o motor voltar`);
|
|
44054
|
+
this.setState({ lastError: "Sem conexão com o motor neste momento; o comando será enviado assim que ela voltar." });
|
|
44055
|
+
this.connect();
|
|
44056
|
+
}
|
|
44057
|
+
/** manda os comandos guardados que ainda fazem sentido (os velhos poderiam atingir outra chamada) */
|
|
44058
|
+
flushPendingCommands() {
|
|
44059
|
+
const now = Date.now();
|
|
44060
|
+
const pending = this.pendingCommands.splice(0);
|
|
44061
|
+
for (const entry of pending) {
|
|
44062
|
+
if (now - entry.at > PENDING_COMMANDS_TTL_MS) {
|
|
44063
|
+
this.log(`comando ${entry.command.name} descartado: a conexão demorou demais para voltar`);
|
|
44064
|
+
continue;
|
|
44065
|
+
}
|
|
44066
|
+
this.send({ type: "command", command: entry.command });
|
|
44067
|
+
this.log(`comando: ${entry.command.name} (enviado depois da reconexão)`);
|
|
44068
|
+
}
|
|
44044
44069
|
}
|
|
44045
44070
|
// ------------------------------------------------------------------ áudio
|
|
44046
44071
|
setInputMuted(muted) {
|
|
@@ -58710,7 +58735,7 @@ function AuthenticatedMobileDialer({
|
|
|
58710
58735
|
showClientInfoModal = false,
|
|
58711
58736
|
density
|
|
58712
58737
|
}) {
|
|
58713
|
-
var _a2, _b, _c, _d, _e;
|
|
58738
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
58714
58739
|
const { skipManualQualification } = useDialerConfig();
|
|
58715
58740
|
const [dialValue, setDialValue] = useState("");
|
|
58716
58741
|
const [activeScreen, setActiveScreen] = useState("dialer");
|
|
@@ -58750,6 +58775,7 @@ function AuthenticatedMobileDialer({
|
|
|
58750
58775
|
const currentCall = useCallOperatorCurrentCall();
|
|
58751
58776
|
const { hangup, answer, reject } = useCallOperatorCurrentCallControls();
|
|
58752
58777
|
const callInfo = useCallOperatorCurrentCallInfo();
|
|
58778
|
+
const activeCallNumber = ((_a2 = currentCall == null ? void 0 : currentCall.data) == null ? void 0 : _a2.destinationNumber) || (currentCall == null ? void 0 : currentCall.callerNumber) || "";
|
|
58753
58779
|
const rawSuccessQualifications = useCallOperatorSuccessQualifications();
|
|
58754
58780
|
const rawDiscardQualifications = useCallOperatorDiscardQualifications();
|
|
58755
58781
|
const successQualifications = useMemo(() => rawSuccessQualifications ?? [], [rawSuccessQualifications]);
|
|
@@ -59324,6 +59350,8 @@ function AuthenticatedMobileDialer({
|
|
|
59324
59350
|
phoneNumber = callInfo.info.campaignContact.phoneNumber;
|
|
59325
59351
|
} else if (dialValue) {
|
|
59326
59352
|
phoneNumber = dialValue;
|
|
59353
|
+
} else if (activeCallNumber) {
|
|
59354
|
+
phoneNumber = activeCallNumber;
|
|
59327
59355
|
}
|
|
59328
59356
|
const cleanNumber = phoneNumber.replace(/[^\d+]/g, "");
|
|
59329
59357
|
let whatsappNumber = cleanNumber;
|
|
@@ -59339,7 +59367,7 @@ function AuthenticatedMobileDialer({
|
|
|
59339
59367
|
const whatsappUrl = `https://wa.me/${whatsappNumber.replace("+", "")}?text=${encodedMessage}`;
|
|
59340
59368
|
console.log("[MobileDialer] Abrindo WhatsApp com template:", whatsappUrl);
|
|
59341
59369
|
window.open(whatsappUrl, "_blank");
|
|
59342
|
-
}, [callInfo, dialValue, userData, username, contactData.finalData]);
|
|
59370
|
+
}, [callInfo, dialValue, userData, username, contactData.finalData, activeCallNumber]);
|
|
59343
59371
|
const handleGoOnBreak = useCallback(
|
|
59344
59372
|
async (breakId) => {
|
|
59345
59373
|
if (!goOnBreak) return;
|
|
@@ -59407,8 +59435,9 @@ function AuthenticatedMobileDialer({
|
|
|
59407
59435
|
if ((callInfo == null ? void 0 : callInfo.type) === "campaign" && ((_a3 = callInfo.info.campaignContact) == null ? void 0 : _a3.phoneNumber)) {
|
|
59408
59436
|
return formatPhoneForDisplay(callInfo.info.campaignContact.phoneNumber);
|
|
59409
59437
|
}
|
|
59410
|
-
|
|
59411
|
-
|
|
59438
|
+
if (formattedDial) return formattedDial;
|
|
59439
|
+
return activeCallNumber ? formatPhoneForDisplay(activeCallNumber) : "(--) ----- ----";
|
|
59440
|
+
}, [callInfo, formattedDial, activeCallNumber]);
|
|
59412
59441
|
const callStatusLabel = useMemo(() => {
|
|
59413
59442
|
if (isConnecting) return "Ligando...";
|
|
59414
59443
|
if (isInCall) return "Em chamada";
|
|
@@ -59423,7 +59452,7 @@ function AuthenticatedMobileDialer({
|
|
|
59423
59452
|
if (isOnBreak) return "paused";
|
|
59424
59453
|
return "available";
|
|
59425
59454
|
}, [isError, isOnBreak]);
|
|
59426
|
-
const activeBreakName = (operatorState == null ? void 0 : operatorState.state) === "onBreak" ? (
|
|
59455
|
+
const activeBreakName = (operatorState == null ? void 0 : operatorState.state) === "onBreak" ? (_b = operatorState.break) == null ? void 0 : _b.name : void 0;
|
|
59427
59456
|
const statusBadgeText = useMemo(() => {
|
|
59428
59457
|
if (isError) return (dialerNotice == null ? void 0 : dialerNotice.source) === "device" ? dialerNotice.title : "Erro";
|
|
59429
59458
|
if (isOnBreak) return currentBreakName || activeBreakName || "Em pausa";
|
|
@@ -59566,15 +59595,15 @@ function AuthenticatedMobileDialer({
|
|
|
59566
59595
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "client-card-header", children: [
|
|
59567
59596
|
/* @__PURE__ */ jsxRuntimeExports.jsx("i", { className: "fas fa-user-circle client-avatar" }),
|
|
59568
59597
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "client-main-info", children: [
|
|
59569
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "client-name", id: "clientName", children: findValue(contactData.finalData, ["DECISOR", "NOME", "CLIENTE", "PROSPECT"]) ?? ((
|
|
59570
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "client-company", id: "clientCompany", children: findValue(contactData.finalData, ["EMPRESA", "RAZAO SOCIAL", "RAZÃO SOCIAL", "RAZAO_SOCIAL"]) ?? ((
|
|
59598
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "client-name", id: "clientName", children: findValue(contactData.finalData, ["DECISOR", "NOME", "CLIENTE", "PROSPECT"]) ?? ((_c = callInfo.info.campaignContact) == null ? void 0 : _c.label) ?? "--" }),
|
|
59599
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "client-company", id: "clientCompany", children: findValue(contactData.finalData, ["EMPRESA", "RAZAO SOCIAL", "RAZÃO SOCIAL", "RAZAO_SOCIAL"]) ?? ((_d = callInfo.info.campaign) == null ? void 0 : _d.name) ?? "--" })
|
|
59571
59600
|
] })
|
|
59572
59601
|
] }),
|
|
59573
59602
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "client-card-divider" }),
|
|
59574
59603
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "client-info-list", children: [
|
|
59575
59604
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "client-info-row", children: [
|
|
59576
59605
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "client-info-label", children: "Socio" }),
|
|
59577
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "client-info-value", children: findValue(contactData.finalData, ["SOCIO", "PROSPECT", "DECISOR", "NOME", "CLIENTE"]) ?? ((
|
|
59606
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "client-info-value", children: findValue(contactData.finalData, ["SOCIO", "PROSPECT", "DECISOR", "NOME", "CLIENTE"]) ?? ((_e = callInfo.info.campaignContact) == null ? void 0 : _e.label) ?? "--" })
|
|
59578
59607
|
] }),
|
|
59579
59608
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "client-info-row", children: [
|
|
59580
59609
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "client-info-label", children: "Empresa" }),
|
|
@@ -59771,7 +59800,7 @@ function AuthenticatedMobileDialer({
|
|
|
59771
59800
|
{
|
|
59772
59801
|
isOpen: isClientInfoModalOpen,
|
|
59773
59802
|
campaignCallInfo,
|
|
59774
|
-
campaignContactPhoneId: ((
|
|
59803
|
+
campaignContactPhoneId: ((_f = currentCall == null ? void 0 : currentCall.data) == null ? void 0 : _f.campaignContactPhoneId) ?? null,
|
|
59775
59804
|
callDuration: callDurationSeconds,
|
|
59776
59805
|
isCallActive: isInCall || isConnecting,
|
|
59777
59806
|
onClose: () => setIsClientInfoModalOpen(false)
|
|
@@ -60538,6 +60567,7 @@ const BUSY_INTERVAL_FACTOR = 3;
|
|
|
60538
60567
|
const DISPATCH_COOLDOWN_MS = 6e3;
|
|
60539
60568
|
const CALL_START_TIMEOUT_MS = 4e3;
|
|
60540
60569
|
const CALL_START_CHECK_MS = 100;
|
|
60570
|
+
const LEAVE_BREAK_TIMEOUT_MS = 8e3;
|
|
60541
60571
|
const MAX_BACKOFF_MS = 6e4;
|
|
60542
60572
|
const NOT_CONFIGURED_INTERVAL_MS = 5 * 6e4;
|
|
60543
60573
|
const NOT_CONFIGURED_CODES = /* @__PURE__ */ new Set(["STORE_NOT_CONFIGURED", "SERVER_NOT_CONFIGURED"]);
|
|
@@ -60553,11 +60583,13 @@ function buildHeaders(sessionToken) {
|
|
|
60553
60583
|
const delay = (ms2) => new Promise((resolve) => setTimeout(resolve, ms2));
|
|
60554
60584
|
function ClickToCallAgent({ enabled = true, pollIntervalMs, sessionToken, onTask }) {
|
|
60555
60585
|
const operatorState = useCallOperatorState();
|
|
60556
|
-
const { makeManualCall } = useCallOperatorControls();
|
|
60586
|
+
const { makeManualCall, becomeAvailable } = useCallOperatorControls();
|
|
60557
60587
|
const stateRef = useRef(operatorState == null ? void 0 : operatorState.state);
|
|
60558
60588
|
stateRef.current = operatorState == null ? void 0 : operatorState.state;
|
|
60559
60589
|
const makeManualCallRef = useRef(makeManualCall);
|
|
60560
60590
|
makeManualCallRef.current = makeManualCall;
|
|
60591
|
+
const becomeAvailableRef = useRef(becomeAvailable);
|
|
60592
|
+
becomeAvailableRef.current = becomeAvailable;
|
|
60561
60593
|
const onTaskRef = useRef(onTask);
|
|
60562
60594
|
onTaskRef.current = onTask;
|
|
60563
60595
|
const tickerRef = useRef(null);
|
|
@@ -60619,6 +60651,16 @@ function ClickToCallAgent({ enabled = true, pollIntervalMs, sessionToken, onTask
|
|
|
60619
60651
|
console.error("[ClickToCall] não foi possível confirmar a tarefa", options.taskId, "; o servidor a marcará como não confirmada");
|
|
60620
60652
|
return false;
|
|
60621
60653
|
};
|
|
60654
|
+
const waitForOperatorState = (predicate, timeoutMs) => new Promise((resolve) => {
|
|
60655
|
+
const deadline = Date.now() + timeoutMs;
|
|
60656
|
+
const check = () => {
|
|
60657
|
+
if (disposed) return resolve(false);
|
|
60658
|
+
if (predicate(stateRef.current)) return resolve(true);
|
|
60659
|
+
if (Date.now() >= deadline) return resolve(false);
|
|
60660
|
+
setTimeout(check, CALL_START_CHECK_MS);
|
|
60661
|
+
};
|
|
60662
|
+
check();
|
|
60663
|
+
});
|
|
60622
60664
|
const waitForCallStart = () => new Promise((resolve) => {
|
|
60623
60665
|
const deadline = Date.now() + CALL_START_TIMEOUT_MS;
|
|
60624
60666
|
const check = () => {
|
|
@@ -60652,6 +60694,23 @@ function ClickToCallAgent({ enabled = true, pollIntervalMs, sessionToken, onTask
|
|
|
60652
60694
|
} catch (error2) {
|
|
60653
60695
|
console.warn("[ClickToCall] onTask lançou erro:", error2);
|
|
60654
60696
|
}
|
|
60697
|
+
if (presenceFromOperatorState(stateRef.current) === "on_break") {
|
|
60698
|
+
console.log("[ClickToCall] operador em pausa: saindo da pausa para ligar");
|
|
60699
|
+
try {
|
|
60700
|
+
becomeAvailableRef.current();
|
|
60701
|
+
} catch (error2) {
|
|
60702
|
+
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
60703
|
+
console.error("[ClickToCall] becomeAvailable falhou:", message);
|
|
60704
|
+
await ack({ taskId: task.id, status: "failed", error: `Não deu para sair da pausa: ${message}`, retry: true });
|
|
60705
|
+
return;
|
|
60706
|
+
}
|
|
60707
|
+
const available = await waitForOperatorState((state2) => state2 === "idle", LEAVE_BREAK_TIMEOUT_MS);
|
|
60708
|
+
if (!available) {
|
|
60709
|
+
console.warn("[ClickToCall] o operador não saiu da pausa a tempo (estado", stateRef.current, "): devolvendo à fila");
|
|
60710
|
+
await ack({ taskId: task.id, status: "failed", error: `Operador não saiu da pausa (${stateRef.current ?? "desconhecido"})`, retry: true });
|
|
60711
|
+
return;
|
|
60712
|
+
}
|
|
60713
|
+
}
|
|
60655
60714
|
try {
|
|
60656
60715
|
makeManualCallRef.current(task.phone);
|
|
60657
60716
|
} catch (error2) {
|
|
@@ -60755,7 +60814,7 @@ function ClickToCallAgent({ enabled = true, pollIntervalMs, sessionToken, onTask
|
|
|
60755
60814
|
}, [enabled, pollIntervalMs, sessionToken]);
|
|
60756
60815
|
return null;
|
|
60757
60816
|
}
|
|
60758
|
-
const WIDGET_VERSION = "2.8.
|
|
60817
|
+
const WIDGET_VERSION = "2.8.3";
|
|
60759
60818
|
let currentSipWebSocket = null;
|
|
60760
60819
|
function sendSipUnregisterIfPossible(ws) {
|
|
60761
60820
|
if (ws.readyState !== WebSocket.OPEN) return;
|