callix-dialer-widget 2.8.3 → 2.8.5
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.
|
@@ -43754,6 +43754,7 @@ 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 ENGINE_VIEW_TIMEOUT_MS = 15e3;
|
|
43757
43758
|
const PENDING_COMMANDS_MAX = 10;
|
|
43758
43759
|
const PENDING_COMMANDS_TTL_MS = 15e3;
|
|
43759
43760
|
function engineWsUrl(baseUrl) {
|
|
@@ -43775,6 +43776,9 @@ class EngineClient {
|
|
|
43775
43776
|
this.reconnectDelay = RECONNECT_MIN_MS;
|
|
43776
43777
|
this.pendingCommands = [];
|
|
43777
43778
|
this.reconnectTimer = null;
|
|
43779
|
+
this.viewTimer = null;
|
|
43780
|
+
this.lastSnapshotAt = null;
|
|
43781
|
+
this.connectionError = null;
|
|
43778
43782
|
this.closed = false;
|
|
43779
43783
|
this.iceServers = [{ urls: "stun:stun.l.google.com:19302" }];
|
|
43780
43784
|
this.pc = null;
|
|
@@ -43828,13 +43832,20 @@ class EngineClient {
|
|
|
43828
43832
|
if (this.closed) this.closed = false;
|
|
43829
43833
|
if (this.ws && (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING)) return;
|
|
43830
43834
|
const Impl = this.options.WebSocketImpl ?? WebSocket;
|
|
43831
|
-
this.setState({ wsState: "connecting" });
|
|
43835
|
+
this.setState({ wsState: "connecting", tabId: null, view: null });
|
|
43832
43836
|
const ws = new Impl(engineWsUrl(this.options.url));
|
|
43833
43837
|
this.ws = ws;
|
|
43838
|
+
this.watchForView(ws);
|
|
43834
43839
|
ws.onopen = () => {
|
|
43840
|
+
var _a2, _b;
|
|
43835
43841
|
if (this.ws !== ws) return;
|
|
43842
|
+
if (this.pendingLogoffToken !== void 0 && ((_b = (_a2 = this.options).sessionToken) == null ? void 0 : _b.call(_a2)) !== this.pendingLogoffToken) {
|
|
43843
|
+
this.pendingCommands = this.pendingCommands.filter((entry) => entry.command.name !== "logoff");
|
|
43844
|
+
this.rejectWaiters(new EngineAccessError("session-changed", "A sessão mudou antes de confirmar a saída."));
|
|
43845
|
+
}
|
|
43836
43846
|
this.reconnectDelay = RECONNECT_MIN_MS;
|
|
43837
43847
|
this.setState({ wsState: "open" });
|
|
43848
|
+
this.watchForView(ws);
|
|
43838
43849
|
const sessionToken = !this.session && this.options.sessionToken ? this.options.sessionToken() : null;
|
|
43839
43850
|
const hello = {
|
|
43840
43851
|
type: "hello",
|
|
@@ -43860,24 +43871,14 @@ class EngineClient {
|
|
|
43860
43871
|
this.handle(message);
|
|
43861
43872
|
};
|
|
43862
43873
|
ws.onclose = () => {
|
|
43863
|
-
|
|
43864
|
-
this.ws = null;
|
|
43865
|
-
const wasEngaged = this.state.engaged;
|
|
43866
|
-
this.setState({ wsState: "closed", tabId: null, engaged: false });
|
|
43867
|
-
if (wasEngaged) this.stopAudio();
|
|
43868
|
-
if (this.closed) return;
|
|
43869
|
-
this.log(`conexão com o motor caiu; nova tentativa em ${this.reconnectDelay} ms`);
|
|
43870
|
-
this.reconnectTimer = setTimeout(() => {
|
|
43871
|
-
this.reconnectTimer = null;
|
|
43872
|
-
this.connect();
|
|
43873
|
-
}, this.reconnectDelay);
|
|
43874
|
-
this.reconnectDelay = Math.min(this.reconnectDelay * 2, RECONNECT_MAX_MS);
|
|
43874
|
+
this.disconnected(ws, "Conexão com o motor interrompida. Reconectando...");
|
|
43875
43875
|
};
|
|
43876
43876
|
ws.onerror = () => void 0;
|
|
43877
43877
|
}
|
|
43878
43878
|
/** fecha de vez (sem reconectar) e solta o áudio */
|
|
43879
43879
|
close() {
|
|
43880
43880
|
this.closed = true;
|
|
43881
|
+
this.clearViewTimer();
|
|
43881
43882
|
if (this.reconnectTimer) {
|
|
43882
43883
|
clearTimeout(this.reconnectTimer);
|
|
43883
43884
|
this.reconnectTimer = null;
|
|
@@ -43889,8 +43890,41 @@ class EngineClient {
|
|
|
43889
43890
|
ws.onclose = null;
|
|
43890
43891
|
ws.close();
|
|
43891
43892
|
}
|
|
43892
|
-
|
|
43893
|
-
this.
|
|
43893
|
+
this.pendingCommands = [];
|
|
43894
|
+
this.rejectWaiters(new Error("a conexão com o motor foi encerrada"));
|
|
43895
|
+
this.userSignal.set(void 0);
|
|
43896
|
+
this.setState({ wsState: "closed", tabId: null, view: null, engaged: false });
|
|
43897
|
+
}
|
|
43898
|
+
clearViewTimer() {
|
|
43899
|
+
if (this.viewTimer) clearTimeout(this.viewTimer);
|
|
43900
|
+
this.viewTimer = null;
|
|
43901
|
+
}
|
|
43902
|
+
watchForView(ws) {
|
|
43903
|
+
var _a2, _b;
|
|
43904
|
+
this.clearViewTimer();
|
|
43905
|
+
this.viewTimer = setTimeout(() => {
|
|
43906
|
+
if (this.ws !== ws) return;
|
|
43907
|
+
this.disconnected(ws, "O motor parou de atualizar o estado. Reconectando...");
|
|
43908
|
+
ws.close();
|
|
43909
|
+
}, ENGINE_VIEW_TIMEOUT_MS);
|
|
43910
|
+
(_b = (_a2 = this.viewTimer).unref) == null ? void 0 : _b.call(_a2);
|
|
43911
|
+
}
|
|
43912
|
+
disconnected(ws, message) {
|
|
43913
|
+
if (this.ws !== ws) return;
|
|
43914
|
+
this.ws = null;
|
|
43915
|
+
this.clearViewTimer();
|
|
43916
|
+
this.userSignal.set(void 0);
|
|
43917
|
+
this.connectionError = message;
|
|
43918
|
+
this.setState({ wsState: "closed", tabId: null, view: null, engaged: false, lastError: message });
|
|
43919
|
+
this.stopAudio();
|
|
43920
|
+
if (this.closed) return;
|
|
43921
|
+
this.log(`conexão com o motor caiu; nova tentativa em ${this.reconnectDelay} ms`);
|
|
43922
|
+
if (this.reconnectTimer) clearTimeout(this.reconnectTimer);
|
|
43923
|
+
this.reconnectTimer = setTimeout(() => {
|
|
43924
|
+
this.reconnectTimer = null;
|
|
43925
|
+
this.connect();
|
|
43926
|
+
}, this.reconnectDelay);
|
|
43927
|
+
this.reconnectDelay = Math.min(this.reconnectDelay * 2, RECONNECT_MAX_MS);
|
|
43894
43928
|
}
|
|
43895
43929
|
/**
|
|
43896
43930
|
* A view atual, ou a próxima que o host mandar (welcome/view). Com `accept`, espera uma
|
|
@@ -43900,7 +43934,7 @@ class EngineClient {
|
|
|
43900
43934
|
waitForView(timeoutMs = 15e3, accept, options) {
|
|
43901
43935
|
const rejected = this.state.rejected;
|
|
43902
43936
|
if (rejected) return Promise.reject(new EngineAccessError(rejected.code, rejected.message));
|
|
43903
|
-
if (!(options == null ? void 0 : options.fresh) && this.state.view && this.state.tabId && (!accept || accept(this.state.view))) return Promise.resolve(this.state.view);
|
|
43937
|
+
if (!(options == null ? void 0 : options.fresh) && this.state.wsState === "open" && this.state.view && this.state.tabId && (!accept || accept(this.state.view))) return Promise.resolve(this.state.view);
|
|
43904
43938
|
return new Promise((resolve, reject) => {
|
|
43905
43939
|
const timer = setTimeout(() => {
|
|
43906
43940
|
const index = this.viewWaiters.findIndex((w) => w.timer === timer);
|
|
@@ -43924,6 +43958,7 @@ class EngineClient {
|
|
|
43924
43958
|
case "welcome": {
|
|
43925
43959
|
if (Array.isArray(message.iceServers) && message.iceServers.length > 0) this.iceServers = message.iceServers;
|
|
43926
43960
|
this.setState({ tabId: message.tabId, rejected: null });
|
|
43961
|
+
if (this.ws) this.watchForView(this.ws);
|
|
43927
43962
|
this.flushPendingCommands();
|
|
43928
43963
|
this.applyView(message.view);
|
|
43929
43964
|
this.log(`sou a aba ${message.tabId}`);
|
|
@@ -43951,6 +43986,10 @@ class EngineClient {
|
|
|
43951
43986
|
break;
|
|
43952
43987
|
}
|
|
43953
43988
|
if (message.code === "session-changed") {
|
|
43989
|
+
if (this.pendingLogoffToken !== void 0) {
|
|
43990
|
+
this.pendingCommands = this.pendingCommands.filter((entry) => entry.command.name !== "logoff");
|
|
43991
|
+
this.rejectWaiters(new EngineAccessError(message.code, message.message));
|
|
43992
|
+
}
|
|
43954
43993
|
this.session = null;
|
|
43955
43994
|
this.log("a sessão deste agente foi trocada por um login novo; reconectando com a credencial atual");
|
|
43956
43995
|
break;
|
|
@@ -43977,21 +44016,34 @@ class EngineClient {
|
|
|
43977
44016
|
}
|
|
43978
44017
|
}
|
|
43979
44018
|
applyView(view) {
|
|
43980
|
-
var _a2, _b;
|
|
44019
|
+
var _a2, _b, _c;
|
|
43981
44020
|
const previous = this.state.view;
|
|
44021
|
+
const snapshotAt = (_a2 = view.snapshot) == null ? void 0 : _a2.at;
|
|
44022
|
+
if (view.engine === "stopped" || view.engine === "crashed") {
|
|
44023
|
+
this.clearViewTimer();
|
|
44024
|
+
} else if (this.ws && (snapshotAt !== void 0 && snapshotAt !== this.lastSnapshotAt || (previous == null ? void 0 : previous.engine) === "stopped" || (previous == null ? void 0 : previous.engine) === "crashed")) {
|
|
44025
|
+
this.watchForView(this.ws);
|
|
44026
|
+
}
|
|
44027
|
+
if (snapshotAt !== void 0) this.lastSnapshotAt = snapshotAt;
|
|
43982
44028
|
const lost = view.sessionLost ?? null;
|
|
43983
44029
|
const newlyLost = Boolean(lost) && !(previous == null ? void 0 : previous.sessionLost);
|
|
43984
44030
|
if (newlyLost) {
|
|
43985
44031
|
this.session = null;
|
|
43986
44032
|
this.log(`o Callix derrubou a sessão: ${(lost == null ? void 0 : lost.message) ?? ""}`);
|
|
43987
44033
|
}
|
|
43988
|
-
const user = (
|
|
44034
|
+
const user = (_b = view.snapshot) == null ? void 0 : _b.leg.user;
|
|
43989
44035
|
this.userSignal.set(user ? { ...user, sessionId: 0 } : void 0);
|
|
43990
|
-
const call = (
|
|
44036
|
+
const call = (_c = view.snapshot) == null ? void 0 : _c.leg.call;
|
|
43991
44037
|
const patch = { view, sessionLost: lost ? { originator: lost.originator, message: lost.message } : null };
|
|
44038
|
+
if (this.connectionError && this.state.lastError === this.connectionError) patch.lastError = null;
|
|
44039
|
+
this.connectionError = null;
|
|
43992
44040
|
if (call && typeof call.muted === "boolean" && call.muted !== this.state.inputMuted && call.state !== "ended") patch.inputMuted = call.muted;
|
|
43993
44041
|
this.setState(patch);
|
|
43994
44042
|
for (const waiter of this.viewWaiters.splice(0)) {
|
|
44043
|
+
if (this.state.wsState !== "open" || !this.state.tabId) {
|
|
44044
|
+
this.viewWaiters.push(waiter);
|
|
44045
|
+
continue;
|
|
44046
|
+
}
|
|
43995
44047
|
if (waiter.accept && !waiter.accept(view)) {
|
|
43996
44048
|
this.viewWaiters.push(waiter);
|
|
43997
44049
|
continue;
|
|
@@ -44014,6 +44066,10 @@ class EngineClient {
|
|
|
44014
44066
|
* (é assim que um login novo substitui a sessão de outro navegador).
|
|
44015
44067
|
*/
|
|
44016
44068
|
setSession(session) {
|
|
44069
|
+
if (this.pendingLogoffToken !== void 0) {
|
|
44070
|
+
this.pendingCommands = this.pendingCommands.filter((entry) => entry.command.name !== "logoff");
|
|
44071
|
+
this.rejectWaiters(new EngineAccessError("session-changed", "Uma sessão nova substituiu o pedido de saída anterior."));
|
|
44072
|
+
}
|
|
44017
44073
|
this.session = session;
|
|
44018
44074
|
this.setState({ rejected: null, sessionLost: null });
|
|
44019
44075
|
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
@@ -44042,8 +44098,38 @@ class EngineClient {
|
|
|
44042
44098
|
release() {
|
|
44043
44099
|
this.send({ type: "release" });
|
|
44044
44100
|
}
|
|
44101
|
+
/** Só confirma a saída quando o host terminou o encerramento do SDK e da sessão. */
|
|
44102
|
+
async logoff(timeoutMs = 4e4) {
|
|
44103
|
+
var _a2, _b;
|
|
44104
|
+
if (this.state.rejected) throw new EngineAccessError(this.state.rejected.code, this.state.rejected.message);
|
|
44105
|
+
this.session = null;
|
|
44106
|
+
this.pendingCommands = [];
|
|
44107
|
+
this.pendingLogoffToken = (_b = (_a2 = this.options).sessionToken) == null ? void 0 : _b.call(_a2);
|
|
44108
|
+
const command = { name: "logoff" };
|
|
44109
|
+
let acknowledged = false;
|
|
44110
|
+
const confirmation = this.waitForView(timeoutMs, (view) => {
|
|
44111
|
+
if (view.loggingOff) {
|
|
44112
|
+
acknowledged = true;
|
|
44113
|
+
return false;
|
|
44114
|
+
}
|
|
44115
|
+
return view.engine === "stopped" || view.engine === "crashed" || acknowledged && Boolean(view.logoffError);
|
|
44116
|
+
}, { fresh: true });
|
|
44117
|
+
this.command(command);
|
|
44118
|
+
try {
|
|
44119
|
+
const view = await confirmation;
|
|
44120
|
+
if (view.logoffError) throw new Error(view.logoffError);
|
|
44121
|
+
if (!acknowledged || view.engine !== "stopped") throw new Error("O motor parou sem confirmar o encerramento da sessão no Callix.");
|
|
44122
|
+
} catch (error2) {
|
|
44123
|
+
if (error2 instanceof EngineAccessError) throw error2;
|
|
44124
|
+
throw new Error(error2 instanceof Error && error2.message !== "o motor não respondeu" ? error2.message : "O motor não confirmou o encerramento da sessão.");
|
|
44125
|
+
} finally {
|
|
44126
|
+
this.pendingCommands = this.pendingCommands.filter((entry) => entry.command !== command);
|
|
44127
|
+
this.pendingLogoffToken = void 0;
|
|
44128
|
+
}
|
|
44129
|
+
}
|
|
44045
44130
|
command(command) {
|
|
44046
44131
|
if (this.ws && this.ws.readyState === WebSocket.OPEN && this.state.tabId) {
|
|
44132
|
+
this.setState({ lastError: null });
|
|
44047
44133
|
this.send({ type: "command", command });
|
|
44048
44134
|
this.log(`comando: ${command.name}${command.phone ? ` ${command.phone}` : ""}`);
|
|
44049
44135
|
return;
|
|
@@ -44051,7 +44137,8 @@ class EngineClient {
|
|
|
44051
44137
|
this.pendingCommands.push({ command, at: Date.now() });
|
|
44052
44138
|
if (this.pendingCommands.length > PENDING_COMMANDS_MAX) this.pendingCommands.shift();
|
|
44053
44139
|
this.log(`comando: ${command.name} guardado até a conexão com o motor voltar`);
|
|
44054
|
-
this.
|
|
44140
|
+
this.connectionError = "Sem conexão com o motor neste momento; o comando será enviado assim que ela voltar.";
|
|
44141
|
+
this.setState({ lastError: this.connectionError });
|
|
44055
44142
|
this.connect();
|
|
44056
44143
|
}
|
|
44057
44144
|
/** manda os comandos guardados que ainda fazem sentido (os velhos poderiam atingir outra chamada) */
|
|
@@ -44313,13 +44400,13 @@ class EngineCall {
|
|
|
44313
44400
|
return Math.max(0, Math.floor((Date.now() - from) / 1e3));
|
|
44314
44401
|
}
|
|
44315
44402
|
answer() {
|
|
44316
|
-
this.client
|
|
44403
|
+
engineCommand(this.client, { name: "answer" });
|
|
44317
44404
|
}
|
|
44318
44405
|
reject() {
|
|
44319
|
-
this.client
|
|
44406
|
+
engineCommand(this.client, { name: "reject" });
|
|
44320
44407
|
}
|
|
44321
44408
|
hangup() {
|
|
44322
|
-
this.client
|
|
44409
|
+
engineCommand(this.client, { name: "hangup" });
|
|
44323
44410
|
}
|
|
44324
44411
|
isOnHold() {
|
|
44325
44412
|
return { local: false, remote: false };
|
|
@@ -44338,7 +44425,7 @@ class EngineCall {
|
|
|
44338
44425
|
this.client.setInputMuted(false);
|
|
44339
44426
|
}
|
|
44340
44427
|
sendDtmf(tones) {
|
|
44341
|
-
this.client
|
|
44428
|
+
engineCommand(this.client, { name: "dtmf", tones });
|
|
44342
44429
|
}
|
|
44343
44430
|
on(event, listener) {
|
|
44344
44431
|
let set = this.listeners.get(event);
|
|
@@ -44374,10 +44461,12 @@ class EngineCall {
|
|
|
44374
44461
|
}
|
|
44375
44462
|
}
|
|
44376
44463
|
function operatorStateFromView(view, call) {
|
|
44377
|
-
var _a2, _b, _c;
|
|
44464
|
+
var _a2, _b, _c, _d, _e;
|
|
44378
44465
|
if (!view) return void 0;
|
|
44379
|
-
if (((_a2 = view.
|
|
44380
|
-
|
|
44466
|
+
if (view.logoffError || ((_a2 = view.snapshot) == null ? void 0 : _a2.leg.logoffError)) return { state: "startupError", error: "unknownError" };
|
|
44467
|
+
if (view.loggingOff || ((_b = view.snapshot) == null ? void 0 : _b.leg.loggingOff)) return { state: "starting" };
|
|
44468
|
+
if (((_c = view.sessionLost) == null ? void 0 : _c.originator) === "anotherDevice") return { state: "startupError", error: "userIsAlreadyConnectedOnAnotherDevice" };
|
|
44469
|
+
const leg = (_d = view.snapshot) == null ? void 0 : _d.leg;
|
|
44381
44470
|
if (!leg) {
|
|
44382
44471
|
if (view.engine === "starting") return { state: "starting" };
|
|
44383
44472
|
if (view.engine === "running") return { state: "starting" };
|
|
@@ -44392,7 +44481,7 @@ function operatorStateFromView(view, call) {
|
|
|
44392
44481
|
case "ringing":
|
|
44393
44482
|
return { state: "callRinging", call: asCall };
|
|
44394
44483
|
case "dialing":
|
|
44395
|
-
return ((
|
|
44484
|
+
return ((_e = leg.call) == null ? void 0 : _e.state) === "ringing" ? { state: "manualCallRinging", call: asCall } : { state: "manualCallSetup", call: asCall };
|
|
44396
44485
|
case "inCall":
|
|
44397
44486
|
return { state: "callInProgress", call: asCall };
|
|
44398
44487
|
case "afterCall":
|
|
@@ -44405,6 +44494,30 @@ function operatorStateFromView(view, call) {
|
|
|
44405
44494
|
return { state: "startupError", error: "unknownError" };
|
|
44406
44495
|
}
|
|
44407
44496
|
}
|
|
44497
|
+
function operatorStateFromClientState(state, call) {
|
|
44498
|
+
if (state.wsState !== "open" || !state.tabId || !state.view) return { state: "starting" };
|
|
44499
|
+
if (state.rejected) return { state: "startupError", error: "unknownError" };
|
|
44500
|
+
return operatorStateFromView(state.view, call);
|
|
44501
|
+
}
|
|
44502
|
+
function assertEngineCommand(client2, allowDisconnected = false) {
|
|
44503
|
+
var _a2, _b, _c, _d;
|
|
44504
|
+
const state = client2.getState();
|
|
44505
|
+
const view = state.view;
|
|
44506
|
+
const error2 = ((_a2 = state.rejected) == null ? void 0 : _a2.message) ?? ((_b = state.sessionLost) == null ? void 0 : _b.message) ?? (view == null ? void 0 : view.logoffError) ?? ((_c = view == null ? void 0 : view.snapshot) == null ? void 0 : _c.leg.logoffError);
|
|
44507
|
+
if (error2) throw new Error(error2);
|
|
44508
|
+
if ((view == null ? void 0 : view.loggingOff) || ((_d = view == null ? void 0 : view.snapshot) == null ? void 0 : _d.leg.loggingOff)) throw new Error("Aguarde o encerramento da sessão antes de usar o discador.");
|
|
44509
|
+
if (state.wsState !== "open" || !state.tabId || !view) {
|
|
44510
|
+
if (allowDisconnected) return;
|
|
44511
|
+
throw new Error("Sem conexão com o motor. Aguarde a reconexão antes de usar o discador.");
|
|
44512
|
+
}
|
|
44513
|
+
if (view.engine !== "running" || !view.snapshot || view.snapshot.leg.status === "offline" || view.snapshot.leg.status === "error" || view.snapshot.leg.status === "starting") {
|
|
44514
|
+
throw new Error("O atendimento ainda não está conectado ao Callix. Aguarde antes de usar o discador.");
|
|
44515
|
+
}
|
|
44516
|
+
}
|
|
44517
|
+
function engineCommand(client2, command) {
|
|
44518
|
+
assertEngineCommand(client2, command.name === "hangup");
|
|
44519
|
+
client2.command(command);
|
|
44520
|
+
}
|
|
44408
44521
|
function callInfoFromView(view) {
|
|
44409
44522
|
var _a2;
|
|
44410
44523
|
const leg = (_a2 = view == null ? void 0 : view.snapshot) == null ? void 0 : _a2.leg;
|
|
@@ -44436,9 +44549,9 @@ function callInfoFromView(view) {
|
|
|
44436
44549
|
return { type: "manual", info: { successQualifications, discardQualifications } };
|
|
44437
44550
|
}
|
|
44438
44551
|
function useEngineCall(client2) {
|
|
44439
|
-
var _a2, _b;
|
|
44552
|
+
var _a2, _b, _c, _d, _e, _f, _g, _h;
|
|
44440
44553
|
const state = useEngineState(client2);
|
|
44441
|
-
const snapshot = ((_b = (
|
|
44554
|
+
const snapshot = state.wsState === "open" && state.tabId && !((_a2 = state.view) == null ? void 0 : _a2.logoffError) && !((_b = state.view) == null ? void 0 : _b.loggingOff) && !((_d = (_c = state.view) == null ? void 0 : _c.snapshot) == null ? void 0 : _d.leg.logoffError) && !((_f = (_e = state.view) == null ? void 0 : _e.snapshot) == null ? void 0 : _f.leg.loggingOff) ? ((_h = (_g = state.view) == null ? void 0 : _g.snapshot) == null ? void 0 : _h.leg.call) ?? null : null;
|
|
44442
44555
|
const ref = useRef(null);
|
|
44443
44556
|
if (!snapshot || snapshot.state === "ended") {
|
|
44444
44557
|
ref.current = null;
|
|
@@ -44452,7 +44565,7 @@ function useEngineCall(client2) {
|
|
|
44452
44565
|
function useEngineOperatorState(client2) {
|
|
44453
44566
|
const state = useEngineState(client2);
|
|
44454
44567
|
const call = useEngineCall(client2);
|
|
44455
|
-
return useMemo(() =>
|
|
44568
|
+
return useMemo(() => operatorStateFromClientState(state, call), [state, call]);
|
|
44456
44569
|
}
|
|
44457
44570
|
function useEngineCurrentCall(client2) {
|
|
44458
44571
|
const call = useEngineCall(client2);
|
|
@@ -44477,15 +44590,16 @@ function useEngineControls(client2) {
|
|
|
44477
44590
|
() => ({
|
|
44478
44591
|
becomeAvailable: () => {
|
|
44479
44592
|
var _a2, _b;
|
|
44593
|
+
assertEngineCommand(client2);
|
|
44480
44594
|
const status = (_b = (_a2 = client2.getState().view) == null ? void 0 : _a2.snapshot) == null ? void 0 : _b.leg.status;
|
|
44481
|
-
if (status === "onBreak") client2
|
|
44595
|
+
if (status === "onBreak") engineCommand(client2, { name: "resume" });
|
|
44482
44596
|
},
|
|
44483
44597
|
goOffline: () => void 0,
|
|
44484
|
-
enterOnBreak: (breakId) => client2
|
|
44485
|
-
makeManualCall: (phoneNumber) => client2
|
|
44598
|
+
enterOnBreak: (breakId) => engineCommand(client2, pauseCommand(breakId)),
|
|
44599
|
+
makeManualCall: (phoneNumber) => engineCommand(client2, { name: "dial", phone: phoneNumber }),
|
|
44486
44600
|
finishAfterCall: (data) => {
|
|
44487
|
-
if (typeof data.qualificationId === "number") client2
|
|
44488
|
-
else client2
|
|
44601
|
+
if (typeof data.qualificationId === "number") engineCommand(client2, { name: "qualify", qualificationId: data.qualificationId, result: data.result === "failure" ? "discard" : "success" });
|
|
44602
|
+
else engineCommand(client2, { name: "finish" });
|
|
44489
44603
|
}
|
|
44490
44604
|
}),
|
|
44491
44605
|
[client2]
|
|
@@ -44494,9 +44608,9 @@ function useEngineControls(client2) {
|
|
|
44494
44608
|
function useEngineCurrentCallControls(client2) {
|
|
44495
44609
|
return useMemo(
|
|
44496
44610
|
() => ({
|
|
44497
|
-
answer: () => client2
|
|
44498
|
-
reject: () => client2
|
|
44499
|
-
hangup: () => client2
|
|
44611
|
+
answer: () => engineCommand(client2, { name: "answer" }),
|
|
44612
|
+
reject: () => engineCommand(client2, { name: "reject" }),
|
|
44613
|
+
hangup: () => engineCommand(client2, { name: "hangup" }),
|
|
44500
44614
|
isOnHold: () => ({ local: false, remote: false }),
|
|
44501
44615
|
hold: async () => void 0,
|
|
44502
44616
|
unhold: async () => void 0,
|
|
@@ -44549,13 +44663,14 @@ function engineOperator(client2) {
|
|
|
44549
44663
|
goOffline: () => void 0,
|
|
44550
44664
|
becomeAvailable: () => {
|
|
44551
44665
|
var _a2, _b;
|
|
44552
|
-
|
|
44666
|
+
assertEngineCommand(client2);
|
|
44667
|
+
if (((_b = (_a2 = client2.getState().view) == null ? void 0 : _a2.snapshot) == null ? void 0 : _b.leg.status) === "onBreak") engineCommand(client2, { name: "resume" });
|
|
44553
44668
|
},
|
|
44554
|
-
enterOnBreak: (breakId) => client2
|
|
44555
|
-
makeManualCall: (phoneNumber) => client2
|
|
44669
|
+
enterOnBreak: (breakId) => engineCommand(client2, pauseCommand(breakId)),
|
|
44670
|
+
makeManualCall: (phoneNumber) => engineCommand(client2, { name: "dial", phone: phoneNumber }),
|
|
44556
44671
|
finishAfterCall: (data) => {
|
|
44557
|
-
if (typeof data.qualificationId === "number") client2
|
|
44558
|
-
else client2
|
|
44672
|
+
if (typeof data.qualificationId === "number") engineCommand(client2, { name: "qualify", qualificationId: data.qualificationId, result: data.result === "failure" ? "discard" : "success" });
|
|
44673
|
+
else engineCommand(client2, { name: "finish" });
|
|
44559
44674
|
}
|
|
44560
44675
|
};
|
|
44561
44676
|
operators.set(client2, operator);
|
|
@@ -57829,8 +57944,14 @@ function LiveCaptionPanelInner({ client: client2, maxLines }) {
|
|
|
57829
57944
|
] });
|
|
57830
57945
|
}
|
|
57831
57946
|
function useDialerNotices(options = {}) {
|
|
57947
|
+
var _a2, _b, _c;
|
|
57832
57948
|
const operatorState = useCallOperatorState();
|
|
57833
57949
|
const currentCall = useCallOperatorCurrentCall();
|
|
57950
|
+
const engine = useEngineClient();
|
|
57951
|
+
const subscribeEngine = useCallback((listener) => engine ? engine.subscribe(listener) : () => {
|
|
57952
|
+
}, [engine]);
|
|
57953
|
+
const readEngine = useCallback(() => (engine == null ? void 0 : engine.getState()) ?? null, [engine]);
|
|
57954
|
+
const engineState = useSyncExternalStore(subscribeEngine, readEngine, readEngine);
|
|
57834
57955
|
const [deviceIssue, setDeviceIssue] = useState(null);
|
|
57835
57956
|
const [sessionDrop, setSessionDrop] = useState(null);
|
|
57836
57957
|
const [callFailure, setCallFailure] = useState(null);
|
|
@@ -57843,7 +57964,7 @@ function useDialerNotices(options = {}) {
|
|
|
57843
57964
|
setDeviceIssue(issue);
|
|
57844
57965
|
}, [options.checkDevices]);
|
|
57845
57966
|
useEffect(() => {
|
|
57846
|
-
var
|
|
57967
|
+
var _a3;
|
|
57847
57968
|
if (options.checkDevices === false) return;
|
|
57848
57969
|
let cancelled = false;
|
|
57849
57970
|
const run = async () => {
|
|
@@ -57853,11 +57974,11 @@ function useDialerNotices(options = {}) {
|
|
|
57853
57974
|
void run();
|
|
57854
57975
|
const mediaDevices = typeof navigator !== "undefined" ? navigator.mediaDevices : void 0;
|
|
57855
57976
|
const handler = () => void run();
|
|
57856
|
-
(
|
|
57977
|
+
(_a3 = mediaDevices == null ? void 0 : mediaDevices.addEventListener) == null ? void 0 : _a3.call(mediaDevices, "devicechange", handler);
|
|
57857
57978
|
return () => {
|
|
57858
|
-
var
|
|
57979
|
+
var _a4;
|
|
57859
57980
|
cancelled = true;
|
|
57860
|
-
(
|
|
57981
|
+
(_a4 = mediaDevices == null ? void 0 : mediaDevices.removeEventListener) == null ? void 0 : _a4.call(mediaDevices, "devicechange", handler);
|
|
57861
57982
|
};
|
|
57862
57983
|
}, [options.checkDevices]);
|
|
57863
57984
|
useCallOperatorEventListener("userSessionDropped", (data) => {
|
|
@@ -57866,8 +57987,8 @@ function useDialerNotices(options = {}) {
|
|
|
57866
57987
|
useEffect(() => {
|
|
57867
57988
|
if (!(currentCall == null ? void 0 : currentCall.on)) return;
|
|
57868
57989
|
const handleFailed = (event) => {
|
|
57869
|
-
var
|
|
57870
|
-
const failure = (event == null ? void 0 : event.failure) ?? ((
|
|
57990
|
+
var _a3;
|
|
57991
|
+
const failure = (event == null ? void 0 : event.failure) ?? ((_a3 = currentCall.toCallData) == null ? void 0 : _a3.call(currentCall).failure) ?? null;
|
|
57871
57992
|
setCallFailure(failure ?? { cause: null });
|
|
57872
57993
|
setDismissedCode(null);
|
|
57873
57994
|
if (failureTimer.current) clearTimeout(failureTimer.current);
|
|
@@ -57875,14 +57996,14 @@ function useDialerNotices(options = {}) {
|
|
|
57875
57996
|
};
|
|
57876
57997
|
currentCall.on("failed", handleFailed);
|
|
57877
57998
|
return () => {
|
|
57878
|
-
var
|
|
57879
|
-
(
|
|
57999
|
+
var _a3;
|
|
58000
|
+
(_a3 = currentCall.off) == null ? void 0 : _a3.call(currentCall, "failed", handleFailed);
|
|
57880
58001
|
};
|
|
57881
58002
|
}, [currentCall, ttl]);
|
|
57882
58003
|
useEffect(() => {
|
|
57883
|
-
var
|
|
58004
|
+
var _a3, _b2;
|
|
57884
58005
|
if ((operatorState == null ? void 0 : operatorState.state) !== "manualCallFailed") return;
|
|
57885
|
-
const failure = ((
|
|
58006
|
+
const failure = ((_b2 = (_a3 = operatorState.call) == null ? void 0 : _a3.toCallData) == null ? void 0 : _b2.call(_a3).failure) ?? null;
|
|
57886
58007
|
setCallFailure((current) => current ?? failure ?? { cause: null });
|
|
57887
58008
|
setDismissedCode(null);
|
|
57888
58009
|
}, [operatorState]);
|
|
@@ -57895,13 +58016,26 @@ function useDialerNotices(options = {}) {
|
|
|
57895
58016
|
useEffect(() => () => {
|
|
57896
58017
|
if (failureTimer.current) clearTimeout(failureTimer.current);
|
|
57897
58018
|
}, []);
|
|
57898
|
-
|
|
58019
|
+
let notice = pickNotice({
|
|
57899
58020
|
deviceIssue,
|
|
57900
58021
|
operatorState: (operatorState == null ? void 0 : operatorState.state) ?? null,
|
|
57901
58022
|
startupError: (operatorState == null ? void 0 : operatorState.state) === "startupError" ? operatorState.error ?? null : null,
|
|
57902
58023
|
sessionDrop,
|
|
57903
58024
|
callFailure
|
|
57904
58025
|
});
|
|
58026
|
+
const logoffError = ((_a2 = engineState == null ? void 0 : engineState.view) == null ? void 0 : _a2.logoffError) ?? ((_c = (_b = engineState == null ? void 0 : engineState.view) == null ? void 0 : _b.snapshot) == null ? void 0 : _c.leg.logoffError);
|
|
58027
|
+
const reconnecting = Boolean(engineState && (engineState.wsState !== "open" || !engineState.tabId));
|
|
58028
|
+
const engineError = logoffError ?? (engineState == null ? void 0 : engineState.lastError);
|
|
58029
|
+
if (engineState && !sessionDrop && (engineError || reconnecting)) {
|
|
58030
|
+
notice = {
|
|
58031
|
+
level: "error",
|
|
58032
|
+
source: "offline",
|
|
58033
|
+
title: logoffError ? "Saída não concluída" : reconnecting ? "Reconectando ao discador" : "Comando não concluído",
|
|
58034
|
+
detail: engineError || "Aguardando a conexão e o estado atual do motor.",
|
|
58035
|
+
action: logoffError ? "Clique em Sair novamente para concluir o encerramento da sessão." : reconnecting ? "Aguarde a conexão voltar antes de ligar." : "Confira o estado do discador e tente novamente.",
|
|
58036
|
+
code: logoffError ? "engine:logoff" : reconnecting ? "engine:reconnecting" : "engine:command"
|
|
58037
|
+
};
|
|
58038
|
+
}
|
|
57905
58039
|
const visible = notice && notice.code !== dismissedCode ? notice : null;
|
|
57906
58040
|
const dismiss = useCallback(() => {
|
|
57907
58041
|
if (!notice) return;
|
|
@@ -58735,7 +58869,7 @@ function AuthenticatedMobileDialer({
|
|
|
58735
58869
|
showClientInfoModal = false,
|
|
58736
58870
|
density
|
|
58737
58871
|
}) {
|
|
58738
|
-
var _a2, _b, _c, _d, _e
|
|
58872
|
+
var _a2, _b, _c, _d, _e;
|
|
58739
58873
|
const { skipManualQualification } = useDialerConfig();
|
|
58740
58874
|
const [dialValue, setDialValue] = useState("");
|
|
58741
58875
|
const [activeScreen, setActiveScreen] = useState("dialer");
|
|
@@ -58749,7 +58883,6 @@ function AuthenticatedMobileDialer({
|
|
|
58749
58883
|
const [isClientInfoModalOpen, setIsClientInfoModalOpen] = useState(false);
|
|
58750
58884
|
const [isDebugPanelOpen, setIsDebugPanelOpen] = useState(false);
|
|
58751
58885
|
useDebugLogger();
|
|
58752
|
-
const [currentBreakName, setCurrentBreakName] = useState(null);
|
|
58753
58886
|
const [pauseStartTime, setPauseStartTime] = useState(null);
|
|
58754
58887
|
const [pauseDurationSeconds, setPauseDurationSeconds] = useState(0);
|
|
58755
58888
|
const [contactData, setContactData] = useState({
|
|
@@ -58785,6 +58918,10 @@ function AuthenticatedMobileDialer({
|
|
|
58785
58918
|
const breaks = useSignal(operator == null ? void 0 : operator.breaks) || [];
|
|
58786
58919
|
const userData = useSignal(operator == null ? void 0 : operator.user);
|
|
58787
58920
|
const isOnBreak = (operatorState == null ? void 0 : operatorState.state) === "onBreak";
|
|
58921
|
+
const activeBreak = (operatorState == null ? void 0 : operatorState.state) === "onBreak" ? operatorState.break : void 0;
|
|
58922
|
+
const activeBreakId = activeBreak == null ? void 0 : activeBreak.id;
|
|
58923
|
+
const hasConfirmedPauseState = isOnBreak || ["idle", "manualCallSetup", "manualCallRinging", "manualCallFailed", "callRinging", "callInProgress", "afterCall"].includes((operatorState == null ? void 0 : operatorState.state) ?? "");
|
|
58924
|
+
const previousBreakRef = useRef({ isOnBreak, id: activeBreakId, confirmed: hasConfirmedPauseState });
|
|
58788
58925
|
const [inputMuted, setInputMuted] = useCallOperatorAudioInputMuted();
|
|
58789
58926
|
const haptic = useHaptic();
|
|
58790
58927
|
const dtmf = useDTMF({ enabled: true });
|
|
@@ -58884,8 +59021,12 @@ function AuthenticatedMobileDialer({
|
|
|
58884
59021
|
const INITIAL_BREAK_ID = 5;
|
|
58885
59022
|
const INITIAL_BREAK_NAME = "Reunião";
|
|
58886
59023
|
const callState = operatorState == null ? void 0 : operatorState.state;
|
|
58887
|
-
const hasEnteredInitialBreakRef = useRef(
|
|
59024
|
+
const hasEnteredInitialBreakRef = useRef(isOnBreak);
|
|
58888
59025
|
useEffect(() => {
|
|
59026
|
+
if (isOnBreak) {
|
|
59027
|
+
hasEnteredInitialBreakRef.current = true;
|
|
59028
|
+
return;
|
|
59029
|
+
}
|
|
58889
59030
|
if (breaks.length === 0 || callState !== "idle" || hasEnteredInitialBreakRef.current || isOnBreak) {
|
|
58890
59031
|
return;
|
|
58891
59032
|
}
|
|
@@ -58898,10 +59039,8 @@ function AuthenticatedMobileDialer({
|
|
|
58898
59039
|
);
|
|
58899
59040
|
if (reuniaoBreak) {
|
|
58900
59041
|
console.log("[MobileDialer] Operador conectado (idle), entrando em pausa inicial:", reuniaoBreak.name);
|
|
58901
|
-
Promise.resolve(goOnBreak(reuniaoBreak.id)).then(() => {
|
|
58902
|
-
console.log("[MobileDialer] Pausa inicial
|
|
58903
|
-
setCurrentBreakName(reuniaoBreak.name);
|
|
58904
|
-
setPauseStartTime(Date.now());
|
|
59042
|
+
Promise.resolve().then(() => goOnBreak(reuniaoBreak.id)).then(() => {
|
|
59043
|
+
console.log("[MobileDialer] Pausa inicial solicitada:", reuniaoBreak.name);
|
|
58905
59044
|
}).catch((err) => {
|
|
58906
59045
|
console.error("[MobileDialer] Falha ao entrar em pausa:", err);
|
|
58907
59046
|
hasEnteredInitialBreakRef.current = false;
|
|
@@ -58909,10 +59048,8 @@ function AuthenticatedMobileDialer({
|
|
|
58909
59048
|
} else {
|
|
58910
59049
|
const firstBreak = breaks[0];
|
|
58911
59050
|
console.log('[MobileDialer] Pausa "Reunião" não encontrada, usando:', firstBreak.name);
|
|
58912
|
-
Promise.resolve(goOnBreak(firstBreak.id)).then(() => {
|
|
58913
|
-
console.log("[MobileDialer] Pausa inicial
|
|
58914
|
-
setCurrentBreakName(firstBreak.name);
|
|
58915
|
-
setPauseStartTime(Date.now());
|
|
59051
|
+
Promise.resolve().then(() => goOnBreak(firstBreak.id)).then(() => {
|
|
59052
|
+
console.log("[MobileDialer] Pausa inicial solicitada:", firstBreak.name);
|
|
58916
59053
|
}).catch((err) => {
|
|
58917
59054
|
console.error("[MobileDialer] Falha ao entrar em pausa:", err);
|
|
58918
59055
|
hasEnteredInitialBreakRef.current = false;
|
|
@@ -58994,7 +59131,8 @@ function AuthenticatedMobileDialer({
|
|
|
58994
59131
|
const { notice: dialerNotice, dismiss: dismissDialerNotice, recheckDevices } = useDialerNotices();
|
|
58995
59132
|
const [noticeHeight, setNoticeHeight] = useState(0);
|
|
58996
59133
|
const isError = callStateStr === "startupError" || callStateStr === "offline" || (dialerNotice == null ? void 0 : dialerNotice.source) === "device" || (dialerNotice == null ? void 0 : dialerNotice.source) === "session";
|
|
58997
|
-
const
|
|
59134
|
+
const isReconnecting = !callStateStr || callStateStr === "starting";
|
|
59135
|
+
const isIdle = callStateStr === "idle" || callStateStr === "onBreak";
|
|
58998
59136
|
const isConnecting = callState === "manualCallSetup" || callState === "manualCallRinging" || callState === "callRinging";
|
|
58999
59137
|
const isInCall = callState === "callInProgress";
|
|
59000
59138
|
const isAfterCall = callState === "afterCall";
|
|
@@ -59027,22 +59165,32 @@ function AuthenticatedMobileDialer({
|
|
|
59027
59165
|
return () => clearInterval(interval);
|
|
59028
59166
|
}, [isInCall]);
|
|
59029
59167
|
useEffect(() => {
|
|
59030
|
-
|
|
59168
|
+
const previous = previousBreakRef.current;
|
|
59169
|
+
if (!hasConfirmedPauseState) {
|
|
59170
|
+
previousBreakRef.current = { ...previous, confirmed: false };
|
|
59031
59171
|
return;
|
|
59032
59172
|
}
|
|
59033
|
-
|
|
59034
|
-
|
|
59035
|
-
setPauseDurationSeconds(elapsed);
|
|
59036
|
-
}, 1e3);
|
|
59037
|
-
return () => clearInterval(interval);
|
|
59038
|
-
}, [isOnBreak, pauseStartTime]);
|
|
59039
|
-
useEffect(() => {
|
|
59040
|
-
if (!isOnBreak && currentBreakName) {
|
|
59041
|
-
setCurrentBreakName(null);
|
|
59173
|
+
previousBreakRef.current = { isOnBreak, id: activeBreakId, confirmed: true };
|
|
59174
|
+
if (!isOnBreak) {
|
|
59042
59175
|
setPauseStartTime(null);
|
|
59043
59176
|
setPauseDurationSeconds(0);
|
|
59177
|
+
} else if (previous.confirmed && !previous.isOnBreak || previous.isOnBreak && previous.id !== activeBreakId) {
|
|
59178
|
+
setPauseStartTime(Date.now());
|
|
59179
|
+
setPauseDurationSeconds(0);
|
|
59044
59180
|
}
|
|
59045
|
-
}, [isOnBreak,
|
|
59181
|
+
}, [isOnBreak, activeBreakId, hasConfirmedPauseState]);
|
|
59182
|
+
useEffect(() => {
|
|
59183
|
+
if (!isOnBreak || pauseStartTime === null) {
|
|
59184
|
+
return;
|
|
59185
|
+
}
|
|
59186
|
+
const update2 = () => {
|
|
59187
|
+
const elapsed = Math.max(0, Math.floor((Date.now() - pauseStartTime) / 1e3));
|
|
59188
|
+
setPauseDurationSeconds(elapsed);
|
|
59189
|
+
};
|
|
59190
|
+
update2();
|
|
59191
|
+
const interval = setInterval(update2, 1e3);
|
|
59192
|
+
return () => clearInterval(interval);
|
|
59193
|
+
}, [isOnBreak, pauseStartTime]);
|
|
59046
59194
|
useEffect(() => {
|
|
59047
59195
|
const onClickToCall = (event) => {
|
|
59048
59196
|
const task = event.detail;
|
|
@@ -59168,6 +59316,7 @@ function AuthenticatedMobileDialer({
|
|
|
59168
59316
|
setDialValue((prev) => prev.slice(0, -1));
|
|
59169
59317
|
}, [haptic]);
|
|
59170
59318
|
const handleCall = useCallback(async () => {
|
|
59319
|
+
if (!isIdle) return;
|
|
59171
59320
|
console.log("[MobileDialer] handleCall triggered, dialValue:", dialValue);
|
|
59172
59321
|
addLog("event", "Call", "📞 Iniciando chamada manual", { dialValue });
|
|
59173
59322
|
const sanitized = sanitizeInput(dialValue);
|
|
@@ -59200,7 +59349,7 @@ function AuthenticatedMobileDialer({
|
|
|
59200
59349
|
setCallError("Erro ao iniciar chamada.");
|
|
59201
59350
|
haptic.notificationError();
|
|
59202
59351
|
}
|
|
59203
|
-
}, [dialValue, makeManualCall, sanitizeInput, haptic]);
|
|
59352
|
+
}, [dialValue, makeManualCall, sanitizeInput, haptic, isIdle]);
|
|
59204
59353
|
const handleHangup = useCallback(async () => {
|
|
59205
59354
|
if (!hangup) return;
|
|
59206
59355
|
addLog("event", "Call", "📴 Encerrando chamada");
|
|
@@ -59372,28 +59521,21 @@ function AuthenticatedMobileDialer({
|
|
|
59372
59521
|
async (breakId) => {
|
|
59373
59522
|
if (!goOnBreak) return;
|
|
59374
59523
|
try {
|
|
59375
|
-
const selectedBreak = breaks.find((b) => b.id === breakId);
|
|
59376
59524
|
await goOnBreak(breakId);
|
|
59377
59525
|
haptic.notificationSuccess();
|
|
59378
|
-
setCurrentBreakName((selectedBreak == null ? void 0 : selectedBreak.name) ?? "Em pausa");
|
|
59379
|
-
setPauseStartTime(Date.now());
|
|
59380
|
-
setPauseDurationSeconds(0);
|
|
59381
59526
|
setIsPauseModalOpen(false);
|
|
59382
59527
|
} catch (error2) {
|
|
59383
59528
|
console.error("Erro ao entrar em pausa", error2);
|
|
59384
59529
|
haptic.notificationError();
|
|
59385
59530
|
}
|
|
59386
59531
|
},
|
|
59387
|
-
[goOnBreak,
|
|
59532
|
+
[goOnBreak, haptic]
|
|
59388
59533
|
);
|
|
59389
59534
|
const handleGoOffBreak = useCallback(async () => {
|
|
59390
59535
|
if (!goOffBreak) return;
|
|
59391
59536
|
try {
|
|
59392
59537
|
await goOffBreak();
|
|
59393
59538
|
haptic.notificationSuccess();
|
|
59394
|
-
setCurrentBreakName(null);
|
|
59395
|
-
setPauseStartTime(null);
|
|
59396
|
-
setPauseDurationSeconds(0);
|
|
59397
59539
|
setIsPauseModalOpen(false);
|
|
59398
59540
|
} catch (error2) {
|
|
59399
59541
|
console.error("Erro ao sair de pausa", error2);
|
|
@@ -59439,6 +59581,7 @@ function AuthenticatedMobileDialer({
|
|
|
59439
59581
|
return activeCallNumber ? formatPhoneForDisplay(activeCallNumber) : "(--) ----- ----";
|
|
59440
59582
|
}, [callInfo, formattedDial, activeCallNumber]);
|
|
59441
59583
|
const callStatusLabel = useMemo(() => {
|
|
59584
|
+
if (isReconnecting) return "Conectando...";
|
|
59442
59585
|
if (isConnecting) return "Ligando...";
|
|
59443
59586
|
if (isInCall) return "Em chamada";
|
|
59444
59587
|
if (isAfterCall) return "Encerrando...";
|
|
@@ -59446,19 +59589,22 @@ function AuthenticatedMobileDialer({
|
|
|
59446
59589
|
if (isError) return (dialerNotice == null ? void 0 : dialerNotice.title) ?? "Erro de conexão";
|
|
59447
59590
|
if (isOnBreak) return "Em pausa";
|
|
59448
59591
|
return "Disponível";
|
|
59449
|
-
}, [callStateStr, dialerNotice, isAfterCall, isConnecting, isError, isInCall, isOnBreak]);
|
|
59592
|
+
}, [callStateStr, dialerNotice, isAfterCall, isConnecting, isError, isInCall, isOnBreak, isReconnecting]);
|
|
59450
59593
|
const statusBadgeClass = useMemo(() => {
|
|
59594
|
+
if (isReconnecting) return "connecting";
|
|
59451
59595
|
if (isError) return "error";
|
|
59452
59596
|
if (isOnBreak) return "paused";
|
|
59453
59597
|
return "available";
|
|
59454
|
-
}, [isError, isOnBreak]);
|
|
59455
|
-
const activeBreakName =
|
|
59598
|
+
}, [isError, isOnBreak, isReconnecting]);
|
|
59599
|
+
const activeBreakName = activeBreak == null ? void 0 : activeBreak.name;
|
|
59456
59600
|
const statusBadgeText = useMemo(() => {
|
|
59601
|
+
if (isReconnecting) return "Conectando";
|
|
59457
59602
|
if (isError) return (dialerNotice == null ? void 0 : dialerNotice.source) === "device" ? dialerNotice.title : "Erro";
|
|
59458
|
-
if (isOnBreak) return
|
|
59603
|
+
if (isOnBreak) return activeBreakName || "Em pausa";
|
|
59459
59604
|
return "Disponível";
|
|
59460
|
-
}, [dialerNotice, isError, isOnBreak,
|
|
59605
|
+
}, [dialerNotice, isError, isOnBreak, activeBreakName, isReconnecting]);
|
|
59461
59606
|
const pauseDurationLabel = useMemo(() => {
|
|
59607
|
+
if (pauseStartTime === null) return "--:--";
|
|
59462
59608
|
const hours = Math.floor(pauseDurationSeconds / 3600);
|
|
59463
59609
|
const minutes = Math.floor(pauseDurationSeconds % 3600 / 60).toString().padStart(2, "0");
|
|
59464
59610
|
const seconds = (pauseDurationSeconds % 60).toString().padStart(2, "0");
|
|
@@ -59466,7 +59612,7 @@ function AuthenticatedMobileDialer({
|
|
|
59466
59612
|
return `${hours}:${minutes}:${seconds}`;
|
|
59467
59613
|
}
|
|
59468
59614
|
return `${minutes}:${seconds}`;
|
|
59469
|
-
}, [pauseDurationSeconds]);
|
|
59615
|
+
}, [pauseDurationSeconds, pauseStartTime]);
|
|
59470
59616
|
const callDurationLabel = useMemo(() => {
|
|
59471
59617
|
const m = Math.floor(callDurationSeconds / 60).toString().padStart(2, "0");
|
|
59472
59618
|
const s = (callDurationSeconds % 60).toString().padStart(2, "0");
|
|
@@ -59507,7 +59653,7 @@ function AuthenticatedMobileDialer({
|
|
|
59507
59653
|
isOnBreak ? /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { className: "resume-btn", id: "resumeBtn", onClick: handleGoOffBreak, children: [
|
|
59508
59654
|
/* @__PURE__ */ jsxRuntimeExports.jsx("i", { className: "fas fa-play" }),
|
|
59509
59655
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Voltar" })
|
|
59510
|
-
] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { className: "pause-btn", id: "pauseBtn", onClick: () => setIsPauseModalOpen(true), children: [
|
|
59656
|
+
] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { className: "pause-btn", id: "pauseBtn", disabled: isReconnecting || callStateStr === "offline" || callStateStr === "startupError", onClick: () => setIsPauseModalOpen(true), children: [
|
|
59511
59657
|
/* @__PURE__ */ jsxRuntimeExports.jsx("i", { className: "fas fa-pause" }),
|
|
59512
59658
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Pausa" })
|
|
59513
59659
|
] }),
|
|
@@ -59595,15 +59741,15 @@ function AuthenticatedMobileDialer({
|
|
|
59595
59741
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "client-card-header", children: [
|
|
59596
59742
|
/* @__PURE__ */ jsxRuntimeExports.jsx("i", { className: "fas fa-user-circle client-avatar" }),
|
|
59597
59743
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "client-main-info", children: [
|
|
59598
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "client-name", id: "clientName", children: findValue(contactData.finalData, ["DECISOR", "NOME", "CLIENTE", "PROSPECT"]) ?? ((
|
|
59599
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "client-company", id: "clientCompany", children: findValue(contactData.finalData, ["EMPRESA", "RAZAO SOCIAL", "RAZÃO SOCIAL", "RAZAO_SOCIAL"]) ?? ((
|
|
59744
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "client-name", id: "clientName", children: findValue(contactData.finalData, ["DECISOR", "NOME", "CLIENTE", "PROSPECT"]) ?? ((_b = callInfo.info.campaignContact) == null ? void 0 : _b.label) ?? "--" }),
|
|
59745
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "client-company", id: "clientCompany", children: findValue(contactData.finalData, ["EMPRESA", "RAZAO SOCIAL", "RAZÃO SOCIAL", "RAZAO_SOCIAL"]) ?? ((_c = callInfo.info.campaign) == null ? void 0 : _c.name) ?? "--" })
|
|
59600
59746
|
] })
|
|
59601
59747
|
] }),
|
|
59602
59748
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "client-card-divider" }),
|
|
59603
59749
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "client-info-list", children: [
|
|
59604
59750
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "client-info-row", children: [
|
|
59605
59751
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "client-info-label", children: "Socio" }),
|
|
59606
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "client-info-value", children: findValue(contactData.finalData, ["SOCIO", "PROSPECT", "DECISOR", "NOME", "CLIENTE"]) ?? ((
|
|
59752
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "client-info-value", children: findValue(contactData.finalData, ["SOCIO", "PROSPECT", "DECISOR", "NOME", "CLIENTE"]) ?? ((_d = callInfo.info.campaignContact) == null ? void 0 : _d.label) ?? "--" })
|
|
59607
59753
|
] }),
|
|
59608
59754
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "client-info-row", children: [
|
|
59609
59755
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "client-info-label", children: "Empresa" }),
|
|
@@ -59800,7 +59946,7 @@ function AuthenticatedMobileDialer({
|
|
|
59800
59946
|
{
|
|
59801
59947
|
isOpen: isClientInfoModalOpen,
|
|
59802
59948
|
campaignCallInfo,
|
|
59803
|
-
campaignContactPhoneId: ((
|
|
59949
|
+
campaignContactPhoneId: ((_e = currentCall == null ? void 0 : currentCall.data) == null ? void 0 : _e.campaignContactPhoneId) ?? null,
|
|
59804
59950
|
callDuration: callDurationSeconds,
|
|
59805
59951
|
isCallActive: isInCall || isConnecting,
|
|
59806
59952
|
onClose: () => setIsClientInfoModalOpen(false)
|
|
@@ -60362,6 +60508,27 @@ function AuthenticatedMiniDialer({
|
|
|
60362
60508
|
)
|
|
60363
60509
|
] });
|
|
60364
60510
|
}
|
|
60511
|
+
async function endUserSdkSession(apiUrl, token, timeoutMs = 2e4) {
|
|
60512
|
+
const controller = new AbortController();
|
|
60513
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
60514
|
+
try {
|
|
60515
|
+
const response = await fetch(apiUrl, {
|
|
60516
|
+
method: "DELETE",
|
|
60517
|
+
headers: { Authorization: `Bearer ${token}`, "x-session-token": token },
|
|
60518
|
+
credentials: "same-origin",
|
|
60519
|
+
signal: controller.signal
|
|
60520
|
+
});
|
|
60521
|
+
const data = await response.json().catch(() => null);
|
|
60522
|
+
if (!response.ok || (data == null ? void 0 : data.success) === false) {
|
|
60523
|
+
throw new Error((data == null ? void 0 : data.error) || `O Callix não confirmou o encerramento da sessão (${response.status}).`);
|
|
60524
|
+
}
|
|
60525
|
+
} catch (error2) {
|
|
60526
|
+
if (controller.signal.aborted) throw new Error("O Callix não respondeu ao pedido de encerramento da sessão.");
|
|
60527
|
+
throw error2;
|
|
60528
|
+
} finally {
|
|
60529
|
+
clearTimeout(timer);
|
|
60530
|
+
}
|
|
60531
|
+
}
|
|
60365
60532
|
const PROBE_TIMEOUT_MS = 600;
|
|
60366
60533
|
const TAKEOVER_GRACE_MS = 3e3;
|
|
60367
60534
|
const TAKEOVER_JITTER_MS = 600;
|
|
@@ -60814,7 +60981,7 @@ function ClickToCallAgent({ enabled = true, pollIntervalMs, sessionToken, onTask
|
|
|
60814
60981
|
}, [enabled, pollIntervalMs, sessionToken]);
|
|
60815
60982
|
return null;
|
|
60816
60983
|
}
|
|
60817
|
-
const WIDGET_VERSION = "2.8.
|
|
60984
|
+
const WIDGET_VERSION = "2.8.5";
|
|
60818
60985
|
let currentSipWebSocket = null;
|
|
60819
60986
|
function sendSipUnregisterIfPossible(ws) {
|
|
60820
60987
|
if (ws.readyState !== WebSocket.OPEN) return;
|
|
@@ -61172,6 +61339,7 @@ function DialerWrapper({ options, containerEl }) {
|
|
|
61172
61339
|
const [tabDecided, setTabDecided] = useState(false);
|
|
61173
61340
|
const [tabNote, setTabNote] = useState(null);
|
|
61174
61341
|
const [engineWaiting, setEngineWaiting] = useState(false);
|
|
61342
|
+
const [engineError, setEngineError] = useState(null);
|
|
61175
61343
|
const busRef = useRef(null);
|
|
61176
61344
|
const takeoverTimerRef = useRef(null);
|
|
61177
61345
|
const isAuthenticatedRef = useRef(false);
|
|
@@ -61179,6 +61347,8 @@ function DialerWrapper({ options, containerEl }) {
|
|
|
61179
61347
|
const isLoadingRef = useRef(false);
|
|
61180
61348
|
isLoadingRef.current = isLoading;
|
|
61181
61349
|
const logoffPendingRef = useRef(false);
|
|
61350
|
+
const logoutInFlightRef = useRef(null);
|
|
61351
|
+
const logoutRetryRef = useRef(false);
|
|
61182
61352
|
const handleLoginRef = useRef(async () => void 0);
|
|
61183
61353
|
const handleLogoutRef = useRef(async () => void 0);
|
|
61184
61354
|
const cancelTakeover = useCallback(() => {
|
|
@@ -61223,6 +61393,7 @@ function DialerWrapper({ options, containerEl }) {
|
|
|
61223
61393
|
log: (message) => console.log("[Callix Dialer/motor]", message)
|
|
61224
61394
|
});
|
|
61225
61395
|
client2.onSessionLost((lost) => {
|
|
61396
|
+
if (logoffPendingRef.current) return;
|
|
61226
61397
|
const notice = describeSessionDrop(lost.originator);
|
|
61227
61398
|
setError(`${notice.title}: ${notice.detail}${notice.action ? ` ${notice.action}` : ""}`);
|
|
61228
61399
|
setIsAuthenticated(false);
|
|
@@ -61321,6 +61492,7 @@ function DialerWrapper({ options, containerEl }) {
|
|
|
61321
61492
|
[options.domain, options.apiUrl]
|
|
61322
61493
|
);
|
|
61323
61494
|
const enterEngine = useCallback(async (user, domain, token) => {
|
|
61495
|
+
var _a2, _b, _c, _d;
|
|
61324
61496
|
if (token) {
|
|
61325
61497
|
const skip = await fetchSkipQualification(domain, token);
|
|
61326
61498
|
if (skip !== null) {
|
|
@@ -61331,6 +61503,16 @@ function DialerWrapper({ options, containerEl }) {
|
|
|
61331
61503
|
}
|
|
61332
61504
|
}
|
|
61333
61505
|
}
|
|
61506
|
+
const engineState = (_a2 = engineRef.current) == null ? void 0 : _a2.getState();
|
|
61507
|
+
if (!engineState || engineState.wsState !== "open" || !engineState.tabId || !engineState.view || engineState.rejected) {
|
|
61508
|
+
throw new Error("A conexão com o motor caiu. Aguarde a reconexão antes de entrar.");
|
|
61509
|
+
}
|
|
61510
|
+
if (engineState.view.engine !== "running" && engineState.view.engine !== "starting" || engineState.sessionLost || engineState.view.sessionLost) {
|
|
61511
|
+
throw new Error("A sessão do motor foi encerrada durante a entrada. Entre novamente.");
|
|
61512
|
+
}
|
|
61513
|
+
if (engineState.view.logoffError || engineState.view.loggingOff || ((_b = engineState.view.snapshot) == null ? void 0 : _b.leg.logoffError) || ((_c = engineState.view.snapshot) == null ? void 0 : _c.leg.loggingOff)) {
|
|
61514
|
+
throw new Error(engineState.view.logoffError || ((_d = engineState.view.snapshot) == null ? void 0 : _d.leg.logoffError) || "A sessão anterior ainda está sendo encerrada.");
|
|
61515
|
+
}
|
|
61334
61516
|
try {
|
|
61335
61517
|
localStorage.setItem(LAST_USERNAME_KEY, user);
|
|
61336
61518
|
if (token) {
|
|
@@ -61371,12 +61553,15 @@ function DialerWrapper({ options, containerEl }) {
|
|
|
61371
61553
|
if (!engineMode || !username || isRestoringSession) return;
|
|
61372
61554
|
const user = username;
|
|
61373
61555
|
const client2 = ensureEngine(user);
|
|
61374
|
-
|
|
61556
|
+
const initial = client2.getState();
|
|
61557
|
+
setEngineWaiting(initial.wsState !== "open" || !initial.tabId || !initial.view);
|
|
61375
61558
|
const fallback = setTimeout(() => setEngineWaiting(false), 15e3);
|
|
61376
61559
|
let joining = false;
|
|
61377
61560
|
let rejectedNote = false;
|
|
61378
61561
|
const sync = () => {
|
|
61379
|
-
|
|
61562
|
+
var _a2;
|
|
61563
|
+
const { view, sessionLost, rejected, wsState, tabId, lastError } = client2.getState();
|
|
61564
|
+
setEngineError((view == null ? void 0 : view.logoffError) ?? ((_a2 = view == null ? void 0 : view.snapshot) == null ? void 0 : _a2.leg.logoffError) ?? lastError ?? null);
|
|
61380
61565
|
if (!rejected && rejectedNote) {
|
|
61381
61566
|
rejectedNote = false;
|
|
61382
61567
|
setTabNote(null);
|
|
@@ -61394,11 +61579,10 @@ function DialerWrapper({ options, containerEl }) {
|
|
|
61394
61579
|
setTabNote(rejected.message);
|
|
61395
61580
|
return;
|
|
61396
61581
|
}
|
|
61397
|
-
if (!view) return;
|
|
61582
|
+
if (wsState !== "open" || !tabId || !view) return;
|
|
61398
61583
|
setEngineWaiting(false);
|
|
61399
|
-
if (view.engine === "stopped" || view.engine === "crashed") logoffPendingRef.current = false;
|
|
61400
61584
|
const hasSession = (view.engine === "running" || view.engine === "starting") && !sessionLost;
|
|
61401
|
-
if (hasSession && !logoffPendingRef.current && !isAuthenticatedRef.current && !isLoadingRef.current && !joining) {
|
|
61585
|
+
if (hasSession && !view.loggingOff && !view.logoffError && !logoffPendingRef.current && !isAuthenticatedRef.current && !isLoadingRef.current && !joining) {
|
|
61402
61586
|
joining = true;
|
|
61403
61587
|
console.log("[Callix Dialer] o motor já segura a sessão deste agente; entrando por aqui também");
|
|
61404
61588
|
void joinEngine(user).finally(() => {
|
|
@@ -61567,6 +61751,11 @@ function DialerWrapper({ options, containerEl }) {
|
|
|
61567
61751
|
}, [engineMode, tabRole, username]);
|
|
61568
61752
|
const handleLogin = useCallback(async (user) => {
|
|
61569
61753
|
var _a2, _b, _c, _d;
|
|
61754
|
+
if (logoutInFlightRef.current) return;
|
|
61755
|
+
if (logoutRetryRef.current) {
|
|
61756
|
+
await handleLogoutRef.current({ broadcast: false });
|
|
61757
|
+
if (logoutRetryRef.current) return;
|
|
61758
|
+
}
|
|
61570
61759
|
setIsLoading(true);
|
|
61571
61760
|
setError(null);
|
|
61572
61761
|
setLoginStatus("Preparando login...");
|
|
@@ -61585,6 +61774,9 @@ function DialerWrapper({ options, containerEl }) {
|
|
|
61585
61774
|
console.log("[Callix Dialer] o motor recusou a credencial desta aba; fazendo login novo que substitui a sessão de lá");
|
|
61586
61775
|
}
|
|
61587
61776
|
const domain = engineDomain();
|
|
61777
|
+
if ((view == null ? void 0 : view.loggingOff) || (view == null ? void 0 : view.logoffError) && (view.engine === "running" || view.engine === "starting")) {
|
|
61778
|
+
throw new Error(view.logoffError || "A sessão anterior ainda está sendo encerrada. Aguarde antes de entrar novamente.");
|
|
61779
|
+
}
|
|
61588
61780
|
const engineHasSession = view !== null && (view.engine === "running" || view.engine === "starting") && !view.sessionLost;
|
|
61589
61781
|
let token = null;
|
|
61590
61782
|
if (engineHasSession) {
|
|
@@ -61800,54 +61992,116 @@ function DialerWrapper({ options, containerEl }) {
|
|
|
61800
61992
|
useEffect(() => {
|
|
61801
61993
|
handleLoginRef.current = handleLogin;
|
|
61802
61994
|
}, [handleLogin]);
|
|
61803
|
-
const handleLogout = useCallback(
|
|
61804
|
-
|
|
61995
|
+
const handleLogout = useCallback((opts) => {
|
|
61996
|
+
if (logoutInFlightRef.current) return logoutInFlightRef.current;
|
|
61805
61997
|
const broadcast = (opts == null ? void 0 : opts.broadcast) !== false;
|
|
61806
61998
|
const keepDecision = (opts == null ? void 0 : opts.keepDecision) === true;
|
|
61807
61999
|
const currentUsername = username;
|
|
62000
|
+
const currentToken = sessionToken ?? (currentUsername ? readStoredToken(currentUsername) : null);
|
|
62001
|
+
const ownsSdkSession = tabRoleRef.current === "leader" || isAuthenticatedRef.current;
|
|
61808
62002
|
cancelTakeover();
|
|
61809
|
-
|
|
61810
|
-
|
|
61811
|
-
|
|
61812
|
-
(_a2 = engineRef.current) == null ? void 0 : _a2.command({ name: "logoff" });
|
|
61813
|
-
}
|
|
61814
|
-
} else {
|
|
61815
|
-
if (broadcast) (_b = busRef.current) == null ? void 0 : _b.post({ type: "logout" });
|
|
61816
|
-
if (cleanupRef.current) {
|
|
61817
|
-
console.log("[Callix Dialer] 📴 Logout: Chamando goOffline()...");
|
|
61818
|
-
cleanupRef.current.goOffline();
|
|
61819
|
-
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
61820
|
-
console.log("[Callix Dialer] 🛑 Logout: Chamando stop()...");
|
|
61821
|
-
cleanupRef.current.stop();
|
|
61822
|
-
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
61823
|
-
}
|
|
61824
|
-
if (currentUsername) releaseLeader(currentUsername, tabIdRef.current);
|
|
61825
|
-
}
|
|
61826
|
-
setIsAuthenticated(false);
|
|
61827
|
-
setSessionToken(null);
|
|
61828
|
-
setCallixDomain(null);
|
|
62003
|
+
setIsLoading(true);
|
|
62004
|
+
isLoadingRef.current = true;
|
|
62005
|
+
setLoginStatus("Encerrando sessão...");
|
|
61829
62006
|
setError(null);
|
|
61830
|
-
|
|
61831
|
-
|
|
61832
|
-
if (currentUsername) saveTabRole(currentUsername, "member");
|
|
61833
|
-
return;
|
|
61834
|
-
}
|
|
61835
|
-
setTabRole(null);
|
|
61836
|
-
clearTabRole();
|
|
61837
|
-
setUsername(presetUsername ?? null);
|
|
61838
|
-
if (typeof window !== "undefined" && currentUsername) {
|
|
62007
|
+
const run = async () => {
|
|
62008
|
+
var _a2, _b;
|
|
61839
62009
|
try {
|
|
61840
|
-
|
|
61841
|
-
|
|
61842
|
-
|
|
61843
|
-
|
|
61844
|
-
|
|
61845
|
-
|
|
62010
|
+
if (options.engineUrl) {
|
|
62011
|
+
const client2 = engineRef.current;
|
|
62012
|
+
const state = client2 == null ? void 0 : client2.getState();
|
|
62013
|
+
if (!client2) throw new Error("Não há conexão com o motor para confirmar a saída.");
|
|
62014
|
+
if (!(state == null ? void 0 : state.rejected) && !(state == null ? void 0 : state.sessionLost)) {
|
|
62015
|
+
logoffPendingRef.current = true;
|
|
62016
|
+
const finishStoppedSession = async () => {
|
|
62017
|
+
if (!currentToken) throw new Error("O motor parou sem confirmar a saída e esta aba não tem o token da sessão.");
|
|
62018
|
+
const stored = currentUsername ? readStoredToken(currentUsername) : null;
|
|
62019
|
+
if (stored && stored !== currentToken) throw new EngineAccessError("session-changed", "Outra aba substituiu a sessão durante o encerramento.");
|
|
62020
|
+
await endUserSdkSession(options.apiUrl || "/api/user-sdk-session", currentToken);
|
|
62021
|
+
};
|
|
62022
|
+
const isStopped = () => {
|
|
62023
|
+
const view = client2.getState().view;
|
|
62024
|
+
return (view == null ? void 0 : view.engine) === "stopped" || (view == null ? void 0 : view.engine) === "crashed";
|
|
62025
|
+
};
|
|
62026
|
+
if (isStopped()) {
|
|
62027
|
+
await finishStoppedSession();
|
|
62028
|
+
} else {
|
|
62029
|
+
try {
|
|
62030
|
+
await client2.logoff();
|
|
62031
|
+
} catch (err) {
|
|
62032
|
+
if (!isStopped()) throw err;
|
|
62033
|
+
await finishStoppedSession();
|
|
62034
|
+
}
|
|
62035
|
+
}
|
|
62036
|
+
}
|
|
62037
|
+
} else {
|
|
62038
|
+
if (broadcast) (_a2 = busRef.current) == null ? void 0 : _a2.post({ type: "logout" });
|
|
62039
|
+
if (cleanupRef.current) {
|
|
62040
|
+
cleanupRef.current.goOffline();
|
|
62041
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
62042
|
+
(_b = cleanupRef.current) == null ? void 0 : _b.stop();
|
|
62043
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
62044
|
+
}
|
|
62045
|
+
if (ownsSdkSession && !keepDecision) {
|
|
62046
|
+
if (!currentToken) throw new Error("Não há token para encerrar a sessão no Callix.");
|
|
62047
|
+
const stored = currentUsername ? readStoredToken(currentUsername) : null;
|
|
62048
|
+
if (stored && stored !== currentToken) throw new EngineAccessError("session-changed", "Outra aba substituiu a sessão durante o encerramento.");
|
|
62049
|
+
await endUserSdkSession(options.apiUrl || "/api/user-sdk-session", currentToken);
|
|
62050
|
+
}
|
|
62051
|
+
if (currentUsername) releaseLeader(currentUsername, tabIdRef.current);
|
|
62052
|
+
}
|
|
62053
|
+
logoutRetryRef.current = false;
|
|
62054
|
+
logoffPendingRef.current = false;
|
|
62055
|
+
setIsAuthenticated(false);
|
|
62056
|
+
setSessionToken(null);
|
|
62057
|
+
currentSessionRef.current.token = null;
|
|
62058
|
+
setCallixDomain(null);
|
|
62059
|
+
if (keepDecision) {
|
|
62060
|
+
setTabRole("member");
|
|
62061
|
+
if (currentUsername) saveTabRole(currentUsername, "member");
|
|
62062
|
+
return;
|
|
62063
|
+
}
|
|
62064
|
+
setTabRole(null);
|
|
62065
|
+
clearTabRole();
|
|
62066
|
+
setUsername(presetUsername ?? null);
|
|
62067
|
+
if (typeof window !== "undefined" && currentUsername && (options.engineUrl || ownsSdkSession)) {
|
|
62068
|
+
try {
|
|
62069
|
+
const STORAGE_KEYS = getStorageKeys(currentUsername);
|
|
62070
|
+
if (localStorage.getItem(STORAGE_KEYS.SESSION_TOKEN) === currentToken) {
|
|
62071
|
+
if (localStorage.getItem(LAST_USERNAME_KEY) === currentUsername) localStorage.removeItem(LAST_USERNAME_KEY);
|
|
62072
|
+
localStorage.removeItem(STORAGE_KEYS.SESSION_TOKEN);
|
|
62073
|
+
localStorage.removeItem(STORAGE_KEYS.DOMAIN);
|
|
62074
|
+
localStorage.removeItem(STORAGE_KEYS.TIMESTAMP);
|
|
62075
|
+
}
|
|
62076
|
+
} catch (err) {
|
|
62077
|
+
console.warn("[Callix Dialer] Não foi possível limpar os dados locais da sessão:", err);
|
|
62078
|
+
}
|
|
62079
|
+
}
|
|
61846
62080
|
} catch (err) {
|
|
61847
|
-
console.
|
|
62081
|
+
console.error("[Callix Dialer] Não foi possível confirmar a saída:", err);
|
|
62082
|
+
if (err instanceof EngineAccessError && err.code === "session-changed") {
|
|
62083
|
+
logoutRetryRef.current = false;
|
|
62084
|
+
logoffPendingRef.current = false;
|
|
62085
|
+
setSessionToken(null);
|
|
62086
|
+
setIsAuthenticated(false);
|
|
62087
|
+
setError("A sessão foi substituída por outro login durante a saída. Entre novamente para usar a sessão atual.");
|
|
62088
|
+
return;
|
|
62089
|
+
}
|
|
62090
|
+
logoutRetryRef.current = true;
|
|
62091
|
+
setIsAuthenticated(false);
|
|
62092
|
+
setError(`Não foi possível confirmar a saída: ${err instanceof Error ? err.message : "falha ao encerrar a sessão"}. Ao entrar novamente, o discador tentará concluir o encerramento primeiro.`);
|
|
62093
|
+
} finally {
|
|
62094
|
+
setIsLoading(false);
|
|
62095
|
+
isLoadingRef.current = false;
|
|
62096
|
+
setLoginStatus(null);
|
|
61848
62097
|
}
|
|
61849
|
-
}
|
|
61850
|
-
|
|
62098
|
+
};
|
|
62099
|
+
const completion = run().finally(() => {
|
|
62100
|
+
logoutInFlightRef.current = null;
|
|
62101
|
+
});
|
|
62102
|
+
logoutInFlightRef.current = completion;
|
|
62103
|
+
return completion;
|
|
62104
|
+
}, [username, sessionToken, presetUsername, options.apiUrl, options.engineUrl, cancelTakeover]);
|
|
61851
62105
|
useEffect(() => {
|
|
61852
62106
|
handleLogoutRef.current = handleLogout;
|
|
61853
62107
|
}, [handleLogout]);
|
|
@@ -61875,6 +62129,7 @@ function DialerWrapper({ options, containerEl }) {
|
|
|
61875
62129
|
const handleSdkSessionDropped = useCallback(
|
|
61876
62130
|
(originator, notice) => {
|
|
61877
62131
|
var _a2;
|
|
62132
|
+
if (logoutInFlightRef.current) return;
|
|
61878
62133
|
const user = username;
|
|
61879
62134
|
if (user) releaseLeader(user, tabIdRef.current);
|
|
61880
62135
|
(_a2 = busRef.current) == null ? void 0 : _a2.post({ type: "dropped", originator });
|
|
@@ -61934,7 +62189,7 @@ function DialerWrapper({ options, containerEl }) {
|
|
|
61934
62189
|
onLogin: handleLogin,
|
|
61935
62190
|
onLogout: handleLogout,
|
|
61936
62191
|
isLoadingSession: isLoading || isRestoringSession || deciding,
|
|
61937
|
-
sessionError: error2,
|
|
62192
|
+
sessionError: error2 || engineError,
|
|
61938
62193
|
sessionStatus: loginStatus,
|
|
61939
62194
|
loginConfirmation,
|
|
61940
62195
|
onCancelLoginConfirmation: handleCancelLoginConfirmation,
|
|
@@ -61957,7 +62212,7 @@ function DialerWrapper({ options, containerEl }) {
|
|
|
61957
62212
|
onLogin: handleLogin,
|
|
61958
62213
|
onLogout: handleLogout,
|
|
61959
62214
|
isLoadingSession: isLoading,
|
|
61960
|
-
sessionError: error2,
|
|
62215
|
+
sessionError: error2 || engineError,
|
|
61961
62216
|
sessionStatus: loginStatus,
|
|
61962
62217
|
variant: uiVariant,
|
|
61963
62218
|
portalTarget,
|