callix-dialer-widget 2.2.0 → 2.3.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 +58 -3
- package/dist-widget/callix-dialer.css +1 -1
- package/dist-widget/callix-dialer.es.js +1198 -662
- package/dist-widget/callix-dialer.es.js.map +1 -1
- package/dist-widget/callix-dialer.umd.js +4 -4
- 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, {
|
|
9
|
+
import React, { useState, useMemo, useRef, useEffect, useCallback, forwardRef, useLayoutEffect, createContext, useImperativeHandle, StrictMode, useContext } 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) {
|
|
@@ -101,9 +101,9 @@ function requireAxios() {
|
|
|
101
101
|
const { toString } = Object.prototype;
|
|
102
102
|
const { getPrototypeOf } = Object;
|
|
103
103
|
const { iterator, toStringTag } = Symbol;
|
|
104
|
-
const kindOf = /* @__PURE__ */ ((
|
|
104
|
+
const kindOf = /* @__PURE__ */ ((cache2) => (thing) => {
|
|
105
105
|
const str = toString.call(thing);
|
|
106
|
-
return
|
|
106
|
+
return cache2[str] || (cache2[str] = str.slice(8, -1).toLowerCase());
|
|
107
107
|
})(/* @__PURE__ */ Object.create(null));
|
|
108
108
|
const kindOfTest = (type) => {
|
|
109
109
|
type = type.toLowerCase();
|
|
@@ -307,10 +307,10 @@ function requireAxios() {
|
|
|
307
307
|
}
|
|
308
308
|
};
|
|
309
309
|
const matchAll = (regExp, str) => {
|
|
310
|
-
let
|
|
310
|
+
let matches2;
|
|
311
311
|
const arr = [];
|
|
312
|
-
while ((
|
|
313
|
-
arr.push(
|
|
312
|
+
while ((matches2 = regExp.exec(str)) !== null) {
|
|
313
|
+
arr.push(matches2);
|
|
314
314
|
}
|
|
315
315
|
return arr;
|
|
316
316
|
};
|
|
@@ -5774,11 +5774,11 @@ var StateNode = (
|
|
|
5774
5774
|
if (!afterConfig) {
|
|
5775
5775
|
return [];
|
|
5776
5776
|
}
|
|
5777
|
-
var mutateEntryExit = function(
|
|
5778
|
-
var delayRef = isFunction(
|
|
5777
|
+
var mutateEntryExit = function(delay2, i2) {
|
|
5778
|
+
var delayRef = isFunction(delay2) ? "".concat(_this.id, ":delay[").concat(i2, "]") : delay2;
|
|
5779
5779
|
var eventType = after(delayRef, _this.id);
|
|
5780
5780
|
_this.onEntry.push(send$1(eventType, {
|
|
5781
|
-
delay
|
|
5781
|
+
delay: delay2
|
|
5782
5782
|
}));
|
|
5783
5783
|
_this.onExit.push(cancel$1(eventType));
|
|
5784
5784
|
return eventType;
|
|
@@ -5788,12 +5788,12 @@ var StateNode = (
|
|
|
5788
5788
|
return __assign(__assign({}, transition), {
|
|
5789
5789
|
event: eventType
|
|
5790
5790
|
});
|
|
5791
|
-
}) : flatten(Object.keys(afterConfig).map(function(
|
|
5792
|
-
var configTransition = afterConfig[
|
|
5791
|
+
}) : flatten(Object.keys(afterConfig).map(function(delay2, i2) {
|
|
5792
|
+
var configTransition = afterConfig[delay2];
|
|
5793
5793
|
var resolvedTransition = isString(configTransition) ? {
|
|
5794
5794
|
target: configTransition
|
|
5795
5795
|
} : configTransition;
|
|
5796
|
-
var resolvedDelay = !isNaN(+
|
|
5796
|
+
var resolvedDelay = !isNaN(+delay2) ? +delay2 : delay2;
|
|
5797
5797
|
var eventType = mutateEntryExit(resolvedDelay, i2);
|
|
5798
5798
|
return toArray(resolvedTransition).map(function(transition) {
|
|
5799
5799
|
return __assign(__assign({}, transition), {
|
|
@@ -5803,9 +5803,9 @@ var StateNode = (
|
|
|
5803
5803
|
});
|
|
5804
5804
|
}));
|
|
5805
5805
|
return delayedTransitions.map(function(delayedTransition) {
|
|
5806
|
-
var
|
|
5806
|
+
var delay2 = delayedTransition.delay;
|
|
5807
5807
|
return __assign(__assign({}, _this.formatTransition(delayedTransition)), {
|
|
5808
|
-
delay
|
|
5808
|
+
delay: delay2
|
|
5809
5809
|
});
|
|
5810
5810
|
});
|
|
5811
5811
|
};
|
|
@@ -7785,13 +7785,13 @@ function requireExtractExtension() {
|
|
|
7785
7785
|
return {};
|
|
7786
7786
|
}
|
|
7787
7787
|
var numberWithoutExtension = number.slice(0, start2);
|
|
7788
|
-
var
|
|
7788
|
+
var matches2 = number.match(EXTN_PATTERN2);
|
|
7789
7789
|
var i2 = 1;
|
|
7790
|
-
while (i2 <
|
|
7791
|
-
if (
|
|
7790
|
+
while (i2 < matches2.length) {
|
|
7791
|
+
if (matches2[i2]) {
|
|
7792
7792
|
return {
|
|
7793
7793
|
number: numberWithoutExtension,
|
|
7794
|
-
ext:
|
|
7794
|
+
ext: matches2[i2]
|
|
7795
7795
|
};
|
|
7796
7796
|
}
|
|
7797
7797
|
i2++;
|
|
@@ -10797,10 +10797,10 @@ function requirePhoneNumberMatcher() {
|
|
|
10797
10797
|
return _createClass2(PhoneNumberMatcher2, [{
|
|
10798
10798
|
key: "find",
|
|
10799
10799
|
value: function find() {
|
|
10800
|
-
var
|
|
10801
|
-
while (this.maxTries > 0 && (
|
|
10802
|
-
var candidate =
|
|
10803
|
-
var offset =
|
|
10800
|
+
var matches2;
|
|
10801
|
+
while (this.maxTries > 0 && (matches2 = this.PATTERN.exec(this.text)) !== null) {
|
|
10802
|
+
var candidate = matches2[0];
|
|
10803
|
+
var offset = matches2.index;
|
|
10804
10804
|
candidate = (0, _parsePreCandidate["default"])(candidate);
|
|
10805
10805
|
if ((0, _isValidPreCandidate["default"])(candidate, offset, this.text)) {
|
|
10806
10806
|
var match2 = (
|
|
@@ -14024,12 +14024,12 @@ function requireMemoize() {
|
|
|
14024
14024
|
throw new TypeError(FUNC_ERROR_TEXT);
|
|
14025
14025
|
}
|
|
14026
14026
|
var memoized = function() {
|
|
14027
|
-
var args = arguments, key = resolver ? resolver.apply(this, args) : args[0],
|
|
14028
|
-
if (
|
|
14029
|
-
return
|
|
14027
|
+
var args = arguments, key = resolver ? resolver.apply(this, args) : args[0], cache2 = memoized.cache;
|
|
14028
|
+
if (cache2.has(key)) {
|
|
14029
|
+
return cache2.get(key);
|
|
14030
14030
|
}
|
|
14031
14031
|
var result2 = func.apply(this, args);
|
|
14032
|
-
memoized.cache =
|
|
14032
|
+
memoized.cache = cache2.set(key, result2) || cache2;
|
|
14033
14033
|
return result2;
|
|
14034
14034
|
};
|
|
14035
14035
|
memoized.cache = new (memoize.Cache || MapCache)();
|
|
@@ -14503,14 +14503,14 @@ function requirePhoneNumberSearch() {
|
|
|
14503
14503
|
return _createClass2(PhoneNumberSearch2, [{
|
|
14504
14504
|
key: "find",
|
|
14505
14505
|
value: function find() {
|
|
14506
|
-
var
|
|
14507
|
-
if (!
|
|
14506
|
+
var matches2 = this.regexp.exec(this.text);
|
|
14507
|
+
if (!matches2) {
|
|
14508
14508
|
return;
|
|
14509
14509
|
}
|
|
14510
|
-
var number =
|
|
14511
|
-
var startsAt =
|
|
14510
|
+
var number = matches2[0];
|
|
14511
|
+
var startsAt = matches2.index;
|
|
14512
14512
|
number = number.replace(WHITESPACE_IN_THE_BEGINNING_PATTERN, "");
|
|
14513
|
-
startsAt +=
|
|
14513
|
+
startsAt += matches2[0].length - number.length;
|
|
14514
14514
|
number = number.replace(PUNCTUATION_IN_THE_END_PATTERN, "");
|
|
14515
14515
|
number = (0, _parsePreCandidate["default"])(number);
|
|
14516
14516
|
var result2 = this.parseCandidate(number, startsAt);
|
|
@@ -42753,73 +42753,73 @@ function requireChunk52ALM2Y4() {
|
|
|
42753
42753
|
function isInjector(value) {
|
|
42754
42754
|
return __isInternalType(value, Injector);
|
|
42755
42755
|
}
|
|
42756
|
-
var getWeakCacheItem = (
|
|
42756
|
+
var getWeakCacheItem = (cache2, deps) => {
|
|
42757
42757
|
while (true) {
|
|
42758
42758
|
const [dep, ...rest] = deps;
|
|
42759
|
-
const entry =
|
|
42759
|
+
const entry = cache2.get(dep);
|
|
42760
42760
|
if (!entry) {
|
|
42761
42761
|
return;
|
|
42762
42762
|
}
|
|
42763
42763
|
if (!rest.length) {
|
|
42764
42764
|
return entry[1];
|
|
42765
42765
|
}
|
|
42766
|
-
|
|
42766
|
+
cache2 = entry[0];
|
|
42767
42767
|
deps = rest;
|
|
42768
42768
|
}
|
|
42769
42769
|
};
|
|
42770
|
-
var setWeakCacheItem = (
|
|
42770
|
+
var setWeakCacheItem = (cache2, deps, item) => {
|
|
42771
42771
|
while (true) {
|
|
42772
42772
|
const [dep, ...rest] = deps;
|
|
42773
|
-
let entry =
|
|
42773
|
+
let entry = cache2.get(dep);
|
|
42774
42774
|
if (!entry) {
|
|
42775
42775
|
entry = [/* @__PURE__ */ new WeakMap()];
|
|
42776
|
-
|
|
42776
|
+
cache2.set(dep, entry);
|
|
42777
42777
|
}
|
|
42778
42778
|
if (!rest.length) {
|
|
42779
42779
|
entry[1] = item;
|
|
42780
42780
|
return;
|
|
42781
42781
|
}
|
|
42782
|
-
|
|
42782
|
+
cache2 = entry[0];
|
|
42783
42783
|
deps = rest;
|
|
42784
42784
|
}
|
|
42785
42785
|
};
|
|
42786
42786
|
var createDeepCache = () => {
|
|
42787
|
-
let
|
|
42787
|
+
let cache2 = /* @__PURE__ */ new WeakMap();
|
|
42788
42788
|
const deepCache = (createFn, foundFn, deps) => {
|
|
42789
42789
|
if (!deps.length)
|
|
42790
42790
|
throw new Error("Dependencies need to exist.");
|
|
42791
|
-
const cachedValue = getWeakCacheItem(
|
|
42791
|
+
const cachedValue = getWeakCacheItem(cache2, deps);
|
|
42792
42792
|
if (cachedValue) {
|
|
42793
42793
|
foundFn(cachedValue);
|
|
42794
42794
|
return cachedValue;
|
|
42795
42795
|
}
|
|
42796
42796
|
const newObject = createFn();
|
|
42797
|
-
setWeakCacheItem(
|
|
42797
|
+
setWeakCacheItem(cache2, deps, newObject);
|
|
42798
42798
|
return newObject;
|
|
42799
42799
|
};
|
|
42800
42800
|
const upsert = (createFn, deps) => {
|
|
42801
42801
|
if (!deps.length)
|
|
42802
42802
|
throw new Error("Dependencies need to exist.");
|
|
42803
|
-
const cachedValue = getWeakCacheItem(
|
|
42803
|
+
const cachedValue = getWeakCacheItem(cache2, deps);
|
|
42804
42804
|
const newObject = createFn(cachedValue);
|
|
42805
|
-
setWeakCacheItem(
|
|
42805
|
+
setWeakCacheItem(cache2, deps, newObject);
|
|
42806
42806
|
};
|
|
42807
42807
|
const remove = (...deps) => {
|
|
42808
|
-
removeWeakCacheItem(
|
|
42808
|
+
removeWeakCacheItem(cache2, deps);
|
|
42809
42809
|
};
|
|
42810
|
-
const get = (deps) => getWeakCacheItem(
|
|
42810
|
+
const get = (deps) => getWeakCacheItem(cache2, deps);
|
|
42811
42811
|
return {
|
|
42812
42812
|
get,
|
|
42813
|
-
cache,
|
|
42813
|
+
cache: cache2,
|
|
42814
42814
|
deepCache,
|
|
42815
42815
|
upsert,
|
|
42816
42816
|
remove
|
|
42817
42817
|
};
|
|
42818
42818
|
};
|
|
42819
|
-
var removeWeakCacheItem = (
|
|
42819
|
+
var removeWeakCacheItem = (cache2, deps) => {
|
|
42820
42820
|
while (true) {
|
|
42821
42821
|
const [dep, ...rest] = deps;
|
|
42822
|
-
let entry =
|
|
42822
|
+
let entry = cache2.get(dep);
|
|
42823
42823
|
if (!entry) {
|
|
42824
42824
|
return;
|
|
42825
42825
|
}
|
|
@@ -42828,7 +42828,7 @@ function requireChunk52ALM2Y4() {
|
|
|
42828
42828
|
entry[1] = void 0;
|
|
42829
42829
|
return;
|
|
42830
42830
|
} else {
|
|
42831
|
-
|
|
42831
|
+
cache2 = entry[0];
|
|
42832
42832
|
deps = rest;
|
|
42833
42833
|
}
|
|
42834
42834
|
}
|
|
@@ -44185,11 +44185,11 @@ var directive = (factory, data) => {
|
|
|
44185
44185
|
const key = stringify(data);
|
|
44186
44186
|
let directive2;
|
|
44187
44187
|
if (key) {
|
|
44188
|
-
var
|
|
44189
|
-
if (!
|
|
44190
|
-
cacheByFactory.set(factory,
|
|
44188
|
+
var cache2 = cacheByFactory.get(factory);
|
|
44189
|
+
if (!cache2) {
|
|
44190
|
+
cacheByFactory.set(factory, cache2 = /* @__PURE__ */ new Map());
|
|
44191
44191
|
}
|
|
44192
|
-
directive2 =
|
|
44192
|
+
directive2 = cache2.get(key);
|
|
44193
44193
|
}
|
|
44194
44194
|
if (!directive2) {
|
|
44195
44195
|
directive2 = Object.defineProperty((params, context) => {
|
|
@@ -44198,9 +44198,9 @@ var directive = (factory, data) => {
|
|
|
44198
44198
|
}, "toJSON", {
|
|
44199
44199
|
value: () => key || data
|
|
44200
44200
|
});
|
|
44201
|
-
if (
|
|
44202
|
-
|
|
44203
|
-
ensureMaxSize(
|
|
44201
|
+
if (cache2) {
|
|
44202
|
+
cache2.set(key, directive2);
|
|
44203
|
+
ensureMaxSize(cache2, 1e4);
|
|
44204
44204
|
}
|
|
44205
44205
|
}
|
|
44206
44206
|
return directive2;
|
|
@@ -45472,7 +45472,7 @@ var resolveContext = {
|
|
|
45472
45472
|
};
|
|
45473
45473
|
var handleArbitraryValues = (section, key) => (key = key[0] == "[" && key.slice(-1) == "]" && key.slice(1, -1)) && includes(section, "olor") == /^(#|(hsl|rgb)a?\(|[a-z]+$)/.test(key) && (includes(key, "calc(") ? key.replace(/(-?\d*\.?\d(?!\b-.+[,)](?![^+\-/*])\D)(?:%|[a-z]+)?|\))([+\-/*])/g, "$1 $2 ") : key);
|
|
45474
45474
|
var makeThemeResolver = (config) => {
|
|
45475
|
-
const
|
|
45475
|
+
const cache2 = /* @__PURE__ */ new Map();
|
|
45476
45476
|
const theme2 = { ...defaultTheme, ...config };
|
|
45477
45477
|
const deref = (theme3, section) => {
|
|
45478
45478
|
const base = theme3 && theme3[section];
|
|
@@ -45486,9 +45486,9 @@ var makeThemeResolver = (config) => {
|
|
|
45486
45486
|
defaultValue = key;
|
|
45487
45487
|
key = join$1(tail(keypath), ".");
|
|
45488
45488
|
}
|
|
45489
|
-
let base =
|
|
45489
|
+
let base = cache2.get(section);
|
|
45490
45490
|
if (!base) {
|
|
45491
|
-
|
|
45491
|
+
cache2.set(section, base = { ...deref(theme2, section) });
|
|
45492
45492
|
Object.assign(base, deref(theme2.extend, section));
|
|
45493
45493
|
}
|
|
45494
45494
|
if (key != null) {
|
|
@@ -48472,96 +48472,133 @@ function getAuthHeaders() {
|
|
|
48472
48472
|
}
|
|
48473
48473
|
return headers;
|
|
48474
48474
|
}
|
|
48475
|
-
|
|
48476
|
-
|
|
48477
|
-
|
|
48478
|
-
|
|
48479
|
-
|
|
48480
|
-
|
|
48481
|
-
}
|
|
48482
|
-
|
|
48483
|
-
|
|
48484
|
-
|
|
48485
|
-
|
|
48486
|
-
|
|
48487
|
-
|
|
48488
|
-
}
|
|
48489
|
-
async function getCodeToNameMapping(campaignModelId) {
|
|
48490
|
-
const url = `${API_BASE_URL}/api/campaign-fields/${campaignModelId}`;
|
|
48491
|
-
const response = await fetch(url, {
|
|
48492
|
-
method: "GET",
|
|
48493
|
-
headers: getAuthHeaders(),
|
|
48494
|
-
credentials: "omit"
|
|
48495
|
-
});
|
|
48496
|
-
if (!response.ok) {
|
|
48497
|
-
const error2 = await response.json().catch(() => ({ error: "Erro desconhecido" }));
|
|
48498
|
-
throw new Error(error2.error || `Falha ao buscar mapeamento: ${response.status}`);
|
|
48499
|
-
}
|
|
48500
|
-
const json = await response.json();
|
|
48501
|
-
return json;
|
|
48502
|
-
}
|
|
48503
|
-
async function getCustomerCodeToNameMapping(formId) {
|
|
48504
|
-
const url = `${API_BASE_URL}/api/campaign-contact/0?source=customer&formId=${encodeURIComponent(String(formId))}`;
|
|
48505
|
-
const response = await fetch(url, {
|
|
48506
|
-
method: "GET",
|
|
48507
|
-
headers: getAuthHeaders(),
|
|
48508
|
-
credentials: "omit"
|
|
48509
|
-
});
|
|
48510
|
-
if (!response.ok) {
|
|
48511
|
-
const error2 = await response.json().catch(() => ({ error: "Erro desconhecido" }));
|
|
48512
|
-
throw new Error(error2.error || `Falha ao buscar campos (cliente): ${response.status}`);
|
|
48475
|
+
const CAMPAIGN_FORM_CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
48476
|
+
const DEFAULT_RETRIES = 2;
|
|
48477
|
+
const RETRY_DELAY_MS = 800;
|
|
48478
|
+
const REQUEST_TIMEOUT_MS$1 = 15e3;
|
|
48479
|
+
const cache = /* @__PURE__ */ new Map();
|
|
48480
|
+
function campaignFormCacheKey(request) {
|
|
48481
|
+
return `${request.source}:${request.id}`;
|
|
48482
|
+
}
|
|
48483
|
+
function campaignFormRequestFromCallInfo(info, phoneId) {
|
|
48484
|
+
var _a2, _b;
|
|
48485
|
+
const contact = info == null ? void 0 : info.campaignContact;
|
|
48486
|
+
if (!(contact == null ? void 0 : contact.id)) {
|
|
48487
|
+
return null;
|
|
48513
48488
|
}
|
|
48514
|
-
const
|
|
48515
|
-
|
|
48516
|
-
|
|
48517
|
-
|
|
48518
|
-
|
|
48519
|
-
|
|
48520
|
-
|
|
48521
|
-
|
|
48489
|
+
const customer = contact.customer;
|
|
48490
|
+
if ((customer == null ? void 0 : customer.id) && (customer == null ? void 0 : customer.formId)) {
|
|
48491
|
+
return { source: "customer", id: customer.id, formId: customer.formId, campaignId: ((_a2 = info == null ? void 0 : info.campaign) == null ? void 0 : _a2.id) ?? null, phoneId: phoneId ?? null };
|
|
48492
|
+
}
|
|
48493
|
+
return { source: "campaign", id: contact.id, campaignId: ((_b = info == null ? void 0 : info.campaign) == null ? void 0 : _b.id) ?? null, phoneId: phoneId ?? null };
|
|
48494
|
+
}
|
|
48495
|
+
function buildCampaignFormUrl(apiBaseUrl, request) {
|
|
48496
|
+
const params = new URLSearchParams();
|
|
48497
|
+
if (request.source === "customer") params.set("source", "customer");
|
|
48498
|
+
if (request.campaignId) params.set("campaignId", String(request.campaignId));
|
|
48499
|
+
if (request.formId) params.set("formId", String(request.formId));
|
|
48500
|
+
if (request.phoneId) params.set("phoneId", String(request.phoneId));
|
|
48501
|
+
if (request.signature && request.expiresAt) {
|
|
48502
|
+
params.set("sig", request.signature);
|
|
48503
|
+
params.set("exp", String(request.expiresAt));
|
|
48504
|
+
}
|
|
48505
|
+
const query = params.toString();
|
|
48506
|
+
return `${apiBaseUrl}/api/campaign-form/${encodeURIComponent(String(request.id))}${query ? `?${query}` : ""}`;
|
|
48507
|
+
}
|
|
48508
|
+
function isFormResponse(value) {
|
|
48509
|
+
if (!value || typeof value !== "object") return false;
|
|
48510
|
+
const form = value;
|
|
48511
|
+
return typeof form.id === "number" && !!form.values && typeof form.values === "object" && Array.isArray(form.fields);
|
|
48512
|
+
}
|
|
48513
|
+
async function requestOnce(url, headers) {
|
|
48514
|
+
const controller = new AbortController();
|
|
48515
|
+
const timer = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS$1);
|
|
48516
|
+
try {
|
|
48517
|
+
const response = await fetch(url, { method: "GET", headers, credentials: "omit", signal: controller.signal });
|
|
48518
|
+
if (!response.ok) {
|
|
48519
|
+
const body = await response.json().catch(() => ({}));
|
|
48520
|
+
const message = body.message || body.error || `Erro ${response.status}`;
|
|
48521
|
+
const error2 = new Error(response.status === 401 ? "Sessão expirada. Entre novamente no discador." : message);
|
|
48522
|
+
error2.status = response.status;
|
|
48523
|
+
throw error2;
|
|
48524
|
+
}
|
|
48525
|
+
const data = await response.json();
|
|
48526
|
+
if (!isFormResponse(data)) {
|
|
48527
|
+
throw new Error("Resposta inesperada do servidor");
|
|
48528
|
+
}
|
|
48529
|
+
return data;
|
|
48530
|
+
} catch (error2) {
|
|
48531
|
+
if (error2 instanceof Error && error2.name === "AbortError") {
|
|
48532
|
+
throw new Error("Tempo esgotado ao buscar o formulário");
|
|
48533
|
+
}
|
|
48534
|
+
throw error2;
|
|
48535
|
+
} finally {
|
|
48536
|
+
clearTimeout(timer);
|
|
48537
|
+
}
|
|
48538
|
+
}
|
|
48539
|
+
function shouldRetry(error2) {
|
|
48540
|
+
const status = error2 == null ? void 0 : error2.status;
|
|
48541
|
+
if (status === void 0) return true;
|
|
48542
|
+
return status >= 500 || status === 408 || status === 429;
|
|
48543
|
+
}
|
|
48544
|
+
function fetchCampaignForm(request, options = {}) {
|
|
48545
|
+
const key = campaignFormCacheKey(request);
|
|
48546
|
+
const now = Date.now();
|
|
48547
|
+
const cached = cache.get(key);
|
|
48548
|
+
if (cached && cached.until > now && !options.force) {
|
|
48549
|
+
return cached.promise;
|
|
48550
|
+
}
|
|
48551
|
+
const url = buildCampaignFormUrl(options.apiBaseUrl ?? API_BASE_URL, request);
|
|
48552
|
+
const headers = options.headers ?? getAuthHeaders();
|
|
48553
|
+
const retries = Math.max(0, options.retries ?? DEFAULT_RETRIES);
|
|
48554
|
+
const promise = (async () => {
|
|
48555
|
+
let lastError;
|
|
48556
|
+
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
48557
|
+
try {
|
|
48558
|
+
return await requestOnce(url, headers);
|
|
48559
|
+
} catch (error2) {
|
|
48560
|
+
lastError = error2;
|
|
48561
|
+
if (attempt === retries || !shouldRetry(error2)) break;
|
|
48562
|
+
await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY_MS * 2 ** attempt));
|
|
48522
48563
|
}
|
|
48523
48564
|
}
|
|
48524
|
-
|
|
48525
|
-
|
|
48526
|
-
}
|
|
48527
|
-
|
|
48528
|
-
|
|
48529
|
-
|
|
48530
|
-
|
|
48531
|
-
|
|
48532
|
-
|
|
48533
|
-
});
|
|
48534
|
-
if (!response.ok) {
|
|
48535
|
-
const error2 = await response.json().catch(() => ({ error: "Erro desconhecido" }));
|
|
48536
|
-
throw new Error(error2.error || `Falha ao buscar valores: ${response.status}`);
|
|
48537
|
-
}
|
|
48538
|
-
const json = await response.json();
|
|
48539
|
-
return json;
|
|
48540
|
-
}
|
|
48541
|
-
async function getCustomerContactValues$1(customerId) {
|
|
48542
|
-
const url = `${API_BASE_URL}/api/campaign-fields/0?source=customer&customerId=${encodeURIComponent(String(customerId))}`;
|
|
48543
|
-
const response = await fetch(url, {
|
|
48544
|
-
method: "GET",
|
|
48545
|
-
headers: getAuthHeaders(),
|
|
48546
|
-
credentials: "omit"
|
|
48565
|
+
throw lastError instanceof Error ? lastError : new Error("Erro ao buscar o formulário");
|
|
48566
|
+
})();
|
|
48567
|
+
cache.set(key, { promise, until: now + CAMPAIGN_FORM_CACHE_TTL_MS });
|
|
48568
|
+
promise.then((form) => {
|
|
48569
|
+
var _a2;
|
|
48570
|
+
if (form.partial && ((_a2 = cache.get(key)) == null ? void 0 : _a2.promise) === promise) cache.delete(key);
|
|
48571
|
+
}).catch(() => {
|
|
48572
|
+
var _a2;
|
|
48573
|
+
if (((_a2 = cache.get(key)) == null ? void 0 : _a2.promise) === promise) cache.delete(key);
|
|
48547
48574
|
});
|
|
48548
|
-
|
|
48549
|
-
const error2 = await response.json().catch(() => ({ error: "Erro desconhecido" }));
|
|
48550
|
-
throw new Error(error2.error || `Falha ao buscar valores (cliente): ${response.status}`);
|
|
48551
|
-
}
|
|
48552
|
-
const json = await response.json();
|
|
48553
|
-
return json;
|
|
48575
|
+
return promise;
|
|
48554
48576
|
}
|
|
48555
|
-
function
|
|
48556
|
-
|
|
48557
|
-
|
|
48558
|
-
|
|
48559
|
-
|
|
48577
|
+
function normalizeFormKey(value) {
|
|
48578
|
+
return String(value ?? "").normalize("NFC").trim().toLowerCase().replace(/\s+/g, " ");
|
|
48579
|
+
}
|
|
48580
|
+
function findFormValue(form, candidates) {
|
|
48581
|
+
if (!(form == null ? void 0 : form.values)) {
|
|
48582
|
+
return void 0;
|
|
48583
|
+
}
|
|
48584
|
+
const byNormalizedKey = /* @__PURE__ */ new Map();
|
|
48585
|
+
for (const [key, value] of Object.entries(form.values)) {
|
|
48586
|
+
const normalized = stripAccents(normalizeFormKey(key));
|
|
48587
|
+
if (!byNormalizedKey.has(normalized) && value !== void 0 && value !== null && String(value).trim() !== "") {
|
|
48588
|
+
byNormalizedKey.set(normalized, String(value));
|
|
48589
|
+
}
|
|
48590
|
+
}
|
|
48591
|
+
for (const candidate of candidates) {
|
|
48592
|
+
const value = byNormalizedKey.get(stripAccents(normalizeFormKey(candidate)));
|
|
48593
|
+
if (value !== void 0) {
|
|
48560
48594
|
return value;
|
|
48561
48595
|
}
|
|
48562
48596
|
}
|
|
48563
48597
|
return void 0;
|
|
48564
48598
|
}
|
|
48599
|
+
function stripAccents(value) {
|
|
48600
|
+
return value.normalize("NFD").replace(/[̀-ͯ]/g, "");
|
|
48601
|
+
}
|
|
48565
48602
|
function formatPhoneValue(raw) {
|
|
48566
48603
|
if (!raw) return "-";
|
|
48567
48604
|
const digits = raw.replace(/\D/g, "");
|
|
@@ -48575,18 +48612,12 @@ function formatPhoneValue(raw) {
|
|
|
48575
48612
|
return raw.trim();
|
|
48576
48613
|
}
|
|
48577
48614
|
function CallInfoDisplay() {
|
|
48615
|
+
var _a2;
|
|
48578
48616
|
const callInfo = clientSdkReactExports.useCallOperatorCurrentCallInfo();
|
|
48579
|
-
|
|
48580
|
-
|
|
48581
|
-
callInfo,
|
|
48582
|
-
type: callInfo == null ? void 0 : callInfo.type,
|
|
48583
|
-
hasCampaignInfo: (callInfo == null ? void 0 : callInfo.type) === "campaign",
|
|
48584
|
-
info: (callInfo == null ? void 0 : callInfo.type) === "campaign" ? callInfo.info : null,
|
|
48585
|
-
campaignContact: (callInfo == null ? void 0 : callInfo.type) === "campaign" ? callInfo.info.campaignContact : null
|
|
48586
|
-
});
|
|
48587
|
-
}, [callInfo]);
|
|
48617
|
+
const currentCall = clientSdkReactExports.useCallOperatorCurrentCall();
|
|
48618
|
+
const campaignContactPhoneId = ((_a2 = currentCall == null ? void 0 : currentCall.data) == null ? void 0 : _a2.campaignContactPhoneId) ?? null;
|
|
48588
48619
|
if ((callInfo == null ? void 0 : callInfo.type) === "campaign") {
|
|
48589
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(CampaignCallInfoDisplay, { campaignCallInfo: callInfo.info });
|
|
48620
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(CampaignCallInfoDisplay, { campaignCallInfo: callInfo.info, campaignContactPhoneId });
|
|
48590
48621
|
}
|
|
48591
48622
|
if (callInfo) {
|
|
48592
48623
|
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mb-4 rounded-lg border border-amber-200 bg-amber-50 px-3 py-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs font-semibold text-amber-700", children: "Chamada manual (sem informações de campanha)" }) });
|
|
@@ -48596,83 +48627,63 @@ function CallInfoDisplay() {
|
|
|
48596
48627
|
function CampaignCallInfoDisplay(props) {
|
|
48597
48628
|
const { campaign, campaignContact } = props.campaignCallInfo;
|
|
48598
48629
|
const [contactData, setContactData] = useState({
|
|
48599
|
-
|
|
48630
|
+
form: null,
|
|
48600
48631
|
isLoading: false,
|
|
48601
48632
|
error: null
|
|
48602
48633
|
});
|
|
48603
|
-
const [
|
|
48634
|
+
const [retry, setRetry] = useState({ key: null, n: 0 });
|
|
48635
|
+
const request = useMemo(
|
|
48636
|
+
() => campaignFormRequestFromCallInfo(props.campaignCallInfo, props.campaignContactPhoneId),
|
|
48637
|
+
[props.campaignCallInfo, props.campaignContactPhoneId]
|
|
48638
|
+
);
|
|
48639
|
+
const requestKey = request ? campaignFormCacheKey(request) : null;
|
|
48640
|
+
const requestRef = useRef(request);
|
|
48641
|
+
requestRef.current = request;
|
|
48642
|
+
const partialRefreshKeyRef = useRef(null);
|
|
48604
48643
|
useEffect(() => {
|
|
48605
|
-
|
|
48606
|
-
|
|
48607
|
-
|
|
48608
|
-
if (fetchedContactId === campaignContact.id) {
|
|
48644
|
+
const current = requestRef.current;
|
|
48645
|
+
if (!current || !requestKey) {
|
|
48646
|
+
setContactData({ form: null, isLoading: false, error: null });
|
|
48609
48647
|
return;
|
|
48610
48648
|
}
|
|
48611
48649
|
let cancelled = false;
|
|
48612
|
-
|
|
48613
|
-
|
|
48614
|
-
|
|
48615
|
-
|
|
48616
|
-
|
|
48617
|
-
|
|
48618
|
-
|
|
48619
|
-
|
|
48620
|
-
getCustomerCodeToNameMapping(customer.formId),
|
|
48621
|
-
getCustomerContactValues$1(customer.id)
|
|
48622
|
-
]);
|
|
48623
|
-
} else {
|
|
48624
|
-
const config = await getCampaignConfig$2(campaignContact.id);
|
|
48625
|
-
if (!config.campaignModelId) {
|
|
48626
|
-
throw new Error("campaignModelId não encontrado");
|
|
48627
|
-
}
|
|
48628
|
-
[codeToNameMap, contactValues] = await Promise.all([
|
|
48629
|
-
getCodeToNameMapping(config.campaignModelId),
|
|
48630
|
-
getContactValues$2(campaignContact.id)
|
|
48631
|
-
]);
|
|
48650
|
+
let refreshTimer = null;
|
|
48651
|
+
setContactData({ form: null, isLoading: true, error: null });
|
|
48652
|
+
fetchCampaignForm(current, { force: retry.key === requestKey && retry.n > 0 }).then((form) => {
|
|
48653
|
+
if (!cancelled) {
|
|
48654
|
+
setContactData({ form, isLoading: false, error: null });
|
|
48655
|
+
if (form.partial && partialRefreshKeyRef.current !== requestKey) {
|
|
48656
|
+
partialRefreshKeyRef.current = requestKey;
|
|
48657
|
+
refreshTimer = setTimeout(() => setRetry((prev) => ({ key: requestKey, n: prev.n + 1 })), 3e3);
|
|
48632
48658
|
}
|
|
48633
|
-
|
|
48634
|
-
|
|
48635
|
-
|
|
48636
|
-
|
|
48637
|
-
|
|
48659
|
+
}
|
|
48660
|
+
}).catch((error2) => {
|
|
48661
|
+
if (!cancelled) {
|
|
48662
|
+
console.error("[CampaignCallInfoDisplay] Erro ao buscar dados:", error2);
|
|
48663
|
+
setContactData({
|
|
48664
|
+
form: null,
|
|
48665
|
+
isLoading: false,
|
|
48666
|
+
error: error2 instanceof Error ? error2.message : "Erro ao buscar dados do contato"
|
|
48638
48667
|
});
|
|
48639
|
-
if (!cancelled) {
|
|
48640
|
-
setContactData({
|
|
48641
|
-
finalData,
|
|
48642
|
-
isLoading: false,
|
|
48643
|
-
error: null
|
|
48644
|
-
});
|
|
48645
|
-
setFetchedContactId(campaignContact.id);
|
|
48646
|
-
}
|
|
48647
|
-
} catch (error2) {
|
|
48648
|
-
if (!cancelled) {
|
|
48649
|
-
console.error("[CampaignCallInfoDisplay] Erro ao buscar dados:", error2);
|
|
48650
|
-
const errorMessage = error2 instanceof Error ? error2.message : "Erro ao buscar dados do contato";
|
|
48651
|
-
setContactData({
|
|
48652
|
-
finalData: {},
|
|
48653
|
-
isLoading: false,
|
|
48654
|
-
error: errorMessage
|
|
48655
|
-
});
|
|
48656
|
-
}
|
|
48657
48668
|
}
|
|
48658
|
-
};
|
|
48659
|
-
void fetchContactData();
|
|
48669
|
+
});
|
|
48660
48670
|
return () => {
|
|
48661
48671
|
cancelled = true;
|
|
48672
|
+
if (refreshTimer) clearTimeout(refreshTimer);
|
|
48662
48673
|
};
|
|
48663
|
-
}, [
|
|
48674
|
+
}, [requestKey, retry]);
|
|
48664
48675
|
const prioritizedFields = useMemo(
|
|
48665
48676
|
() => [
|
|
48666
|
-
{ label: "Decisor", keys: ["DECISOR"], icon: /* @__PURE__ */ jsxRuntimeExports.jsx(FiUser, { className: "text-sm" }) },
|
|
48667
|
-
{ label: "Empresa", keys: ["EMPRESA", "RAZAO SOCIAL"], icon: /* @__PURE__ */ jsxRuntimeExports.jsx(FiBriefcase, { className: "text-sm" }) },
|
|
48668
|
-
{ label: "Dívida ativa", keys: ["DIVIDA ATIVA", "DÍVIDA ATIVA"], icon: /* @__PURE__ */ jsxRuntimeExports.jsx(FiHash, { className: "text-sm" }) },
|
|
48677
|
+
{ label: "Decisor", keys: ["DECISOR", "CONTATO", "NOME"], icon: /* @__PURE__ */ jsxRuntimeExports.jsx(FiUser, { className: "text-sm" }) },
|
|
48678
|
+
{ label: "Empresa", keys: ["EMPRESA", "RAZAO SOCIAL", "RAZÃO SOCIAL", "CLIENTE"], icon: /* @__PURE__ */ jsxRuntimeExports.jsx(FiBriefcase, { className: "text-sm" }) },
|
|
48679
|
+
{ label: "Dívida ativa", keys: ["DIVIDA ATIVA", "DÍVIDA ATIVA", "VALOR TOTAL DEVIDO"], icon: /* @__PURE__ */ jsxRuntimeExports.jsx(FiHash, { className: "text-sm" }) },
|
|
48669
48680
|
{ label: "Telefone", keys: ["TELEFONE", "CELULAR", "WHATSAPP"], icon: /* @__PURE__ */ jsxRuntimeExports.jsx(FiSmartphone, { className: "text-sm" }) }
|
|
48670
48681
|
],
|
|
48671
48682
|
[]
|
|
48672
48683
|
);
|
|
48673
48684
|
const highlightData = useMemo(() => {
|
|
48674
48685
|
return prioritizedFields.map((field) => {
|
|
48675
|
-
const rawValue = (field.label === "Telefone" ?
|
|
48686
|
+
const rawValue = (field.label === "Telefone" ? findFormValue(contactData.form, field.keys) ?? (campaignContact == null ? void 0 : campaignContact.phoneNumber) : findFormValue(contactData.form, field.keys)) || "";
|
|
48676
48687
|
const display2 = field.label === "Telefone" ? formatPhoneValue(rawValue) : (rawValue || "-").toString().trim() || "-";
|
|
48677
48688
|
return {
|
|
48678
48689
|
...field,
|
|
@@ -48680,7 +48691,7 @@ function CampaignCallInfoDisplay(props) {
|
|
|
48680
48691
|
isEmpty: !rawValue
|
|
48681
48692
|
};
|
|
48682
48693
|
});
|
|
48683
|
-
}, [campaignContact == null ? void 0 : campaignContact.phoneNumber, contactData.
|
|
48694
|
+
}, [campaignContact == null ? void 0 : campaignContact.phoneNumber, contactData.form, prioritizedFields]);
|
|
48684
48695
|
const hasData = highlightData.some((item) => !item.isEmpty);
|
|
48685
48696
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mb-4 rounded-2xl border border-slate-200 bg-white/90 p-3 shadow-sm", children: [
|
|
48686
48697
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mb-3 flex items-center justify-between gap-2", children: [
|
|
@@ -48696,7 +48707,7 @@ function CampaignCallInfoDisplay(props) {
|
|
|
48696
48707
|
"Em chamada"
|
|
48697
48708
|
] })
|
|
48698
48709
|
] }),
|
|
48699
|
-
contactData.isLoading && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded-xl border border-slate-200 bg-slate-50 p-4 text-center", children: [
|
|
48710
|
+
contactData.isLoading && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded-xl border border-slate-200 bg-slate-50 p-4 text-center", role: "status", children: [
|
|
48700
48711
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mx-auto mb-2 inline-block h-7 w-7 animate-spin rounded-full border-2 border-emerald-500 border-t-transparent" }),
|
|
48701
48712
|
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs font-medium text-slate-600", children: "Carregando dados do contato..." })
|
|
48702
48713
|
] }),
|
|
@@ -48706,10 +48717,11 @@ function CampaignCallInfoDisplay(props) {
|
|
|
48706
48717
|
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs font-semibold text-rose-700", children: "Erro ao carregar dados" })
|
|
48707
48718
|
] }),
|
|
48708
48719
|
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "ml-6 text-[11px] text-rose-600", children: contactData.error }),
|
|
48709
|
-
|
|
48720
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
48710
48721
|
"button",
|
|
48711
48722
|
{
|
|
48712
|
-
|
|
48723
|
+
type: "button",
|
|
48724
|
+
onClick: () => setRetry((prev) => ({ key: requestKey, n: prev.n + 1 })),
|
|
48713
48725
|
className: "mt-2 ml-6 text-[11px] font-semibold text-rose-700 underline hover:text-rose-800",
|
|
48714
48726
|
children: "Tentar novamente"
|
|
48715
48727
|
}
|
|
@@ -50237,13 +50249,13 @@ function extractExtension(number) {
|
|
|
50237
50249
|
return {};
|
|
50238
50250
|
}
|
|
50239
50251
|
var numberWithoutExtension = number.slice(0, start2);
|
|
50240
|
-
var
|
|
50252
|
+
var matches2 = number.match(EXTN_PATTERN);
|
|
50241
50253
|
var i2 = 1;
|
|
50242
|
-
while (i2 <
|
|
50243
|
-
if (
|
|
50254
|
+
while (i2 < matches2.length) {
|
|
50255
|
+
if (matches2[i2]) {
|
|
50244
50256
|
return {
|
|
50245
50257
|
number: numberWithoutExtension,
|
|
50246
|
-
ext:
|
|
50258
|
+
ext: matches2[i2]
|
|
50247
50259
|
};
|
|
50248
50260
|
}
|
|
50249
50261
|
i2++;
|
|
@@ -51141,6 +51153,266 @@ function buildDialPlan(rawValue, defaultPrefix = DEFAULT_COUNTRY_PREFIX) {
|
|
|
51141
51153
|
const differs = Boolean(e164) && onlyDigits(e164 ?? "") !== typedDigits;
|
|
51142
51154
|
return { raw, display: display2, e164, dialDisplay, isValid: isValid2, differs };
|
|
51143
51155
|
}
|
|
51156
|
+
const QUERIES = {
|
|
51157
|
+
fine: "(pointer: fine)",
|
|
51158
|
+
coarse: "(pointer: coarse)",
|
|
51159
|
+
hover: "(hover: hover)"
|
|
51160
|
+
};
|
|
51161
|
+
function matches(query) {
|
|
51162
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
|
|
51163
|
+
return null;
|
|
51164
|
+
}
|
|
51165
|
+
try {
|
|
51166
|
+
return window.matchMedia(query).matches;
|
|
51167
|
+
} catch {
|
|
51168
|
+
return null;
|
|
51169
|
+
}
|
|
51170
|
+
}
|
|
51171
|
+
function getInputProfile() {
|
|
51172
|
+
const fine = matches(QUERIES.fine);
|
|
51173
|
+
const coarse = matches(QUERIES.coarse);
|
|
51174
|
+
const hover = matches(QUERIES.hover);
|
|
51175
|
+
const pointer = coarse ? "coarse" : fine ? "fine" : "unknown";
|
|
51176
|
+
const touchLike = pointer === "coarse" || pointer !== "fine" && hover === false;
|
|
51177
|
+
return { pointer, hover: hover === true, touchLike };
|
|
51178
|
+
}
|
|
51179
|
+
function resolveDensity(density, profile) {
|
|
51180
|
+
if (density === "compact" || density === "comfortable") {
|
|
51181
|
+
return density;
|
|
51182
|
+
}
|
|
51183
|
+
return profile.touchLike ? "comfortable" : "compact";
|
|
51184
|
+
}
|
|
51185
|
+
function parseDensity(value) {
|
|
51186
|
+
const normalized = (value ?? "").trim().toLowerCase();
|
|
51187
|
+
if (normalized === "compact" || normalized === "compacta" || normalized === "compacto") return "compact";
|
|
51188
|
+
if (normalized === "comfortable" || normalized === "confortavel" || normalized === "confortável" || normalized === "touch") return "comfortable";
|
|
51189
|
+
if (normalized === "auto") return "auto";
|
|
51190
|
+
return void 0;
|
|
51191
|
+
}
|
|
51192
|
+
function useInputProfile() {
|
|
51193
|
+
const [profile, setProfile] = useState(() => getInputProfile());
|
|
51194
|
+
useEffect(() => {
|
|
51195
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
|
|
51196
|
+
return;
|
|
51197
|
+
}
|
|
51198
|
+
const update2 = () => setProfile(getInputProfile());
|
|
51199
|
+
const lists = [];
|
|
51200
|
+
for (const query of Object.values(QUERIES)) {
|
|
51201
|
+
try {
|
|
51202
|
+
const list = window.matchMedia(query);
|
|
51203
|
+
if (typeof list.addEventListener === "function") {
|
|
51204
|
+
list.addEventListener("change", update2);
|
|
51205
|
+
} else if (typeof list.addListener === "function") {
|
|
51206
|
+
list.addListener(update2);
|
|
51207
|
+
}
|
|
51208
|
+
lists.push(list);
|
|
51209
|
+
} catch {
|
|
51210
|
+
}
|
|
51211
|
+
}
|
|
51212
|
+
update2();
|
|
51213
|
+
return () => {
|
|
51214
|
+
for (const list of lists) {
|
|
51215
|
+
if (typeof list.removeEventListener === "function") {
|
|
51216
|
+
list.removeEventListener("change", update2);
|
|
51217
|
+
} else if (typeof list.removeListener === "function") {
|
|
51218
|
+
list.removeListener(update2);
|
|
51219
|
+
}
|
|
51220
|
+
}
|
|
51221
|
+
};
|
|
51222
|
+
}, []);
|
|
51223
|
+
return profile;
|
|
51224
|
+
}
|
|
51225
|
+
const CLICK_TO_CALL_EVENT = "callix:click-to-call";
|
|
51226
|
+
function presenceFromOperatorState(state) {
|
|
51227
|
+
if (!state) {
|
|
51228
|
+
return "unknown";
|
|
51229
|
+
}
|
|
51230
|
+
switch (state) {
|
|
51231
|
+
case "idle":
|
|
51232
|
+
return "available";
|
|
51233
|
+
case "onBreak":
|
|
51234
|
+
return "on_break";
|
|
51235
|
+
case "afterCall":
|
|
51236
|
+
case "manualCallFailed":
|
|
51237
|
+
return "after_call";
|
|
51238
|
+
case "offline":
|
|
51239
|
+
case "stopped":
|
|
51240
|
+
case "startupError":
|
|
51241
|
+
case "startup.error":
|
|
51242
|
+
case "networkDown":
|
|
51243
|
+
return "offline";
|
|
51244
|
+
case "starting":
|
|
51245
|
+
return "unknown";
|
|
51246
|
+
case "callRinging":
|
|
51247
|
+
case "manualCallSetup":
|
|
51248
|
+
case "manualCallRinging":
|
|
51249
|
+
case "callInProgress":
|
|
51250
|
+
return "in_call";
|
|
51251
|
+
default:
|
|
51252
|
+
return /call|ringing|dial/i.test(state) ? "in_call" : "unknown";
|
|
51253
|
+
}
|
|
51254
|
+
}
|
|
51255
|
+
function canDispatchTo(presence) {
|
|
51256
|
+
return presence === "available" || presence === "on_break";
|
|
51257
|
+
}
|
|
51258
|
+
const REQUEST_TIMEOUT_MS = 1e4;
|
|
51259
|
+
const DEFAULT_PRESENCE_TTL_SECONDS = 45;
|
|
51260
|
+
function withTimeout(signal) {
|
|
51261
|
+
const controller = new AbortController();
|
|
51262
|
+
const timer = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
51263
|
+
if (signal) {
|
|
51264
|
+
if (signal.aborted) {
|
|
51265
|
+
controller.abort();
|
|
51266
|
+
} else {
|
|
51267
|
+
signal.addEventListener("abort", () => controller.abort(), { once: true });
|
|
51268
|
+
}
|
|
51269
|
+
}
|
|
51270
|
+
return { signal: controller.signal, clear: () => clearTimeout(timer) };
|
|
51271
|
+
}
|
|
51272
|
+
async function pollClickToCall(options) {
|
|
51273
|
+
const { signal, clear } = withTimeout(options.signal);
|
|
51274
|
+
try {
|
|
51275
|
+
const response = await fetch(`${options.apiBaseUrl}/api/click-to-call/poll`, {
|
|
51276
|
+
method: "POST",
|
|
51277
|
+
headers: options.headers,
|
|
51278
|
+
body: JSON.stringify({ state: options.state ?? null, claim: options.claim }),
|
|
51279
|
+
credentials: "omit",
|
|
51280
|
+
signal
|
|
51281
|
+
});
|
|
51282
|
+
if (!response.ok) {
|
|
51283
|
+
let code = null;
|
|
51284
|
+
try {
|
|
51285
|
+
const data2 = await response.json();
|
|
51286
|
+
code = typeof (data2 == null ? void 0 : data2.error) === "string" ? data2.error : null;
|
|
51287
|
+
} catch {
|
|
51288
|
+
}
|
|
51289
|
+
return { ok: false, status: response.status, code };
|
|
51290
|
+
}
|
|
51291
|
+
const data = await response.json();
|
|
51292
|
+
return {
|
|
51293
|
+
ok: true,
|
|
51294
|
+
presence: data.presence ?? "unknown",
|
|
51295
|
+
task: data.task && typeof data.task === "object" && typeof data.task.phone === "string" ? data.task : null,
|
|
51296
|
+
pollIntervalMs: typeof data.pollIntervalMs === "number" ? data.pollIntervalMs : 0,
|
|
51297
|
+
presenceTtlSeconds: typeof data.presenceTtlSeconds === "number" && data.presenceTtlSeconds > 0 ? data.presenceTtlSeconds : DEFAULT_PRESENCE_TTL_SECONDS
|
|
51298
|
+
};
|
|
51299
|
+
} finally {
|
|
51300
|
+
clear();
|
|
51301
|
+
}
|
|
51302
|
+
}
|
|
51303
|
+
async function ackClickToCall(options) {
|
|
51304
|
+
const { signal, clear } = withTimeout();
|
|
51305
|
+
try {
|
|
51306
|
+
const response = await fetch(`${options.apiBaseUrl}/api/click-to-call/${encodeURIComponent(options.taskId)}`, {
|
|
51307
|
+
method: "PATCH",
|
|
51308
|
+
headers: options.headers,
|
|
51309
|
+
body: JSON.stringify({ status: options.status, error: options.error, retry: options.retry === true }),
|
|
51310
|
+
credentials: "omit",
|
|
51311
|
+
keepalive: true,
|
|
51312
|
+
signal
|
|
51313
|
+
});
|
|
51314
|
+
if (!response.ok) {
|
|
51315
|
+
let code = null;
|
|
51316
|
+
try {
|
|
51317
|
+
const data2 = await response.json();
|
|
51318
|
+
code = typeof (data2 == null ? void 0 : data2.error) === "string" ? data2.error : null;
|
|
51319
|
+
} catch {
|
|
51320
|
+
}
|
|
51321
|
+
return { ok: false, status: response.status, code };
|
|
51322
|
+
}
|
|
51323
|
+
const data = await response.json();
|
|
51324
|
+
return { ok: true, task: data.task ?? null };
|
|
51325
|
+
} finally {
|
|
51326
|
+
clear();
|
|
51327
|
+
}
|
|
51328
|
+
}
|
|
51329
|
+
function reportClickToCallOffline(config) {
|
|
51330
|
+
try {
|
|
51331
|
+
void fetch(`${config.apiBaseUrl}/api/click-to-call/poll`, {
|
|
51332
|
+
method: "POST",
|
|
51333
|
+
headers: config.headers,
|
|
51334
|
+
body: JSON.stringify({ state: "offline", claim: false }),
|
|
51335
|
+
credentials: "omit",
|
|
51336
|
+
keepalive: true
|
|
51337
|
+
}).catch(() => void 0);
|
|
51338
|
+
} catch {
|
|
51339
|
+
}
|
|
51340
|
+
}
|
|
51341
|
+
const WORKER_SOURCE = `
|
|
51342
|
+
let timer = null;
|
|
51343
|
+
self.onmessage = (event) => {
|
|
51344
|
+
const interval = Number(event && event.data && event.data.interval) || 0;
|
|
51345
|
+
if (timer) { clearInterval(timer); timer = null; }
|
|
51346
|
+
if (interval > 0) { timer = setInterval(() => self.postMessage('tick'), interval); }
|
|
51347
|
+
};
|
|
51348
|
+
`;
|
|
51349
|
+
function createBackgroundTicker(callback, intervalMs) {
|
|
51350
|
+
let current = Math.max(250, Math.round(intervalMs));
|
|
51351
|
+
let fallbackTimer = null;
|
|
51352
|
+
let worker = null;
|
|
51353
|
+
let objectUrl = null;
|
|
51354
|
+
let stopped = false;
|
|
51355
|
+
const startFallback = () => {
|
|
51356
|
+
if (stopped) return;
|
|
51357
|
+
if (fallbackTimer) clearInterval(fallbackTimer);
|
|
51358
|
+
fallbackTimer = setInterval(callback, current);
|
|
51359
|
+
};
|
|
51360
|
+
try {
|
|
51361
|
+
if (typeof Worker !== "undefined" && typeof Blob !== "undefined" && typeof URL !== "undefined" && URL.createObjectURL) {
|
|
51362
|
+
objectUrl = URL.createObjectURL(new Blob([WORKER_SOURCE], { type: "application/javascript" }));
|
|
51363
|
+
worker = new Worker(objectUrl);
|
|
51364
|
+
worker.onmessage = () => {
|
|
51365
|
+
if (!stopped) callback();
|
|
51366
|
+
};
|
|
51367
|
+
worker.onerror = () => {
|
|
51368
|
+
worker == null ? void 0 : worker.terminate();
|
|
51369
|
+
worker = null;
|
|
51370
|
+
startFallback();
|
|
51371
|
+
};
|
|
51372
|
+
worker.postMessage({ interval: current });
|
|
51373
|
+
} else {
|
|
51374
|
+
startFallback();
|
|
51375
|
+
}
|
|
51376
|
+
} catch {
|
|
51377
|
+
worker = null;
|
|
51378
|
+
startFallback();
|
|
51379
|
+
}
|
|
51380
|
+
return {
|
|
51381
|
+
setInterval(ms2) {
|
|
51382
|
+
if (stopped) return;
|
|
51383
|
+
const next = Math.max(250, Math.round(ms2));
|
|
51384
|
+
if (next === current) return;
|
|
51385
|
+
current = next;
|
|
51386
|
+
if (worker) {
|
|
51387
|
+
worker.postMessage({ interval: current });
|
|
51388
|
+
} else {
|
|
51389
|
+
startFallback();
|
|
51390
|
+
}
|
|
51391
|
+
},
|
|
51392
|
+
stop() {
|
|
51393
|
+
stopped = true;
|
|
51394
|
+
if (worker) {
|
|
51395
|
+
worker.terminate();
|
|
51396
|
+
worker = null;
|
|
51397
|
+
}
|
|
51398
|
+
if (objectUrl) {
|
|
51399
|
+
URL.revokeObjectURL(objectUrl);
|
|
51400
|
+
objectUrl = null;
|
|
51401
|
+
}
|
|
51402
|
+
if (fallbackTimer) {
|
|
51403
|
+
clearInterval(fallbackTimer);
|
|
51404
|
+
fallbackTimer = null;
|
|
51405
|
+
}
|
|
51406
|
+
}
|
|
51407
|
+
};
|
|
51408
|
+
}
|
|
51409
|
+
function nationalDigitsFromE164(e164) {
|
|
51410
|
+
const digits = (e164 ?? "").replace(/\D/g, "");
|
|
51411
|
+
if (digits.startsWith("55") && (digits.length === 12 || digits.length === 13)) {
|
|
51412
|
+
return digits.slice(2);
|
|
51413
|
+
}
|
|
51414
|
+
return e164.startsWith("+") ? `+${digits}` : digits;
|
|
51415
|
+
}
|
|
51144
51416
|
const DEFAULT_DIALER_DIMENSIONS = { width: 448, height: 640 };
|
|
51145
51417
|
const MIN_DIALER_WIDTH = 280;
|
|
51146
51418
|
const MIN_DIALER_HEIGHT = 420;
|
|
@@ -51344,6 +51616,17 @@ function FloatingDialer({
|
|
|
51344
51616
|
}
|
|
51345
51617
|
prevAuthRef.current = isAuthenticated;
|
|
51346
51618
|
}, [isAuthenticated]);
|
|
51619
|
+
useEffect(() => {
|
|
51620
|
+
const onClickToCall = (event) => {
|
|
51621
|
+
const task = event.detail;
|
|
51622
|
+
setIsOpen(true);
|
|
51623
|
+
if (task == null ? void 0 : task.phone) {
|
|
51624
|
+
updateDialValue(nationalDigitsFromE164(task.phone).slice(0, MAX_DIAL_LENGTH));
|
|
51625
|
+
}
|
|
51626
|
+
};
|
|
51627
|
+
window.addEventListener(CLICK_TO_CALL_EVENT, onClickToCall);
|
|
51628
|
+
return () => window.removeEventListener(CLICK_TO_CALL_EVENT, onClickToCall);
|
|
51629
|
+
}, [updateDialValue]);
|
|
51347
51630
|
const prevLoginSignalRef = useRef(false);
|
|
51348
51631
|
useEffect(() => {
|
|
51349
51632
|
const hasLoginSignal = !isAuthenticated && Boolean(loginConfirmation || sessionError);
|
|
@@ -51845,7 +52128,8 @@ function AuthenticatedDialer({
|
|
|
51845
52128
|
typeof window !== "undefined" ? window.innerWidth <= 640 : false
|
|
51846
52129
|
);
|
|
51847
52130
|
const isMobileVariant = variant === "mobile";
|
|
51848
|
-
const
|
|
52131
|
+
const inputProfile = useInputProfile();
|
|
52132
|
+
const isMobileLayout = isMobileVariant || isMobileViewport && inputProfile.touchLike;
|
|
51849
52133
|
const breaks = useSignal(operator == null ? void 0 : operator.breaks) || [];
|
|
51850
52134
|
const { goOnBreak, goOffBreak } = useOperatorBreak();
|
|
51851
52135
|
const sanitizedDialValue = useMemo(() => dialValue.slice(0, MAX_DIAL_LENGTH), [dialValue]);
|
|
@@ -51879,11 +52163,16 @@ function AuthenticatedDialer({
|
|
|
51879
52163
|
[becomeAvailable]
|
|
51880
52164
|
);
|
|
51881
52165
|
useEffect(() => {
|
|
51882
|
-
if (
|
|
51883
|
-
|
|
51884
|
-
void requestAvailability("Nao foi possivel ficar disponivel automaticamente.");
|
|
52166
|
+
if (hasRequestedAvailabilityRef.current) {
|
|
52167
|
+
return;
|
|
51885
52168
|
}
|
|
51886
|
-
|
|
52169
|
+
hasRequestedAvailabilityRef.current = true;
|
|
52170
|
+
const busyStates = ["onBreak", "manualCallSetup", "manualCallRinging", "manualCallFailed", "callRinging", "callInProgress", "afterCall"];
|
|
52171
|
+
if (callState && busyStates.includes(callState)) {
|
|
52172
|
+
return;
|
|
52173
|
+
}
|
|
52174
|
+
void requestAvailability("Nao foi possivel ficar disponivel automaticamente.");
|
|
52175
|
+
}, [requestAvailability, callState]);
|
|
51887
52176
|
useEffect(() => {
|
|
51888
52177
|
if (callState === "idle") {
|
|
51889
52178
|
setAvailabilityError(null);
|
|
@@ -51968,8 +52257,14 @@ function AuthenticatedDialer({
|
|
|
51968
52257
|
}, 8e3);
|
|
51969
52258
|
return () => window.clearTimeout(timer);
|
|
51970
52259
|
}, [callState]);
|
|
52260
|
+
const normalizedNumberRef = useRef(normalizedNumber);
|
|
52261
|
+
normalizedNumberRef.current = normalizedNumber;
|
|
51971
52262
|
useEffect(() => {
|
|
51972
52263
|
if (callState === "manualCallRinging" || callState === "callInProgress") {
|
|
52264
|
+
const dialed = normalizedNumberRef.current;
|
|
52265
|
+
if (dialed) {
|
|
52266
|
+
setLastDialedNumber((previous) => previous ?? dialed);
|
|
52267
|
+
}
|
|
51973
52268
|
setDialValue("");
|
|
51974
52269
|
}
|
|
51975
52270
|
if (callState === "idle") {
|
|
@@ -52368,6 +52663,16 @@ function AuthenticatedDialer({
|
|
|
52368
52663
|
return newValue;
|
|
52369
52664
|
});
|
|
52370
52665
|
}, [setDialValue, cursorPosition]);
|
|
52666
|
+
useEffect(() => {
|
|
52667
|
+
const onClickToCall = (event) => {
|
|
52668
|
+
const task = event.detail;
|
|
52669
|
+
if (!(task == null ? void 0 : task.phone)) return;
|
|
52670
|
+
setCallError(null);
|
|
52671
|
+
setLastDialedNumber(task.phone);
|
|
52672
|
+
};
|
|
52673
|
+
window.addEventListener(CLICK_TO_CALL_EVENT, onClickToCall);
|
|
52674
|
+
return () => window.removeEventListener(CLICK_TO_CALL_EVENT, onClickToCall);
|
|
52675
|
+
}, []);
|
|
52371
52676
|
const handleCall = useCallback(async () => {
|
|
52372
52677
|
if (!isIdle && !isOnBreak) {
|
|
52373
52678
|
return;
|
|
@@ -54056,30 +54361,65 @@ function historyPhoneDigits(item) {
|
|
|
54056
54361
|
}
|
|
54057
54362
|
return digits;
|
|
54058
54363
|
}
|
|
54364
|
+
function normalizeSearchText(value) {
|
|
54365
|
+
return (value ?? "").toString().normalize("NFD").replace(/[̀-ͯ]/g, "").toLowerCase().replace(/\s+/g, " ").trim();
|
|
54366
|
+
}
|
|
54367
|
+
function classifyHistoryQuery(query) {
|
|
54368
|
+
const raw = (query ?? "").trim();
|
|
54369
|
+
if (!raw) {
|
|
54370
|
+
return { kind: "empty", digits: "", text: "" };
|
|
54371
|
+
}
|
|
54372
|
+
const digits = onlyDigits(raw);
|
|
54373
|
+
const nonPhoneChars = raw.replace(/[\d\s()+\-.]/g, "");
|
|
54374
|
+
if (digits.length >= 3 && nonPhoneChars.length === 0) {
|
|
54375
|
+
return { kind: "phone", digits, text: normalizeSearchText(raw) };
|
|
54376
|
+
}
|
|
54377
|
+
return { kind: "text", digits, text: normalizeSearchText(raw) };
|
|
54378
|
+
}
|
|
54379
|
+
function historySearchHaystack(item) {
|
|
54380
|
+
const parts = [
|
|
54381
|
+
item.formattedPhone,
|
|
54382
|
+
historyPhoneDigits(item),
|
|
54383
|
+
item.callTypeLabel,
|
|
54384
|
+
item.campaignName,
|
|
54385
|
+
item.contactLabel,
|
|
54386
|
+
item.qualificationName,
|
|
54387
|
+
item.failureCauseLabel,
|
|
54388
|
+
item.hangupCauseLabel,
|
|
54389
|
+
item.formattedDate,
|
|
54390
|
+
item.note,
|
|
54391
|
+
item.protocol !== void 0 ? String(item.protocol) : void 0
|
|
54392
|
+
];
|
|
54393
|
+
if (item.fields) {
|
|
54394
|
+
for (const value of Object.values(item.fields)) {
|
|
54395
|
+
if (value !== void 0 && value !== null) {
|
|
54396
|
+
parts.push(String(value));
|
|
54397
|
+
}
|
|
54398
|
+
}
|
|
54399
|
+
}
|
|
54400
|
+
return normalizeSearchText(parts.filter(Boolean).join(" | "));
|
|
54401
|
+
}
|
|
54402
|
+
function itemMatchesHistoryQuery(item, query) {
|
|
54403
|
+
if (query.kind === "empty") {
|
|
54404
|
+
return true;
|
|
54405
|
+
}
|
|
54406
|
+
if (query.kind === "phone") {
|
|
54407
|
+
return historyPhoneDigits(item).includes(query.digits) || onlyDigits(item.phoneNumber).includes(query.digits) || item.protocol !== void 0 && String(item.protocol).includes(query.digits);
|
|
54408
|
+
}
|
|
54409
|
+
const haystack = historySearchHaystack(item);
|
|
54410
|
+
const terms = query.text.split(" ").filter(Boolean);
|
|
54411
|
+
return terms.every((term) => haystack.includes(term));
|
|
54412
|
+
}
|
|
54413
|
+
function filterHistoryItems(items, query) {
|
|
54414
|
+
const parsed = typeof query === "string" ? classifyHistoryQuery(query) : query;
|
|
54415
|
+
if (parsed.kind === "empty") {
|
|
54416
|
+
return items;
|
|
54417
|
+
}
|
|
54418
|
+
return items.filter((item) => itemMatchesHistoryQuery(item, parsed));
|
|
54419
|
+
}
|
|
54059
54420
|
const DEFAULT_QUALIFICATION = "chamada sem qualificação";
|
|
54421
|
+
const SEARCH_DEBOUNCE_MS = 350;
|
|
54060
54422
|
const DETAILS_TITLE = "Ver detalhes da chamada";
|
|
54061
|
-
async function fetchJson(url, headers) {
|
|
54062
|
-
const response = await fetch(url, { method: "GET", headers, credentials: "omit" });
|
|
54063
|
-
if (!response.ok) {
|
|
54064
|
-
const body = await response.json().catch(() => ({}));
|
|
54065
|
-
throw new Error(body.error || `Erro ${response.status}`);
|
|
54066
|
-
}
|
|
54067
|
-
return await response.json();
|
|
54068
|
-
}
|
|
54069
|
-
async function fetchCampaignForm(apiBaseUrl, contactId, headers) {
|
|
54070
|
-
const config = await fetchJson(`${apiBaseUrl}/api/campaign-config/${contactId}`, headers);
|
|
54071
|
-
if (!(config == null ? void 0 : config.campaignModelId)) {
|
|
54072
|
-
throw new Error("Formulário da campanha não encontrado");
|
|
54073
|
-
}
|
|
54074
|
-
const [fields, values] = await Promise.all([
|
|
54075
|
-
fetchJson(`${apiBaseUrl}/api/campaign-fields/${config.campaignModelId}`, headers),
|
|
54076
|
-
fetchJson(`${apiBaseUrl}/api/campaign-contact/${contactId}`, headers)
|
|
54077
|
-
]);
|
|
54078
|
-
return {
|
|
54079
|
-
rows: Array.isArray(fields == null ? void 0 : fields.rows) ? fields.rows.filter((row) => Array.isArray(row) && row.length > 0) : [],
|
|
54080
|
-
values: values && typeof values === "object" ? values : {}
|
|
54081
|
-
};
|
|
54082
|
-
}
|
|
54083
54423
|
function useRecordings(apiBaseUrl, getAuthHeaders2) {
|
|
54084
54424
|
const [states, setStates] = useState({});
|
|
54085
54425
|
const statesRef = useRef(states);
|
|
@@ -54335,7 +54675,7 @@ function CallDetailsSheet({
|
|
|
54335
54675
|
onCall,
|
|
54336
54676
|
onWhatsApp
|
|
54337
54677
|
}) {
|
|
54338
|
-
const [form, setForm] = useState({ status: "idle",
|
|
54678
|
+
const [form, setForm] = useState({ status: "idle", form: null });
|
|
54339
54679
|
const closeButtonRef = useRef(null);
|
|
54340
54680
|
const isCampaign = item.callType === "campaign";
|
|
54341
54681
|
useEffect(() => {
|
|
@@ -54361,65 +54701,79 @@ function CallDetailsSheet({
|
|
|
54361
54701
|
}, [onClose]);
|
|
54362
54702
|
useEffect(() => {
|
|
54363
54703
|
if (!isCampaign || !item.campaignContactId) {
|
|
54364
|
-
setForm({ status: "idle",
|
|
54704
|
+
setForm({ status: "idle", form: null });
|
|
54365
54705
|
return;
|
|
54366
54706
|
}
|
|
54367
54707
|
let cancelled = false;
|
|
54368
|
-
setForm({ status: "loading",
|
|
54369
|
-
fetchCampaignForm(
|
|
54708
|
+
setForm({ status: "loading", form: null });
|
|
54709
|
+
fetchCampaignForm(
|
|
54710
|
+
{
|
|
54711
|
+
source: "campaign",
|
|
54712
|
+
id: item.campaignContactId,
|
|
54713
|
+
campaignId: item.campaignId ?? null,
|
|
54714
|
+
signature: item.formSignature ?? null,
|
|
54715
|
+
expiresAt: item.formExpiresAt ?? null
|
|
54716
|
+
},
|
|
54717
|
+
{ apiBaseUrl, headers: getAuthHeaders2(), retries: 0 }
|
|
54718
|
+
).then((result2) => {
|
|
54370
54719
|
if (!cancelled) {
|
|
54371
|
-
setForm({ status: "ready",
|
|
54720
|
+
setForm({ status: "ready", form: result2 });
|
|
54372
54721
|
}
|
|
54373
54722
|
}).catch((error2) => {
|
|
54374
54723
|
if (!cancelled) {
|
|
54375
54724
|
console.warn("[CallHistoryList] Formulário da campanha indisponível, usando campos do histórico:", error2);
|
|
54376
|
-
setForm({
|
|
54377
|
-
status: "error",
|
|
54378
|
-
rows: [],
|
|
54379
|
-
values: {},
|
|
54380
|
-
error: error2 instanceof Error ? error2.message : "Erro ao carregar formulário"
|
|
54381
|
-
});
|
|
54725
|
+
setForm({ status: "error", form: null, error: error2 instanceof Error ? error2.message : "Erro ao carregar formulário" });
|
|
54382
54726
|
}
|
|
54383
54727
|
});
|
|
54384
54728
|
return () => {
|
|
54385
54729
|
cancelled = true;
|
|
54386
54730
|
};
|
|
54387
|
-
}, [apiBaseUrl, getAuthHeaders2, isCampaign, item.campaignContactId, item.id]);
|
|
54731
|
+
}, [apiBaseUrl, getAuthHeaders2, isCampaign, item.campaignContactId, item.campaignId, item.id]);
|
|
54388
54732
|
const fallbackFields = useMemo(
|
|
54389
54733
|
() => Object.entries(item.fields ?? {}).filter(
|
|
54390
54734
|
([key, value]) => value !== void 0 && value !== null && String(value).trim() !== "" && !isInternalFieldKey(key)
|
|
54391
54735
|
),
|
|
54392
54736
|
[item.fields]
|
|
54393
54737
|
);
|
|
54738
|
+
const fallbackByKey = useMemo(() => {
|
|
54739
|
+
const map = /* @__PURE__ */ new Map();
|
|
54740
|
+
for (const [key, value] of Object.entries(item.fields ?? {})) {
|
|
54741
|
+
if (value === void 0 || value === null || String(value).trim() === "") continue;
|
|
54742
|
+
map.set(stripAccents(normalizeFormKey(key)), String(value));
|
|
54743
|
+
}
|
|
54744
|
+
return map;
|
|
54745
|
+
}, [item.fields]);
|
|
54394
54746
|
const resolveFieldValue = (field) => {
|
|
54395
|
-
|
|
54396
|
-
|
|
54397
|
-
if (byCode !== void 0 && byCode !== null && String(byCode).trim() !== "") {
|
|
54398
|
-
return String(byCode);
|
|
54399
|
-
}
|
|
54400
|
-
const byName = (_a2 = item.fields) == null ? void 0 : _a2[field.name];
|
|
54401
|
-
if (byName !== void 0 && byName !== null && String(byName).trim() !== "") {
|
|
54402
|
-
return String(byName);
|
|
54747
|
+
if (field.value && field.value.trim() !== "") {
|
|
54748
|
+
return field.value;
|
|
54403
54749
|
}
|
|
54404
|
-
|
|
54750
|
+
const byName = fallbackByKey.get(stripAccents(normalizeFormKey(field.label))) ?? fallbackByKey.get(stripAccents(normalizeFormKey(field.key)));
|
|
54751
|
+
return byName ?? "-";
|
|
54405
54752
|
};
|
|
54406
|
-
const
|
|
54753
|
+
const formRows = form.status === "ready" && form.form ? form.form.rows && form.form.rows.length > 0 ? form.form.rows : form.form.fields.length > 0 ? [form.form.fields] : [] : [];
|
|
54754
|
+
const hasFormRows = formRows.length > 0;
|
|
54407
54755
|
let formContent;
|
|
54408
|
-
if (form.status === "loading") {
|
|
54756
|
+
if (form.status === "loading" && fallbackFields.length === 0) {
|
|
54409
54757
|
formContent = /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "details-loading", role: "status", children: [
|
|
54410
54758
|
/* @__PURE__ */ jsxRuntimeExports.jsx("i", { className: "fas fa-spinner fa-spin", "aria-hidden": "true" }),
|
|
54411
54759
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Carregando formulário..." })
|
|
54412
54760
|
] });
|
|
54413
54761
|
} else if (hasFormRows) {
|
|
54414
|
-
formContent =
|
|
54415
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "details-field-label", title: field.
|
|
54762
|
+
formContent = formRows.map((row, rowIndex) => /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "details-form-row", children: row.map((field, fieldIndex) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "details-field", children: [
|
|
54763
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "details-field-label", title: field.label, children: field.label }),
|
|
54416
54764
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "details-field-value", children: resolveFieldValue(field) })
|
|
54417
|
-
] }, `${rowIndex}-${fieldIndex}-${field.
|
|
54765
|
+
] }, `${rowIndex}-${fieldIndex}-${field.key}`)) }, rowIndex));
|
|
54418
54766
|
} else if (fallbackFields.length > 0) {
|
|
54419
|
-
formContent = /* @__PURE__ */ jsxRuntimeExports.
|
|
54420
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
54421
|
-
|
|
54422
|
-
|
|
54767
|
+
formContent = /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
54768
|
+
form.status === "loading" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "details-loading details-loading-inline", role: "status", children: [
|
|
54769
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("i", { className: "fas fa-spinner fa-spin", "aria-hidden": "true" }),
|
|
54770
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Atualizando formulário..." })
|
|
54771
|
+
] }),
|
|
54772
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "details-form-row", children: fallbackFields.map(([key, value]) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "details-field", children: [
|
|
54773
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "details-field-label", title: key, children: key }),
|
|
54774
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "details-field-value", children: value })
|
|
54775
|
+
] }, key)) })
|
|
54776
|
+
] });
|
|
54423
54777
|
} else {
|
|
54424
54778
|
formContent = /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "details-empty", children: [
|
|
54425
54779
|
/* @__PURE__ */ jsxRuntimeExports.jsx("i", { className: "fas fa-user", "aria-hidden": "true" }),
|
|
@@ -54528,12 +54882,52 @@ function CallHistoryList({
|
|
|
54528
54882
|
onCall,
|
|
54529
54883
|
onWhatsApp,
|
|
54530
54884
|
apiBaseUrl,
|
|
54531
|
-
getAuthHeaders: getAuthHeaders2
|
|
54885
|
+
getAuthHeaders: getAuthHeaders2,
|
|
54886
|
+
query,
|
|
54887
|
+
onQueryChange,
|
|
54888
|
+
isSearching = false,
|
|
54889
|
+
searchHint = null
|
|
54532
54890
|
}) {
|
|
54533
54891
|
const [openPlayerId, setOpenPlayerId] = useState(null);
|
|
54534
54892
|
const [selectedId, setSelectedId] = useState(null);
|
|
54535
54893
|
const recordings = useRecordings(apiBaseUrl, getAuthHeaders2);
|
|
54536
54894
|
const { retain } = recordings;
|
|
54895
|
+
const [draft, setDraft] = useState(query ?? "");
|
|
54896
|
+
const lastEmittedRef = useRef(query ?? "");
|
|
54897
|
+
const debounceRef = useRef(null);
|
|
54898
|
+
useEffect(() => {
|
|
54899
|
+
const external = query ?? "";
|
|
54900
|
+
if (external !== lastEmittedRef.current) {
|
|
54901
|
+
lastEmittedRef.current = external;
|
|
54902
|
+
setDraft(external);
|
|
54903
|
+
}
|
|
54904
|
+
}, [query]);
|
|
54905
|
+
useEffect(() => {
|
|
54906
|
+
return () => {
|
|
54907
|
+
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
54908
|
+
};
|
|
54909
|
+
}, []);
|
|
54910
|
+
const handleDraftChange = useCallback(
|
|
54911
|
+
(value) => {
|
|
54912
|
+
setDraft(value);
|
|
54913
|
+
if (!onQueryChange) return;
|
|
54914
|
+
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
54915
|
+
debounceRef.current = setTimeout(() => {
|
|
54916
|
+
lastEmittedRef.current = value;
|
|
54917
|
+
onQueryChange(value);
|
|
54918
|
+
}, SEARCH_DEBOUNCE_MS);
|
|
54919
|
+
},
|
|
54920
|
+
[onQueryChange]
|
|
54921
|
+
);
|
|
54922
|
+
const clearSearch = useCallback(() => {
|
|
54923
|
+
setDraft("");
|
|
54924
|
+
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
54925
|
+
lastEmittedRef.current = "";
|
|
54926
|
+
onQueryChange == null ? void 0 : onQueryChange("");
|
|
54927
|
+
}, [onQueryChange]);
|
|
54928
|
+
const parsedQuery = useMemo(() => classifyHistoryQuery(draft), [draft]);
|
|
54929
|
+
const visibleItems = useMemo(() => filterHistoryItems(items, parsedQuery), [items, parsedQuery]);
|
|
54930
|
+
const hasQuery = parsedQuery.kind !== "empty";
|
|
54537
54931
|
const dayLabels = useMemo(() => {
|
|
54538
54932
|
const now = /* @__PURE__ */ new Date();
|
|
54539
54933
|
const labels = {};
|
|
@@ -54583,6 +54977,28 @@ function CallHistoryList({
|
|
|
54583
54977
|
/* @__PURE__ */ jsxRuntimeExports.jsx("h1", { className: "header-title", children: "Recentes" }),
|
|
54584
54978
|
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "history-refresh-btn", onClick: onRefresh, disabled: isLoading, "aria-label": "Atualizar histórico", children: /* @__PURE__ */ jsxRuntimeExports.jsx("i", { className: `fas fa-arrows-rotate ${isLoading ? "fa-spin" : ""}`, "aria-hidden": "true" }) })
|
|
54585
54979
|
] }),
|
|
54980
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "history-search-bar", children: [
|
|
54981
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "history-search", children: [
|
|
54982
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("i", { className: "fas fa-magnifying-glass history-search-icon", "aria-hidden": "true" }),
|
|
54983
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
54984
|
+
"input",
|
|
54985
|
+
{
|
|
54986
|
+
type: "search",
|
|
54987
|
+
className: "history-search-input",
|
|
54988
|
+
placeholder: "Buscar número, campanha, cliente...",
|
|
54989
|
+
"aria-label": "Buscar no histórico",
|
|
54990
|
+
autoComplete: "off",
|
|
54991
|
+
autoCapitalize: "none",
|
|
54992
|
+
autoCorrect: "off",
|
|
54993
|
+
spellCheck: false,
|
|
54994
|
+
value: draft,
|
|
54995
|
+
onChange: (event) => handleDraftChange(event.target.value)
|
|
54996
|
+
}
|
|
54997
|
+
),
|
|
54998
|
+
isSearching ? /* @__PURE__ */ jsxRuntimeExports.jsx("i", { className: "fas fa-spinner fa-spin history-search-spinner", "aria-hidden": "true", title: "Buscando..." }) : draft ? /* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "history-search-clear", onClick: clearSearch, "aria-label": "Limpar busca", children: /* @__PURE__ */ jsxRuntimeExports.jsx("i", { className: "fas fa-xmark", "aria-hidden": "true" }) }) : null
|
|
54999
|
+
] }),
|
|
55000
|
+
hasQuery && searchHint && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "history-search-hint", children: searchHint })
|
|
55001
|
+
] }),
|
|
54586
55002
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "call-history-list", id: "callHistoryList", children: isLoading && items.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "history-loading", role: "status", children: [
|
|
54587
55003
|
/* @__PURE__ */ jsxRuntimeExports.jsx("i", { className: "fas fa-spinner fa-spin", "aria-hidden": "true" }),
|
|
54588
55004
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Carregando..." })
|
|
@@ -54593,7 +55009,18 @@ function CallHistoryList({
|
|
|
54593
55009
|
] }) : items.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "history-empty", children: [
|
|
54594
55010
|
/* @__PURE__ */ jsxRuntimeExports.jsx("i", { className: "fas fa-phone-slash", "aria-hidden": "true" }),
|
|
54595
55011
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Nenhuma ligação recente" })
|
|
54596
|
-
] }) :
|
|
55012
|
+
] }) : visibleItems.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "history-empty history-empty-search", children: [
|
|
55013
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("i", { className: "fas fa-magnifying-glass", "aria-hidden": "true" }),
|
|
55014
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
|
|
55015
|
+
"Nenhuma chamada encontrada para ",
|
|
55016
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("strong", { children: [
|
|
55017
|
+
"“",
|
|
55018
|
+
draft.trim(),
|
|
55019
|
+
"”"
|
|
55020
|
+
] })
|
|
55021
|
+
] }),
|
|
55022
|
+
isSearching && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "history-search-status", children: "Buscando no servidor..." })
|
|
55023
|
+
] }) : visibleItems.map((item) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
54597
55024
|
HistoryRow,
|
|
54598
55025
|
{
|
|
54599
55026
|
item,
|
|
@@ -56073,99 +56500,17 @@ function formatDuration(seconds) {
|
|
|
56073
56500
|
}
|
|
56074
56501
|
return `${mins}:${secs.toString().padStart(2, "0")}`;
|
|
56075
56502
|
}
|
|
56076
|
-
|
|
56077
|
-
|
|
56078
|
-
|
|
56079
|
-
|
|
56080
|
-
|
|
56081
|
-
|
|
56082
|
-
const response = await fetch(url, options);
|
|
56083
|
-
const duration = Date.now() - startTime;
|
|
56084
|
-
console.log(`[DraggableClientInfoModal] ⏱️ Resposta em ${duration}ms - Status: ${response.status}`);
|
|
56085
|
-
if (!response.ok) {
|
|
56086
|
-
if (response.status >= 400 && response.status < 500) {
|
|
56087
|
-
const error2 = await response.json().catch(() => ({ error: "Erro desconhecido" }));
|
|
56088
|
-
console.error(`[DraggableClientInfoModal] ❌ Erro do cliente (${response.status}):`, error2);
|
|
56089
|
-
throw new Error(error2.error || `Falha: ${response.status}`);
|
|
56090
|
-
}
|
|
56091
|
-
console.warn(`[DraggableClientInfoModal] ⚠️ Erro do servidor (${response.status}), tentando novamente...`);
|
|
56092
|
-
throw new Error(`HTTP ${response.status}`);
|
|
56093
|
-
}
|
|
56094
|
-
const json = await response.json();
|
|
56095
|
-
console.log(`[DraggableClientInfoModal] ✅ Dados recebidos com sucesso`);
|
|
56096
|
-
return json;
|
|
56097
|
-
} catch (error2) {
|
|
56098
|
-
const isLastAttempt = i2 === retries - 1;
|
|
56099
|
-
if (isLastAttempt) {
|
|
56100
|
-
console.error(`[DraggableClientInfoModal] 💥 Falha final após ${retries} tentativas:`, error2);
|
|
56101
|
-
throw error2;
|
|
56102
|
-
}
|
|
56103
|
-
const delay = backoff * Math.pow(2, i2);
|
|
56104
|
-
console.warn(`[DraggableClientInfoModal] ⏳ Aguardando ${delay}ms antes da próxima tentativa...`);
|
|
56105
|
-
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
56106
|
-
}
|
|
56107
|
-
}
|
|
56108
|
-
throw new Error("Todas as tentativas falharam");
|
|
56109
|
-
}
|
|
56110
|
-
async function getCampaignConfig$1(contactId) {
|
|
56111
|
-
const url = `${API_BASE_URL}/api/campaign-config/${contactId}`;
|
|
56112
|
-
return fetchWithRetry(url, {
|
|
56113
|
-
method: "GET",
|
|
56114
|
-
headers: getAuthHeaders(),
|
|
56115
|
-
credentials: "omit"
|
|
56116
|
-
});
|
|
56117
|
-
}
|
|
56118
|
-
async function getCampaignFields(campaignModelId) {
|
|
56119
|
-
const url = `${API_BASE_URL}/api/campaign-fields/${campaignModelId}`;
|
|
56120
|
-
const json = await fetchWithRetry(url, {
|
|
56121
|
-
method: "GET",
|
|
56122
|
-
headers: getAuthHeaders(),
|
|
56123
|
-
credentials: "omit"
|
|
56124
|
-
});
|
|
56125
|
-
console.log("[DraggableClientInfoModal] Estrutura de campos recebida:", json);
|
|
56126
|
-
if (!json.rows || !Array.isArray(json.rows)) {
|
|
56127
|
-
console.warn("[DraggableClientInfoModal] Estrutura de campos inválida, usando fallback");
|
|
56128
|
-
return {
|
|
56129
|
-
rows: [],
|
|
56130
|
-
labelField: null,
|
|
56131
|
-
phoneFields: []
|
|
56132
|
-
};
|
|
56133
|
-
}
|
|
56134
|
-
return json;
|
|
56135
|
-
}
|
|
56136
|
-
async function getCustomerFields(formId) {
|
|
56137
|
-
const url = `${API_BASE_URL}/api/campaign-contact/0?source=customer&formId=${encodeURIComponent(String(formId))}`;
|
|
56138
|
-
const json = await fetchWithRetry(url, {
|
|
56139
|
-
method: "GET",
|
|
56140
|
-
headers: getAuthHeaders(),
|
|
56141
|
-
credentials: "omit"
|
|
56142
|
-
});
|
|
56143
|
-
console.log("[DraggableClientInfoModal] (cliente) Estrutura de campos recebida:", json);
|
|
56144
|
-
if (!json.rows || !Array.isArray(json.rows)) {
|
|
56145
|
-
console.warn("[DraggableClientInfoModal] (cliente) Estrutura de campos inválida, usando fallback");
|
|
56146
|
-
return { rows: [], labelField: null, phoneFields: [] };
|
|
56147
|
-
}
|
|
56148
|
-
return json;
|
|
56149
|
-
}
|
|
56150
|
-
async function getContactValues$1(contactId) {
|
|
56151
|
-
const url = `${API_BASE_URL}/api/campaign-contact/${contactId}`;
|
|
56152
|
-
return fetchWithRetry(url, {
|
|
56153
|
-
method: "GET",
|
|
56154
|
-
headers: getAuthHeaders(),
|
|
56155
|
-
credentials: "omit"
|
|
56156
|
-
});
|
|
56157
|
-
}
|
|
56158
|
-
async function getCustomerContactValues(customerId) {
|
|
56159
|
-
const url = `${API_BASE_URL}/api/campaign-fields/0?source=customer&customerId=${encodeURIComponent(String(customerId))}`;
|
|
56160
|
-
return fetchWithRetry(url, {
|
|
56161
|
-
method: "GET",
|
|
56162
|
-
headers: getAuthHeaders(),
|
|
56163
|
-
credentials: "omit"
|
|
56164
|
-
});
|
|
56503
|
+
function gridColsFor(count) {
|
|
56504
|
+
if (count === 2) return "grid-cols-2";
|
|
56505
|
+
if (count === 3) return "grid-cols-3";
|
|
56506
|
+
if (count === 4) return "grid-cols-4";
|
|
56507
|
+
if (count >= 5) return "grid-cols-5";
|
|
56508
|
+
return "grid-cols-1";
|
|
56165
56509
|
}
|
|
56166
56510
|
function DraggableClientInfoModal({
|
|
56167
56511
|
isOpen,
|
|
56168
56512
|
campaignCallInfo,
|
|
56513
|
+
campaignContactPhoneId,
|
|
56169
56514
|
callDuration,
|
|
56170
56515
|
isCallActive,
|
|
56171
56516
|
onClose
|
|
@@ -56175,12 +56520,19 @@ function DraggableClientInfoModal({
|
|
|
56175
56520
|
const dragMovedRef = useRef(false);
|
|
56176
56521
|
const [position2, setPosition] = useState({ x: 100, y: 100 });
|
|
56177
56522
|
const [isDragging, setIsDragging] = useState(false);
|
|
56178
|
-
const [
|
|
56179
|
-
const [fieldRows, setFieldRows] = useState([]);
|
|
56523
|
+
const [form, setForm] = useState(null);
|
|
56180
56524
|
const [isLoading, setIsLoading] = useState(false);
|
|
56181
56525
|
const [error2, setError] = useState(null);
|
|
56182
|
-
const [
|
|
56526
|
+
const [retry, setRetry] = useState({ key: null, n: 0 });
|
|
56183
56527
|
const campaignContact = campaignCallInfo == null ? void 0 : campaignCallInfo.campaignContact;
|
|
56528
|
+
const request = useMemo(
|
|
56529
|
+
() => campaignFormRequestFromCallInfo(campaignCallInfo, campaignContactPhoneId),
|
|
56530
|
+
[campaignCallInfo, campaignContactPhoneId]
|
|
56531
|
+
);
|
|
56532
|
+
const requestKey = request ? campaignFormCacheKey(request) : null;
|
|
56533
|
+
const requestRef = useRef(request);
|
|
56534
|
+
requestRef.current = request;
|
|
56535
|
+
const partialRefreshKeyRef = useRef(null);
|
|
56184
56536
|
const clampPositionToViewport = useCallback((proposed) => {
|
|
56185
56537
|
if (typeof window === "undefined") {
|
|
56186
56538
|
return proposed;
|
|
@@ -56224,62 +56576,40 @@ function DraggableClientInfoModal({
|
|
|
56224
56576
|
};
|
|
56225
56577
|
}, [isOpen, clampPositionToViewport]);
|
|
56226
56578
|
useEffect(() => {
|
|
56227
|
-
|
|
56228
|
-
|
|
56229
|
-
|
|
56230
|
-
|
|
56579
|
+
const current = requestRef.current;
|
|
56580
|
+
if (!current || !requestKey) {
|
|
56581
|
+
setForm(null);
|
|
56582
|
+
setError(null);
|
|
56583
|
+
setIsLoading(false);
|
|
56231
56584
|
return;
|
|
56232
56585
|
}
|
|
56233
56586
|
let cancelled = false;
|
|
56234
|
-
|
|
56235
|
-
|
|
56236
|
-
|
|
56237
|
-
|
|
56238
|
-
|
|
56239
|
-
console.log("[DraggableClientInfoModal]
|
|
56240
|
-
|
|
56241
|
-
|
|
56242
|
-
if (
|
|
56243
|
-
|
|
56244
|
-
|
|
56245
|
-
getCustomerFields(customer.formId),
|
|
56246
|
-
getCustomerContactValues(customer.id)
|
|
56247
|
-
]);
|
|
56248
|
-
} else {
|
|
56249
|
-
console.log("[DraggableClientInfoModal] Modo CAMPANHA: buscando config, campos e valores");
|
|
56250
|
-
const config = await getCampaignConfig$1(campaignContact.id);
|
|
56251
|
-
console.log("[DraggableClientInfoModal] Config recebida:", config);
|
|
56252
|
-
if (!config.campaignModelId) {
|
|
56253
|
-
throw new Error("campaignModelId não encontrado");
|
|
56254
|
-
}
|
|
56255
|
-
[campaignFields, contactValues] = await Promise.all([
|
|
56256
|
-
getCampaignFields(config.campaignModelId),
|
|
56257
|
-
getContactValues$1(campaignContact.id)
|
|
56258
|
-
]);
|
|
56259
|
-
}
|
|
56260
|
-
console.log("[DraggableClientInfoModal] Campos recebidos:", campaignFields);
|
|
56261
|
-
console.log("[DraggableClientInfoModal] Valores recebidos:", contactValues);
|
|
56262
|
-
if (!cancelled) {
|
|
56263
|
-
console.log("[DraggableClientInfoModal] ✅ Dados carregados com sucesso");
|
|
56264
|
-
setContactData(contactValues);
|
|
56265
|
-
setFieldRows(campaignFields.rows || []);
|
|
56266
|
-
setFetchedContactId(campaignContact.id);
|
|
56267
|
-
setIsLoading(false);
|
|
56268
|
-
}
|
|
56269
|
-
} catch (err) {
|
|
56270
|
-
if (!cancelled) {
|
|
56271
|
-
console.error("[DraggableClientInfoModal] ❌ Erro ao buscar dados:", err);
|
|
56272
|
-
const errorMessage = err instanceof Error ? err.message : "Erro ao buscar dados do contato";
|
|
56273
|
-
setError(errorMessage);
|
|
56274
|
-
setIsLoading(false);
|
|
56587
|
+
let refreshTimer = null;
|
|
56588
|
+
setIsLoading(true);
|
|
56589
|
+
setError(null);
|
|
56590
|
+
fetchCampaignForm(current, { force: retry.key === requestKey && retry.n > 0 }).then((result2) => {
|
|
56591
|
+
if (!cancelled) {
|
|
56592
|
+
console.log("[DraggableClientInfoModal] ✅ Formulário carregado:", result2.valuesSource, result2.layoutSource, result2.fields.length, "campos", result2.partial ? "(parcial)" : "");
|
|
56593
|
+
setForm(result2);
|
|
56594
|
+
setIsLoading(false);
|
|
56595
|
+
if (result2.partial && partialRefreshKeyRef.current !== requestKey) {
|
|
56596
|
+
partialRefreshKeyRef.current = requestKey;
|
|
56597
|
+
refreshTimer = setTimeout(() => setRetry((prev) => ({ key: requestKey, n: prev.n + 1 })), 3e3);
|
|
56275
56598
|
}
|
|
56276
56599
|
}
|
|
56277
|
-
}
|
|
56278
|
-
|
|
56600
|
+
}).catch((err) => {
|
|
56601
|
+
if (!cancelled) {
|
|
56602
|
+
console.error("[DraggableClientInfoModal] ❌ Erro ao buscar o formulário:", err);
|
|
56603
|
+
setForm(null);
|
|
56604
|
+
setError(err instanceof Error ? err.message : "Erro ao buscar dados do contato");
|
|
56605
|
+
setIsLoading(false);
|
|
56606
|
+
}
|
|
56607
|
+
});
|
|
56279
56608
|
return () => {
|
|
56280
56609
|
cancelled = true;
|
|
56610
|
+
if (refreshTimer) clearTimeout(refreshTimer);
|
|
56281
56611
|
};
|
|
56282
|
-
}, [
|
|
56612
|
+
}, [requestKey, retry]);
|
|
56283
56613
|
useEffect(() => {
|
|
56284
56614
|
if (!isDragging) {
|
|
56285
56615
|
return;
|
|
@@ -56341,14 +56671,16 @@ function DraggableClientInfoModal({
|
|
|
56341
56671
|
onClose();
|
|
56342
56672
|
}
|
|
56343
56673
|
}, [isCallActive, onClose]);
|
|
56674
|
+
const handleRetry = useCallback(() => {
|
|
56675
|
+
setRetry((prev) => ({ key: requestKey, n: prev.n + 1 }));
|
|
56676
|
+
}, [requestKey]);
|
|
56344
56677
|
if (!isOpen) {
|
|
56345
56678
|
return null;
|
|
56346
56679
|
}
|
|
56347
|
-
const
|
|
56348
|
-
const
|
|
56349
|
-
const
|
|
56350
|
-
|
|
56351
|
-
};
|
|
56680
|
+
const rows = (form == null ? void 0 : form.rows) && form.rows.length > 0 ? form.rows : [];
|
|
56681
|
+
const hasRows = rows.length > 0;
|
|
56682
|
+
const hasFields = Boolean(form && form.fields.length > 0);
|
|
56683
|
+
const hasData = hasRows || hasFields;
|
|
56352
56684
|
const modalContent = /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
56353
56685
|
"div",
|
|
56354
56686
|
{
|
|
@@ -56403,46 +56735,36 @@ function DraggableClientInfoModal({
|
|
|
56403
56735
|
] })
|
|
56404
56736
|
] })
|
|
56405
56737
|
] }),
|
|
56406
|
-
isLoading && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: tw`rounded-lg border border-blue-200 bg-blue-50 p-6 text-center`, children: [
|
|
56738
|
+
isLoading && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: tw`rounded-lg border border-blue-200 bg-blue-50 p-6 text-center`, role: "status", children: [
|
|
56407
56739
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: tw`mx-auto mb-2 inline-block h-6 w-6 animate-spin rounded-full border-2 border-blue-500 border-t-transparent` }),
|
|
56408
56740
|
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: tw`text-xs font-medium text-blue-700`, children: "Carregando dados do contato..." })
|
|
56409
56741
|
] }),
|
|
56410
|
-
error2 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: tw`rounded-lg border border-red-200 bg-red-50 p-3`, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: tw`flex items-center gap-2`, children: [
|
|
56742
|
+
error2 && !isLoading && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: tw`rounded-lg border border-red-200 bg-red-50 p-3`, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: tw`flex items-center gap-2`, children: [
|
|
56411
56743
|
/* @__PURE__ */ jsxRuntimeExports.jsx(FiAlertCircle, { className: tw`h-4 w-4 flex-shrink-0 text-red-600` }),
|
|
56412
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
56744
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: tw`min-w-0 flex-1`, children: [
|
|
56413
56745
|
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: tw`text-xs font-semibold text-red-700`, children: "Erro ao carregar dados" }),
|
|
56414
56746
|
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: tw`text-[10px] text-red-600`, children: error2 })
|
|
56415
|
-
] })
|
|
56416
|
-
|
|
56417
|
-
|
|
56418
|
-
const numFields = row.length;
|
|
56419
|
-
let gridCols = "grid-cols-1";
|
|
56420
|
-
if (numFields === 2) {
|
|
56421
|
-
gridCols = "grid-cols-2";
|
|
56422
|
-
} else if (numFields === 3) {
|
|
56423
|
-
gridCols = "grid-cols-3";
|
|
56424
|
-
} else if (numFields === 4) {
|
|
56425
|
-
gridCols = "grid-cols-4";
|
|
56426
|
-
} else if (numFields === 5) {
|
|
56427
|
-
gridCols = "grid-cols-5";
|
|
56428
|
-
}
|
|
56429
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
56430
|
-
"div",
|
|
56747
|
+
] }),
|
|
56748
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
56749
|
+
"button",
|
|
56431
56750
|
{
|
|
56432
|
-
|
|
56433
|
-
|
|
56434
|
-
|
|
56435
|
-
|
|
56436
|
-
|
|
56437
|
-
|
|
56438
|
-
|
|
56439
|
-
|
|
56440
|
-
|
|
56441
|
-
|
|
56442
|
-
|
|
56443
|
-
|
|
56444
|
-
|
|
56445
|
-
|
|
56751
|
+
type: "button",
|
|
56752
|
+
onClick: handleRetry,
|
|
56753
|
+
className: tw`rounded-md border border-red-300 bg-white px-2 py-1 text-[11px] font-semibold text-red-700 transition hover:bg-red-100`,
|
|
56754
|
+
children: "Tentar novamente"
|
|
56755
|
+
}
|
|
56756
|
+
)
|
|
56757
|
+
] }) }),
|
|
56758
|
+
!isLoading && !error2 && hasRows && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: tw`space-y-2`, children: rows.map((row, rowIndex) => /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: tw`grid gap-2 ${gridColsFor(row.length)}`, children: row.map((field, fieldIndex) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
56759
|
+
Field,
|
|
56760
|
+
{
|
|
56761
|
+
label: field.label,
|
|
56762
|
+
value: field.value || "-",
|
|
56763
|
+
fullWidth: field.width === "100%"
|
|
56764
|
+
},
|
|
56765
|
+
`${rowIndex}-${fieldIndex}-${field.key}`
|
|
56766
|
+
)) }, rowIndex)) }),
|
|
56767
|
+
!isLoading && !error2 && !hasRows && hasFields && form && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: tw`grid grid-cols-2 gap-2`, children: form.fields.map((field) => /* @__PURE__ */ jsxRuntimeExports.jsx(Field, { label: field.label, value: field.value || "-" }, field.key)) }),
|
|
56446
56768
|
!isLoading && !error2 && !hasData && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: tw`flex flex-col items-center justify-center rounded-lg border border-slate-200 bg-slate-50 px-4 py-8 text-center`, children: [
|
|
56447
56769
|
/* @__PURE__ */ jsxRuntimeExports.jsx(FiUser, { className: tw`mb-2 h-8 w-8 text-slate-400` }),
|
|
56448
56770
|
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: tw`text-sm text-slate-500`, children: "Nenhum dado disponível" })
|
|
@@ -56563,104 +56885,8 @@ if (typeof window !== "undefined" && !window.__fetchIntercepted__) {
|
|
|
56563
56885
|
};
|
|
56564
56886
|
console.log("%c[FETCH INTERCEPTOR] ✅ Ativo - todas as requisições serão logadas", "color: #2196F3; font-weight: bold; font-size: 12px");
|
|
56565
56887
|
}
|
|
56566
|
-
async function getCampaignConfig(contactId) {
|
|
56567
|
-
const url = `${API_BASE_URL}/api/campaign-config/${contactId}`;
|
|
56568
|
-
const headers = getAuthHeaders();
|
|
56569
|
-
console.log("[getCampaignConfig] URL:", url);
|
|
56570
|
-
console.log("[getCampaignConfig] Headers:", JSON.stringify(headers));
|
|
56571
|
-
const response = await fetch(url, { method: "GET", headers, credentials: "omit" });
|
|
56572
|
-
if (!response.ok) {
|
|
56573
|
-
const errorBody = await response.json().catch(() => ({ error: "Erro desconhecido" }));
|
|
56574
|
-
console.error("[getCampaignConfig] Erro:", response.status, errorBody);
|
|
56575
|
-
if (response.status === 401) {
|
|
56576
|
-
const token = getSessionToken();
|
|
56577
|
-
console.error("[getCampaignConfig] 401 - Token atual:", token ? `${token.substring(0, 20)}...` : "NULL");
|
|
56578
|
-
console.error("[getCampaignConfig] 401 - Resposta completa:", JSON.stringify(errorBody));
|
|
56579
|
-
}
|
|
56580
|
-
throw new Error(errorBody.error || `Falha ao buscar config: ${response.status}`);
|
|
56581
|
-
}
|
|
56582
|
-
return response.json();
|
|
56583
|
-
}
|
|
56584
|
-
function processRowsToMapping(apiResponse) {
|
|
56585
|
-
const mapping = {};
|
|
56586
|
-
console.log("[processRowsToMapping] Processando estrutura:", typeof apiResponse);
|
|
56587
|
-
if (!apiResponse || typeof apiResponse !== "object") {
|
|
56588
|
-
console.warn("[processRowsToMapping] Resposta inválida:", apiResponse);
|
|
56589
|
-
return mapping;
|
|
56590
|
-
}
|
|
56591
|
-
const data = apiResponse;
|
|
56592
|
-
if (!data.rows || !Array.isArray(data.rows)) {
|
|
56593
|
-
console.warn("[processRowsToMapping] rows não encontrado ou não é array:", data);
|
|
56594
|
-
return mapping;
|
|
56595
|
-
}
|
|
56596
|
-
console.log("[processRowsToMapping] Total de linhas (rows):", data.rows.length);
|
|
56597
|
-
for (let rowIndex = 0; rowIndex < data.rows.length; rowIndex++) {
|
|
56598
|
-
const row = data.rows[rowIndex];
|
|
56599
|
-
if (!Array.isArray(row)) {
|
|
56600
|
-
console.warn(`[processRowsToMapping] Row ${rowIndex} não é array:`, row);
|
|
56601
|
-
continue;
|
|
56602
|
-
}
|
|
56603
|
-
for (const field of row) {
|
|
56604
|
-
if (field && typeof field === "object" && "code" in field && "name" in field) {
|
|
56605
|
-
const fieldObj = field;
|
|
56606
|
-
if (fieldObj.code && fieldObj.name) {
|
|
56607
|
-
console.log(`[processRowsToMapping] ✓ Mapeando: "${fieldObj.code}" -> "${fieldObj.name}"`);
|
|
56608
|
-
mapping[fieldObj.code] = fieldObj.name;
|
|
56609
|
-
}
|
|
56610
|
-
}
|
|
56611
|
-
}
|
|
56612
|
-
}
|
|
56613
|
-
console.log("[processRowsToMapping] Mapeamento final:", mapping);
|
|
56614
|
-
console.log("[processRowsToMapping] Total de campos mapeados:", Object.keys(mapping).length);
|
|
56615
|
-
return mapping;
|
|
56616
|
-
}
|
|
56617
|
-
function applyMappingToValues(mapping, values) {
|
|
56618
|
-
const finalData = {};
|
|
56619
|
-
console.log("[applyMappingToValues] Aplicando mapeamento...");
|
|
56620
|
-
console.log("[applyMappingToValues] Mapping keys:", Object.keys(mapping));
|
|
56621
|
-
console.log("[applyMappingToValues] Values keys:", Object.keys(values));
|
|
56622
|
-
for (const [code, value] of Object.entries(values)) {
|
|
56623
|
-
const name = mapping[code];
|
|
56624
|
-
if (name) {
|
|
56625
|
-
console.log(`[applyMappingToValues] ✓ "${code}" -> "${name}" = "${value}"`);
|
|
56626
|
-
finalData[name] = value;
|
|
56627
|
-
} else {
|
|
56628
|
-
console.log(`[applyMappingToValues] ✗ "${code}" não tem mapeamento (valor: "${value}")`);
|
|
56629
|
-
}
|
|
56630
|
-
}
|
|
56631
|
-
console.log("[applyMappingToValues] Final data:", finalData);
|
|
56632
|
-
return finalData;
|
|
56633
|
-
}
|
|
56634
|
-
async function fetchCampaignFieldsRaw(campaignModelId) {
|
|
56635
|
-
const url = `${API_BASE_URL}/api/campaign-fields/${campaignModelId}`;
|
|
56636
|
-
console.log("[fetchCampaignFieldsRaw] URL:", url);
|
|
56637
|
-
const response = await fetch(url, { method: "GET", headers: getAuthHeaders(), credentials: "omit" });
|
|
56638
|
-
if (!response.ok) {
|
|
56639
|
-
const error2 = await response.json().catch(() => ({ error: "Erro desconhecido" }));
|
|
56640
|
-
throw new Error(error2.error || `Falha ao buscar campos: ${response.status}`);
|
|
56641
|
-
}
|
|
56642
|
-
const json = await response.json();
|
|
56643
|
-
console.log("[fetchCampaignFieldsRaw] Resposta recebida:", JSON.stringify(json, null, 2).substring(0, 500));
|
|
56644
|
-
return json;
|
|
56645
|
-
}
|
|
56646
|
-
async function getContactValues(contactId) {
|
|
56647
|
-
const url = `${API_BASE_URL}/api/campaign-contact/${contactId}`;
|
|
56648
|
-
const response = await fetch(url, { method: "GET", headers: getAuthHeaders(), credentials: "omit" });
|
|
56649
|
-
if (!response.ok) {
|
|
56650
|
-
const error2 = await response.json().catch(() => ({ error: "Erro desconhecido" }));
|
|
56651
|
-
throw new Error(error2.error || `Falha ao buscar valores: ${response.status}`);
|
|
56652
|
-
}
|
|
56653
|
-
return response.json();
|
|
56654
|
-
}
|
|
56655
56888
|
function findValue(finalData, candidates) {
|
|
56656
|
-
|
|
56657
|
-
const lowerCandidates = candidates.map((item) => item.toLowerCase());
|
|
56658
|
-
for (const [key, value] of entries) {
|
|
56659
|
-
if (lowerCandidates.includes(key.toLowerCase())) {
|
|
56660
|
-
return value;
|
|
56661
|
-
}
|
|
56662
|
-
}
|
|
56663
|
-
return void 0;
|
|
56889
|
+
return findFormValue({ values: finalData }, candidates);
|
|
56664
56890
|
}
|
|
56665
56891
|
function MobileDialer(props) {
|
|
56666
56892
|
useEffect(() => {
|
|
@@ -56673,10 +56899,12 @@ function MobileDialer(props) {
|
|
|
56673
56899
|
document.head.appendChild(link);
|
|
56674
56900
|
}
|
|
56675
56901
|
}, []);
|
|
56902
|
+
const inputProfile = useInputProfile();
|
|
56903
|
+
const density = resolveDensity(props.density, inputProfile);
|
|
56676
56904
|
if (!props.isAuthenticated) {
|
|
56677
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(MobileDialerLogin, { ...props });
|
|
56905
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(MobileDialerLogin, { ...props, density });
|
|
56678
56906
|
}
|
|
56679
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(AuthenticatedMobileDialer, { ...props });
|
|
56907
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(AuthenticatedMobileDialer, { ...props, density });
|
|
56680
56908
|
}
|
|
56681
56909
|
function MobileDialerLogin({
|
|
56682
56910
|
username,
|
|
@@ -56685,7 +56913,8 @@ function MobileDialerLogin({
|
|
|
56685
56913
|
sessionError,
|
|
56686
56914
|
sessionStatus,
|
|
56687
56915
|
loginConfirmation,
|
|
56688
|
-
onCancelLoginConfirmation
|
|
56916
|
+
onCancelLoginConfirmation,
|
|
56917
|
+
density
|
|
56689
56918
|
}) {
|
|
56690
56919
|
const [loginInput, setLoginInput] = useState(username ?? "");
|
|
56691
56920
|
const [loginError, setLoginError] = useState(null);
|
|
@@ -56712,7 +56941,7 @@ function MobileDialerLogin({
|
|
|
56712
56941
|
const handleLogin = useCallback(() => submitLogin(loginInput), [submitLogin, loginInput]);
|
|
56713
56942
|
const showConfirmation = Boolean(loginConfirmation) && !isLoadingSession;
|
|
56714
56943
|
const loadingUser = ((loginConfirmation == null ? void 0 : loginConfirmation.username) || loginInput || username || "").trim();
|
|
56715
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "phone-container", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "screen dialer-screen login-screen active", id: "dialerScreen", children: [
|
|
56944
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "phone-container", "data-density": density === "compact" ? "compact" : "comfortable", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "screen dialer-screen login-screen active", id: "dialerScreen", children: [
|
|
56716
56945
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "dialer-header", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "status-container", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { type: "button", className: `status-badge ${isLoadingSession ? "connecting" : "available"}`, children: [
|
|
56717
56946
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "status-dot" }),
|
|
56718
56947
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "status-text", children: isLoadingSession ? "Conectando" : "Login" })
|
|
@@ -56826,9 +57055,10 @@ Gostaríamos de fazer um *diagnóstico gratuito* para te apresentar os valores r
|
|
|
56826
57055
|
}
|
|
56827
57056
|
function AuthenticatedMobileDialer({
|
|
56828
57057
|
username,
|
|
56829
|
-
showClientInfoModal = false
|
|
57058
|
+
showClientInfoModal = false,
|
|
57059
|
+
density
|
|
56830
57060
|
}) {
|
|
56831
|
-
var _a2, _b, _c;
|
|
57061
|
+
var _a2, _b, _c, _d;
|
|
56832
57062
|
const { skipManualQualification } = useDialerConfig();
|
|
56833
57063
|
const [dialValue, setDialValue] = useState("");
|
|
56834
57064
|
const [activeScreen, setActiveScreen] = useState("dialer");
|
|
@@ -56850,10 +57080,14 @@ function AuthenticatedMobileDialer({
|
|
|
56850
57080
|
isLoading: false,
|
|
56851
57081
|
error: null
|
|
56852
57082
|
});
|
|
56853
|
-
const [fetchedContactId, setFetchedContactId] = useState(null);
|
|
56854
57083
|
const [callHistory, setCallHistory] = useState([]);
|
|
56855
57084
|
const [isLoadingHistory, setIsLoadingHistory] = useState(false);
|
|
56856
57085
|
const [historyError, setHistoryError] = useState(null);
|
|
57086
|
+
const [historyQuery, setHistoryQuery] = useState("");
|
|
57087
|
+
const [historySearchResults, setHistorySearchResults] = useState(null);
|
|
57088
|
+
const [isSearchingHistory, setIsSearchingHistory] = useState(false);
|
|
57089
|
+
const historyTextPoolRef = useRef(null);
|
|
57090
|
+
const historySearchSeqRef = useRef(0);
|
|
56857
57091
|
const [isSpeakerOn, setIsSpeakerOn] = useState(false);
|
|
56858
57092
|
const [audioOutputDevices, setAudioOutputDevices] = useState([]);
|
|
56859
57093
|
const [speakerDeviceId, setSpeakerDeviceId] = useState(null);
|
|
@@ -57030,90 +57264,54 @@ function AuthenticatedMobileDialer({
|
|
|
57030
57264
|
});
|
|
57031
57265
|
}
|
|
57032
57266
|
}, [callInfo]);
|
|
57033
|
-
const
|
|
57034
|
-
|
|
57267
|
+
const campaignFormRequest = useMemo(
|
|
57268
|
+
() => {
|
|
57269
|
+
var _a3;
|
|
57270
|
+
return (callInfo == null ? void 0 : callInfo.type) === "campaign" ? campaignFormRequestFromCallInfo(callInfo.info, ((_a3 = currentCall == null ? void 0 : currentCall.data) == null ? void 0 : _a3.campaignContactPhoneId) ?? null) : null;
|
|
57271
|
+
},
|
|
57272
|
+
[callInfo, currentCall]
|
|
57273
|
+
);
|
|
57274
|
+
const campaignFormKey = campaignFormRequest ? campaignFormCacheKey(campaignFormRequest) : null;
|
|
57275
|
+
const campaignFormRequestRef = useRef(campaignFormRequest);
|
|
57276
|
+
campaignFormRequestRef.current = campaignFormRequest;
|
|
57035
57277
|
useEffect(() => {
|
|
57036
|
-
|
|
57278
|
+
const request = campaignFormRequestRef.current;
|
|
57279
|
+
if (!request || !campaignFormKey) {
|
|
57037
57280
|
setContactData({ finalData: {}, isLoading: false, error: null });
|
|
57038
|
-
setFetchedContactId(null);
|
|
57039
|
-
return;
|
|
57040
|
-
}
|
|
57041
|
-
if (fetchedContactId === campaignContactId) {
|
|
57042
57281
|
return;
|
|
57043
57282
|
}
|
|
57044
57283
|
let cancelled = false;
|
|
57045
|
-
|
|
57046
|
-
|
|
57047
|
-
|
|
57048
|
-
|
|
57049
|
-
|
|
57050
|
-
|
|
57051
|
-
|
|
57052
|
-
|
|
57053
|
-
hasToken: !!tokenAtFetch,
|
|
57054
|
-
localStorageLength: typeof window !== "undefined" ? localStorage.length : 0
|
|
57284
|
+
let refreshTimer = null;
|
|
57285
|
+
setContactData({ finalData: {}, isLoading: true, error: null });
|
|
57286
|
+
addLog("debug", "FetchContact", "Buscando formulário do contato", { contactId: request.id, source: request.source });
|
|
57287
|
+
const apply2 = (form) => {
|
|
57288
|
+
setContactData({ finalData: form.values, isLoading: false, error: null });
|
|
57289
|
+
addLog("info", "FetchContact", `✅ Formulário: ${form.fields.length} campos (${form.valuesSource}, layout ${form.layoutSource})`, {
|
|
57290
|
+
contactId: request.id,
|
|
57291
|
+
partial: form.partial === true
|
|
57055
57292
|
});
|
|
57056
|
-
console.log("[MobileDialer] ========================================");
|
|
57057
|
-
setContactData({ finalData: {}, isLoading: true, error: null });
|
|
57058
|
-
try {
|
|
57059
|
-
const customer = campaignContact == null ? void 0 : campaignContact.customer;
|
|
57060
|
-
let fieldsRawData;
|
|
57061
|
-
let contactValues = {};
|
|
57062
|
-
if ((customer == null ? void 0 : customer.id) && (customer == null ? void 0 : customer.formId)) {
|
|
57063
|
-
console.log("[MobileDialer] 📋 Modo CLIENTE detectado:", customer);
|
|
57064
|
-
const customerFieldsUrl = `${API_BASE_URL}/api/campaign-contact/0?source=customer&formId=${encodeURIComponent(String(customer.formId))}`;
|
|
57065
|
-
const customerValuesUrl = `${API_BASE_URL}/api/campaign-fields/0?source=customer&customerId=${encodeURIComponent(String(customer.id))}`;
|
|
57066
|
-
const [fieldsResponse, valuesResponse] = await Promise.all([
|
|
57067
|
-
fetch(customerFieldsUrl, { method: "GET", headers: getAuthHeaders(), credentials: "omit" }),
|
|
57068
|
-
fetch(customerValuesUrl, { method: "GET", headers: getAuthHeaders(), credentials: "omit" })
|
|
57069
|
-
]);
|
|
57070
|
-
if (!fieldsResponse.ok) throw new Error(`Erro ao buscar campos cliente: ${fieldsResponse.status}`);
|
|
57071
|
-
if (!valuesResponse.ok) throw new Error(`Erro ao buscar valores cliente: ${valuesResponse.status}`);
|
|
57072
|
-
fieldsRawData = await fieldsResponse.json();
|
|
57073
|
-
contactValues = await valuesResponse.json();
|
|
57074
|
-
} else {
|
|
57075
|
-
console.log("[MobileDialer] 📋 Modo CAMPANHA detectado");
|
|
57076
|
-
const config = await getCampaignConfig(campaignContactId);
|
|
57077
|
-
console.log("[MobileDialer] Config recebida:", config);
|
|
57078
|
-
if (!config.campaignModelId) {
|
|
57079
|
-
throw new Error("campaignModelId não encontrado");
|
|
57080
|
-
}
|
|
57081
|
-
const [rawFields, rawValues] = await Promise.all([
|
|
57082
|
-
fetchCampaignFieldsRaw(config.campaignModelId),
|
|
57083
|
-
getContactValues(campaignContactId)
|
|
57084
|
-
]);
|
|
57085
|
-
fieldsRawData = rawFields;
|
|
57086
|
-
contactValues = rawValues;
|
|
57087
|
-
}
|
|
57088
|
-
console.log("[MobileDialer] ======= DADOS BRUTOS =======");
|
|
57089
|
-
console.log("[MobileDialer] fieldsRawData:", JSON.stringify(fieldsRawData, null, 2).substring(0, 1e3));
|
|
57090
|
-
console.log("[MobileDialer] contactValues:", JSON.stringify(contactValues, null, 2));
|
|
57091
|
-
const codeToNameMap = processRowsToMapping(fieldsRawData);
|
|
57092
|
-
console.log("[MobileDialer] ======= MAPEAMENTO PROCESSADO =======");
|
|
57093
|
-
console.log("[MobileDialer] codeToNameMap:", JSON.stringify(codeToNameMap, null, 2));
|
|
57094
|
-
const finalData = applyMappingToValues(codeToNameMap, contactValues);
|
|
57095
|
-
console.log("[MobileDialer] ======= RESULTADO FINAL =======");
|
|
57096
|
-
console.log("[MobileDialer] finalData:", JSON.stringify(finalData, null, 2));
|
|
57097
|
-
console.log("[MobileDialer] finalData keys:", Object.keys(finalData));
|
|
57098
|
-
console.log("[MobileDialer] ================================");
|
|
57099
|
-
if (!cancelled) {
|
|
57100
|
-
setContactData({ finalData, isLoading: false, error: null });
|
|
57101
|
-
setFetchedContactId(campaignContactId);
|
|
57102
|
-
}
|
|
57103
|
-
} catch (error2) {
|
|
57104
|
-
if (!cancelled) {
|
|
57105
|
-
console.error("[MobileDialer] Erro ao buscar dados:", error2);
|
|
57106
|
-
const errorMessage = error2 instanceof Error ? error2.message : "Erro ao buscar dados";
|
|
57107
|
-
setContactData({ finalData: {}, isLoading: false, error: errorMessage });
|
|
57108
|
-
setFetchedContactId(campaignContactId);
|
|
57109
|
-
}
|
|
57110
|
-
}
|
|
57111
57293
|
};
|
|
57112
|
-
|
|
57294
|
+
fetchCampaignForm(request).then((form) => {
|
|
57295
|
+
if (cancelled) return;
|
|
57296
|
+
apply2(form);
|
|
57297
|
+
if (form.partial) {
|
|
57298
|
+
refreshTimer = setTimeout(() => {
|
|
57299
|
+
if (cancelled) return;
|
|
57300
|
+
fetchCampaignForm(request, { force: true }).then((refreshed) => {
|
|
57301
|
+
if (!cancelled) apply2(refreshed);
|
|
57302
|
+
}).catch(() => void 0);
|
|
57303
|
+
}, 3e3);
|
|
57304
|
+
}
|
|
57305
|
+
}).catch((error2) => {
|
|
57306
|
+
if (cancelled) return;
|
|
57307
|
+
console.error("[MobileDialer] Erro ao buscar o formulário:", error2);
|
|
57308
|
+
setContactData({ finalData: {}, isLoading: false, error: error2 instanceof Error ? error2.message : "Erro ao buscar dados" });
|
|
57309
|
+
});
|
|
57113
57310
|
return () => {
|
|
57114
57311
|
cancelled = true;
|
|
57312
|
+
if (refreshTimer) clearTimeout(refreshTimer);
|
|
57115
57313
|
};
|
|
57116
|
-
}, [
|
|
57314
|
+
}, [campaignFormKey]);
|
|
57117
57315
|
const callStateStr = callState;
|
|
57118
57316
|
const isError = callStateStr === "startup.error" || callStateStr === "offline";
|
|
57119
57317
|
const isIdle = !callStateStr || callStateStr === "starting" || callStateStr === "idle" || callStateStr === "manualCallSetup" || callStateStr === "onBreak";
|
|
@@ -57165,6 +57363,18 @@ function AuthenticatedMobileDialer({
|
|
|
57165
57363
|
setPauseDurationSeconds(0);
|
|
57166
57364
|
}
|
|
57167
57365
|
}, [isOnBreak, currentBreakName]);
|
|
57366
|
+
useEffect(() => {
|
|
57367
|
+
const onClickToCall = (event) => {
|
|
57368
|
+
const task = event.detail;
|
|
57369
|
+
if (!(task == null ? void 0 : task.phone)) return;
|
|
57370
|
+
setCallError(null);
|
|
57371
|
+
setDialValue(nationalDigitsFromE164(task.phone).slice(0, 32));
|
|
57372
|
+
setActiveScreen("dialer");
|
|
57373
|
+
addLog("event", "Call", `🖱️ Click-to-call recebido: ${task.phoneDisplay}`, { taskId: task.id, source: task.source });
|
|
57374
|
+
};
|
|
57375
|
+
window.addEventListener(CLICK_TO_CALL_EVENT, onClickToCall);
|
|
57376
|
+
return () => window.removeEventListener(CLICK_TO_CALL_EVENT, onClickToCall);
|
|
57377
|
+
}, []);
|
|
57168
57378
|
useEffect(() => {
|
|
57169
57379
|
console.log("[MobileDialer] Screen control effect - callState:", callState, "isInCall:", isInCall, "isConnecting:", isConnecting, "isAfterCall:", isAfterCall);
|
|
57170
57380
|
if (isInCall || isConnecting) {
|
|
@@ -57356,16 +57566,17 @@ function AuthenticatedMobileDialer({
|
|
|
57356
57566
|
haptic.notificationError();
|
|
57357
57567
|
}
|
|
57358
57568
|
}, [haptic, speakerSupported, speakerDeviceId, defaultDeviceId, isSpeakerOn, operator]);
|
|
57359
|
-
const
|
|
57360
|
-
|
|
57361
|
-
|
|
57362
|
-
|
|
57363
|
-
|
|
57364
|
-
|
|
57365
|
-
|
|
57366
|
-
|
|
57367
|
-
|
|
57368
|
-
|
|
57569
|
+
const requestHistory = useCallback(
|
|
57570
|
+
async ({ phone, limit }) => {
|
|
57571
|
+
const agentId = userData == null ? void 0 : userData.id;
|
|
57572
|
+
if (!agentId) {
|
|
57573
|
+
throw new Error("Aguardando ID do usuário");
|
|
57574
|
+
}
|
|
57575
|
+
const params = new URLSearchParams({ agent_id: String(agentId), limit: String(limit) });
|
|
57576
|
+
if (phone) {
|
|
57577
|
+
params.set("phone", phone);
|
|
57578
|
+
}
|
|
57579
|
+
const response = await fetch(`${API_BASE_URL}/api/call-history?${params.toString()}`, {
|
|
57369
57580
|
method: "GET",
|
|
57370
57581
|
headers: getAuthHeaders(),
|
|
57371
57582
|
credentials: "omit"
|
|
@@ -57376,8 +57587,22 @@ function AuthenticatedMobileDialer({
|
|
|
57376
57587
|
);
|
|
57377
57588
|
}
|
|
57378
57589
|
const data = await response.json();
|
|
57379
|
-
|
|
57380
|
-
|
|
57590
|
+
return data.items || [];
|
|
57591
|
+
},
|
|
57592
|
+
[userData == null ? void 0 : userData.id]
|
|
57593
|
+
);
|
|
57594
|
+
const fetchCallHistory = useCallback(async () => {
|
|
57595
|
+
if (!(userData == null ? void 0 : userData.id)) {
|
|
57596
|
+
console.log("[MobileDialer] Aguardando ID do usuário para buscar histórico");
|
|
57597
|
+
return;
|
|
57598
|
+
}
|
|
57599
|
+
setIsLoadingHistory(true);
|
|
57600
|
+
setHistoryError(null);
|
|
57601
|
+
historyTextPoolRef.current = null;
|
|
57602
|
+
try {
|
|
57603
|
+
const items = await requestHistory({ limit: 50 });
|
|
57604
|
+
console.log("[MobileDialer] Histórico recebido:", items.length, "registros");
|
|
57605
|
+
setCallHistory(items);
|
|
57381
57606
|
} catch (error2) {
|
|
57382
57607
|
console.error("[MobileDialer] Erro ao buscar histórico:", error2);
|
|
57383
57608
|
setHistoryError(error2 instanceof Error && error2.message.startsWith("Sessão") ? error2.message : "Erro ao carregar histórico");
|
|
@@ -57385,7 +57610,54 @@ function AuthenticatedMobileDialer({
|
|
|
57385
57610
|
} finally {
|
|
57386
57611
|
setIsLoadingHistory(false);
|
|
57387
57612
|
}
|
|
57388
|
-
}, [userData == null ? void 0 : userData.id]);
|
|
57613
|
+
}, [requestHistory, userData == null ? void 0 : userData.id]);
|
|
57614
|
+
const handleHistoryQueryChange = useCallback(
|
|
57615
|
+
async (query) => {
|
|
57616
|
+
setHistoryQuery(query);
|
|
57617
|
+
const parsed = classifyHistoryQuery(query);
|
|
57618
|
+
const seq = ++historySearchSeqRef.current;
|
|
57619
|
+
if (parsed.kind === "empty") {
|
|
57620
|
+
setHistorySearchResults(null);
|
|
57621
|
+
setIsSearchingHistory(false);
|
|
57622
|
+
return;
|
|
57623
|
+
}
|
|
57624
|
+
setIsSearchingHistory(true);
|
|
57625
|
+
try {
|
|
57626
|
+
let results;
|
|
57627
|
+
if (parsed.kind === "phone") {
|
|
57628
|
+
results = await requestHistory({ phone: parsed.digits, limit: 100 });
|
|
57629
|
+
} else {
|
|
57630
|
+
if (!historyTextPoolRef.current) {
|
|
57631
|
+
historyTextPoolRef.current = await requestHistory({ limit: 200 });
|
|
57632
|
+
}
|
|
57633
|
+
results = historyTextPoolRef.current;
|
|
57634
|
+
}
|
|
57635
|
+
if (seq === historySearchSeqRef.current) {
|
|
57636
|
+
setHistorySearchResults(results);
|
|
57637
|
+
}
|
|
57638
|
+
} catch (error2) {
|
|
57639
|
+
console.error("[MobileDialer] Erro na busca do histórico:", error2);
|
|
57640
|
+
if (seq === historySearchSeqRef.current) {
|
|
57641
|
+
setHistorySearchResults(null);
|
|
57642
|
+
}
|
|
57643
|
+
} finally {
|
|
57644
|
+
if (seq === historySearchSeqRef.current) {
|
|
57645
|
+
setIsSearchingHistory(false);
|
|
57646
|
+
}
|
|
57647
|
+
}
|
|
57648
|
+
},
|
|
57649
|
+
[requestHistory]
|
|
57650
|
+
);
|
|
57651
|
+
const historySearchHint = useMemo(() => {
|
|
57652
|
+
const parsed = classifyHistoryQuery(historyQuery);
|
|
57653
|
+
if (parsed.kind === "phone") {
|
|
57654
|
+
return "Busca por número em todo o histórico";
|
|
57655
|
+
}
|
|
57656
|
+
if (parsed.kind === "text") {
|
|
57657
|
+
return historySearchResults ? "Busca por texto nas últimas 200 chamadas" : "Busca por texto nas chamadas carregadas";
|
|
57658
|
+
}
|
|
57659
|
+
return null;
|
|
57660
|
+
}, [historyQuery, historySearchResults]);
|
|
57389
57661
|
useEffect(() => {
|
|
57390
57662
|
if (activeScreen === "history") {
|
|
57391
57663
|
void fetchCallHistory();
|
|
@@ -57536,7 +57808,7 @@ function AuthenticatedMobileDialer({
|
|
|
57536
57808
|
addLog("info", "Debug", "🔒 Painel de debug fechado");
|
|
57537
57809
|
} });
|
|
57538
57810
|
}
|
|
57539
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "phone-container", children: [
|
|
57811
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "phone-container", "data-density": density === "compact" ? "compact" : "comfortable", children: [
|
|
57540
57812
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `screen dialer-screen ${activeScreen === "dialer" ? "active" : ""}`, id: "dialerScreen", children: [
|
|
57541
57813
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "dialer-header", children: [
|
|
57542
57814
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "status-container", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { className: `status-badge ${statusBadgeClass}`, id: "statusBadge", children: [
|
|
@@ -57699,10 +57971,14 @@ function AuthenticatedMobileDialer({
|
|
|
57699
57971
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `screen call-history-screen ${activeScreen === "history" ? "active" : ""}`, id: "callHistoryScreen", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
57700
57972
|
CallHistoryList,
|
|
57701
57973
|
{
|
|
57702
|
-
items: callHistory,
|
|
57974
|
+
items: historySearchResults ?? callHistory,
|
|
57703
57975
|
isLoading: isLoadingHistory,
|
|
57704
57976
|
error: historyError,
|
|
57705
57977
|
onRefresh: fetchCallHistory,
|
|
57978
|
+
query: historyQuery,
|
|
57979
|
+
onQueryChange: handleHistoryQueryChange,
|
|
57980
|
+
isSearching: isSearchingHistory,
|
|
57981
|
+
searchHint: historySearchHint,
|
|
57706
57982
|
onCall: (call) => {
|
|
57707
57983
|
haptic.impactLight();
|
|
57708
57984
|
setDialValue(historyPhoneDigits(call));
|
|
@@ -57820,6 +58096,7 @@ function AuthenticatedMobileDialer({
|
|
|
57820
58096
|
{
|
|
57821
58097
|
isOpen: isClientInfoModalOpen,
|
|
57822
58098
|
campaignCallInfo,
|
|
58099
|
+
campaignContactPhoneId: ((_d = currentCall == null ? void 0 : currentCall.data) == null ? void 0 : _d.campaignContactPhoneId) ?? null,
|
|
57823
58100
|
callDuration: callDurationSeconds,
|
|
57824
58101
|
isCallActive: isInCall || isConnecting,
|
|
57825
58102
|
onClose: () => setIsClientInfoModalOpen(false)
|
|
@@ -58096,9 +58373,11 @@ function AuthenticatedMiniDialer({
|
|
|
58096
58373
|
isLoadingSession,
|
|
58097
58374
|
sessionError
|
|
58098
58375
|
}) {
|
|
58376
|
+
var _a2;
|
|
58099
58377
|
const { skipManualQualification } = useDialerConfig();
|
|
58100
58378
|
const operatorState = clientSdkReactExports.useCallOperatorState();
|
|
58101
58379
|
const currentCallInfo = clientSdkReactExports.useCallOperatorCurrentCallInfo();
|
|
58380
|
+
const currentCall = clientSdkReactExports.useCallOperatorCurrentCall();
|
|
58102
58381
|
const rawSuccessQualifications = clientSdkReactExports.useCallOperatorSuccessQualifications();
|
|
58103
58382
|
const rawDiscardQualifications = clientSdkReactExports.useCallOperatorDiscardQualifications();
|
|
58104
58383
|
const successQualifications = useMemo(() => rawSuccessQualifications ?? [], [rawSuccessQualifications]);
|
|
@@ -58354,6 +58633,7 @@ function AuthenticatedMiniDialer({
|
|
|
58354
58633
|
{
|
|
58355
58634
|
isOpen: isClientInfoModalOpen,
|
|
58356
58635
|
campaignCallInfo,
|
|
58636
|
+
campaignContactPhoneId: ((_a2 = currentCall == null ? void 0 : currentCall.data) == null ? void 0 : _a2.campaignContactPhoneId) ?? null,
|
|
58357
58637
|
callDuration: callDurationSeconds,
|
|
58358
58638
|
isCallActive: isInCall || isConnecting,
|
|
58359
58639
|
onClose: () => setIsClientInfoModalOpen(false)
|
|
@@ -58376,7 +58656,229 @@ function AuthenticatedMiniDialer({
|
|
|
58376
58656
|
)
|
|
58377
58657
|
] });
|
|
58378
58658
|
}
|
|
58379
|
-
const
|
|
58659
|
+
const DEFAULT_CLICK_TO_CALL_INTERVAL_MS = 4e3;
|
|
58660
|
+
const BUSY_INTERVAL_FACTOR = 3;
|
|
58661
|
+
const DISPATCH_COOLDOWN_MS = 6e3;
|
|
58662
|
+
const CALL_START_TIMEOUT_MS = 4e3;
|
|
58663
|
+
const CALL_START_CHECK_MS = 100;
|
|
58664
|
+
const MAX_BACKOFF_MS = 6e4;
|
|
58665
|
+
const NOT_CONFIGURED_INTERVAL_MS = 5 * 6e4;
|
|
58666
|
+
const NOT_CONFIGURED_CODES = /* @__PURE__ */ new Set(["STORE_NOT_CONFIGURED", "SERVER_NOT_CONFIGURED"]);
|
|
58667
|
+
const ACK_ATTEMPTS = 3;
|
|
58668
|
+
const ACK_RETRY_DELAY_MS = 1500;
|
|
58669
|
+
const CALL_STARTED_STATES = /* @__PURE__ */ new Set(["manualCallSetup", "manualCallRinging", "callInProgress", "afterCall"]);
|
|
58670
|
+
function buildHeaders(sessionToken) {
|
|
58671
|
+
if (sessionToken) {
|
|
58672
|
+
return { "Content-Type": "application/json", "x-session-token": sessionToken, Authorization: `Bearer ${sessionToken}` };
|
|
58673
|
+
}
|
|
58674
|
+
return getAuthHeaders();
|
|
58675
|
+
}
|
|
58676
|
+
const delay = (ms2) => new Promise((resolve) => setTimeout(resolve, ms2));
|
|
58677
|
+
function ClickToCallAgent({ enabled = true, pollIntervalMs, sessionToken, onTask }) {
|
|
58678
|
+
const operatorState = clientSdkReactExports.useCallOperatorState();
|
|
58679
|
+
const { makeManualCall } = clientSdkReactExports.useCallOperatorControls();
|
|
58680
|
+
const stateRef = useRef(operatorState == null ? void 0 : operatorState.state);
|
|
58681
|
+
stateRef.current = operatorState == null ? void 0 : operatorState.state;
|
|
58682
|
+
const makeManualCallRef = useRef(makeManualCall);
|
|
58683
|
+
makeManualCallRef.current = makeManualCall;
|
|
58684
|
+
const onTaskRef = useRef(onTask);
|
|
58685
|
+
onTaskRef.current = onTask;
|
|
58686
|
+
const tickerRef = useRef(null);
|
|
58687
|
+
const applyIntervalRef = useRef(null);
|
|
58688
|
+
useEffect(() => {
|
|
58689
|
+
var _a2;
|
|
58690
|
+
(_a2 = applyIntervalRef.current) == null ? void 0 : _a2.call(applyIntervalRef);
|
|
58691
|
+
}, [operatorState == null ? void 0 : operatorState.state]);
|
|
58692
|
+
useEffect(() => {
|
|
58693
|
+
if (!enabled) {
|
|
58694
|
+
return void 0;
|
|
58695
|
+
}
|
|
58696
|
+
let disposed = false;
|
|
58697
|
+
let inFlight = false;
|
|
58698
|
+
let cooldownUntil = 0;
|
|
58699
|
+
let failureStreak = 0;
|
|
58700
|
+
let mode2 = "normal";
|
|
58701
|
+
let notConfiguredWarned = false;
|
|
58702
|
+
let presenceTtlMs = 45e3;
|
|
58703
|
+
let baseInterval = Math.max(1e3, pollIntervalMs ?? DEFAULT_CLICK_TO_CALL_INTERVAL_MS);
|
|
58704
|
+
const config = { apiBaseUrl: API_BASE_URL, headers: buildHeaders(sessionToken) };
|
|
58705
|
+
const computeInterval = () => {
|
|
58706
|
+
if (mode2 === "notConfigured") {
|
|
58707
|
+
return NOT_CONFIGURED_INTERVAL_MS;
|
|
58708
|
+
}
|
|
58709
|
+
const ceiling = Math.max(1e3, Math.floor(presenceTtlMs / 2));
|
|
58710
|
+
const base = Math.min(baseInterval, ceiling);
|
|
58711
|
+
if (mode2 === "backoff") {
|
|
58712
|
+
return Math.min(base * 2 ** failureStreak, MAX_BACKOFF_MS);
|
|
58713
|
+
}
|
|
58714
|
+
const busy = Math.min(base * BUSY_INTERVAL_FACTOR, ceiling);
|
|
58715
|
+
return canDispatchTo(presenceFromOperatorState(stateRef.current)) ? base : busy;
|
|
58716
|
+
};
|
|
58717
|
+
const applyInterval = () => {
|
|
58718
|
+
var _a2;
|
|
58719
|
+
return (_a2 = tickerRef.current) == null ? void 0 : _a2.setInterval(computeInterval());
|
|
58720
|
+
};
|
|
58721
|
+
applyIntervalRef.current = applyInterval;
|
|
58722
|
+
const ack = async (options) => {
|
|
58723
|
+
for (let attempt = 0; attempt < ACK_ATTEMPTS; attempt++) {
|
|
58724
|
+
try {
|
|
58725
|
+
const result2 = await ackClickToCall({ ...config, ...options });
|
|
58726
|
+
if (result2.ok) {
|
|
58727
|
+
return true;
|
|
58728
|
+
}
|
|
58729
|
+
const retryable = result2.status >= 500 || result2.status === 408 || result2.status === 429;
|
|
58730
|
+
if (!retryable) {
|
|
58731
|
+
console.warn("[ClickToCall] confirmação recusada pelo servidor:", result2.status, result2.code ?? "", "(tarefa", options.taskId, ")");
|
|
58732
|
+
return false;
|
|
58733
|
+
}
|
|
58734
|
+
} catch (error2) {
|
|
58735
|
+
console.warn("[ClickToCall] confirmação falhou (tentativa", attempt + 1, "):", error2 instanceof Error ? error2.message : error2);
|
|
58736
|
+
}
|
|
58737
|
+
if (disposed || attempt === ACK_ATTEMPTS - 1) {
|
|
58738
|
+
break;
|
|
58739
|
+
}
|
|
58740
|
+
await delay(ACK_RETRY_DELAY_MS * (attempt + 1));
|
|
58741
|
+
}
|
|
58742
|
+
console.error("[ClickToCall] não foi possível confirmar a tarefa", options.taskId, "; o servidor a marcará como não confirmada");
|
|
58743
|
+
return false;
|
|
58744
|
+
};
|
|
58745
|
+
const waitForCallStart = () => new Promise((resolve) => {
|
|
58746
|
+
const deadline = Date.now() + CALL_START_TIMEOUT_MS;
|
|
58747
|
+
const check = () => {
|
|
58748
|
+
if (disposed) return resolve("disposed");
|
|
58749
|
+
const state = stateRef.current;
|
|
58750
|
+
if (state && CALL_STARTED_STATES.has(state)) return resolve("started");
|
|
58751
|
+
if (state === "manualCallFailed") return resolve("manual_failed");
|
|
58752
|
+
if (state === "callRinging" || presenceFromOperatorState(state) === "offline") return resolve("interrupted");
|
|
58753
|
+
if (Date.now() >= deadline) return resolve("not_started");
|
|
58754
|
+
setTimeout(check, CALL_START_CHECK_MS);
|
|
58755
|
+
};
|
|
58756
|
+
check();
|
|
58757
|
+
});
|
|
58758
|
+
const dispatch = async (task) => {
|
|
58759
|
+
var _a2;
|
|
58760
|
+
const state = stateRef.current;
|
|
58761
|
+
cooldownUntil = Date.now() + DISPATCH_COOLDOWN_MS;
|
|
58762
|
+
if (!canDispatchTo(presenceFromOperatorState(state))) {
|
|
58763
|
+
console.warn("[ClickToCall] tarefa", task.id, "recebida com operador ocupado (", state, "): devolvendo à fila");
|
|
58764
|
+
await ack({ taskId: task.id, status: "failed", error: `Operador indisponível (${state ?? "desconhecido"})`, retry: true });
|
|
58765
|
+
return;
|
|
58766
|
+
}
|
|
58767
|
+
console.log("[ClickToCall] 🖱️ ligação pedida pela API:", task.phoneDisplay, "(tarefa", task.id, ")");
|
|
58768
|
+
try {
|
|
58769
|
+
window.dispatchEvent(new CustomEvent(CLICK_TO_CALL_EVENT, { detail: task }));
|
|
58770
|
+
} catch (error2) {
|
|
58771
|
+
console.warn("[ClickToCall] falha ao notificar o discador:", error2);
|
|
58772
|
+
}
|
|
58773
|
+
try {
|
|
58774
|
+
(_a2 = onTaskRef.current) == null ? void 0 : _a2.call(onTaskRef, task);
|
|
58775
|
+
} catch (error2) {
|
|
58776
|
+
console.warn("[ClickToCall] onTask lançou erro:", error2);
|
|
58777
|
+
}
|
|
58778
|
+
try {
|
|
58779
|
+
makeManualCallRef.current(task.phone);
|
|
58780
|
+
} catch (error2) {
|
|
58781
|
+
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
58782
|
+
console.error("[ClickToCall] makeManualCall falhou:", message);
|
|
58783
|
+
await ack({ taskId: task.id, status: "failed", error: message, retry: false });
|
|
58784
|
+
return;
|
|
58785
|
+
}
|
|
58786
|
+
const outcome = await waitForCallStart();
|
|
58787
|
+
switch (outcome) {
|
|
58788
|
+
case "started":
|
|
58789
|
+
await ack({ taskId: task.id, status: "calling" });
|
|
58790
|
+
return;
|
|
58791
|
+
case "manual_failed":
|
|
58792
|
+
console.error("[ClickToCall] o SDK não conseguiu completar a chamada manual");
|
|
58793
|
+
await ack({ taskId: task.id, status: "failed", error: "Chamada manual falhou no SDK", retry: false });
|
|
58794
|
+
return;
|
|
58795
|
+
case "interrupted":
|
|
58796
|
+
console.warn("[ClickToCall] chamada manual não aconteceu (estado", stateRef.current, "): devolvendo à fila");
|
|
58797
|
+
await ack({ taskId: task.id, status: "failed", error: `Discador interrompido (${stateRef.current ?? "desconhecido"})`, retry: true });
|
|
58798
|
+
return;
|
|
58799
|
+
case "disposed":
|
|
58800
|
+
await ack({ taskId: task.id, status: "failed", error: "Discador encerrado durante a discagem", retry: true });
|
|
58801
|
+
return;
|
|
58802
|
+
default: {
|
|
58803
|
+
const message = `SDK não iniciou a chamada (estado continua ${stateRef.current ?? "desconhecido"})`;
|
|
58804
|
+
console.error("[ClickToCall]", message);
|
|
58805
|
+
await ack({ taskId: task.id, status: "failed", error: message, retry: false });
|
|
58806
|
+
}
|
|
58807
|
+
}
|
|
58808
|
+
};
|
|
58809
|
+
const tick = async () => {
|
|
58810
|
+
if (disposed || inFlight) {
|
|
58811
|
+
return;
|
|
58812
|
+
}
|
|
58813
|
+
inFlight = true;
|
|
58814
|
+
try {
|
|
58815
|
+
const state = stateRef.current;
|
|
58816
|
+
const claim = canDispatchTo(presenceFromOperatorState(state)) && Date.now() >= cooldownUntil;
|
|
58817
|
+
let result2;
|
|
58818
|
+
try {
|
|
58819
|
+
result2 = await pollClickToCall({ ...config, state, claim });
|
|
58820
|
+
} catch (error2) {
|
|
58821
|
+
result2 = { ok: false, status: 0, code: error2 instanceof Error && error2.name === "AbortError" ? "TIMEOUT" : "NETWORK" };
|
|
58822
|
+
}
|
|
58823
|
+
if (disposed) {
|
|
58824
|
+
if (result2.ok && result2.task) {
|
|
58825
|
+
await ack({ taskId: result2.task.id, status: "failed", error: "Discador encerrado antes de discar", retry: true });
|
|
58826
|
+
}
|
|
58827
|
+
return;
|
|
58828
|
+
}
|
|
58829
|
+
if (!result2.ok) {
|
|
58830
|
+
failureStreak += 1;
|
|
58831
|
+
const notConfigured = result2.code !== null && NOT_CONFIGURED_CODES.has(result2.code);
|
|
58832
|
+
mode2 = notConfigured ? "notConfigured" : "backoff";
|
|
58833
|
+
if (notConfigured) {
|
|
58834
|
+
if (!notConfiguredWarned) {
|
|
58835
|
+
notConfiguredWarned = true;
|
|
58836
|
+
console.warn("[ClickToCall] backend sem click-to-call configurado (", result2.code, "); nova tentativa em 5 min");
|
|
58837
|
+
}
|
|
58838
|
+
} else if (failureStreak === 1) {
|
|
58839
|
+
console.warn("[ClickToCall] polling falhou (HTTP", result2.status, result2.code ?? "", "); aplicando backoff");
|
|
58840
|
+
}
|
|
58841
|
+
applyInterval();
|
|
58842
|
+
return;
|
|
58843
|
+
}
|
|
58844
|
+
if (mode2 !== "normal") {
|
|
58845
|
+
mode2 = "normal";
|
|
58846
|
+
failureStreak = 0;
|
|
58847
|
+
}
|
|
58848
|
+
presenceTtlMs = result2.presenceTtlSeconds * 1e3;
|
|
58849
|
+
if (pollIntervalMs === void 0 && result2.pollIntervalMs > 0) {
|
|
58850
|
+
baseInterval = Math.max(1e3, result2.pollIntervalMs);
|
|
58851
|
+
}
|
|
58852
|
+
applyInterval();
|
|
58853
|
+
if (result2.task) {
|
|
58854
|
+
try {
|
|
58855
|
+
await dispatch(result2.task);
|
|
58856
|
+
} catch (error2) {
|
|
58857
|
+
console.error("[ClickToCall] erro ao tratar a tarefa", result2.task.id, ":", error2 instanceof Error ? error2.message : error2);
|
|
58858
|
+
}
|
|
58859
|
+
}
|
|
58860
|
+
} finally {
|
|
58861
|
+
inFlight = false;
|
|
58862
|
+
}
|
|
58863
|
+
};
|
|
58864
|
+
const ticker = createBackgroundTicker(() => void tick(), computeInterval());
|
|
58865
|
+
tickerRef.current = ticker;
|
|
58866
|
+
void tick();
|
|
58867
|
+
return () => {
|
|
58868
|
+
disposed = true;
|
|
58869
|
+
ticker.stop();
|
|
58870
|
+
if (tickerRef.current === ticker) {
|
|
58871
|
+
tickerRef.current = null;
|
|
58872
|
+
}
|
|
58873
|
+
if (applyIntervalRef.current === applyInterval) {
|
|
58874
|
+
applyIntervalRef.current = null;
|
|
58875
|
+
}
|
|
58876
|
+
reportClickToCallOffline(config);
|
|
58877
|
+
};
|
|
58878
|
+
}, [enabled, pollIntervalMs, sessionToken]);
|
|
58879
|
+
return null;
|
|
58880
|
+
}
|
|
58881
|
+
const WIDGET_VERSION = "2.3.0";
|
|
58380
58882
|
let currentSipWebSocket = null;
|
|
58381
58883
|
function sendSipUnregisterIfPossible(ws) {
|
|
58382
58884
|
if (ws.readyState !== WebSocket.OPEN) return;
|
|
@@ -58576,8 +59078,25 @@ function deriveOptionsFromElement(element) {
|
|
|
58576
59078
|
if (datasetAutoLogin !== void 0 && datasetAutoLogin !== null) {
|
|
58577
59079
|
result2.autoLogin = ["true", "1", "yes", ""].includes(datasetAutoLogin.trim().toLowerCase());
|
|
58578
59080
|
}
|
|
59081
|
+
const datasetDensity = parseDensity(element.getAttribute("data-callix-density") ?? element.dataset.callixDensity);
|
|
59082
|
+
if (datasetDensity) {
|
|
59083
|
+
result2.density = datasetDensity;
|
|
59084
|
+
}
|
|
59085
|
+
const datasetClickToCall = element.getAttribute("data-callix-click-to-call") ?? element.dataset.callixClickToCall;
|
|
59086
|
+
if (datasetClickToCall !== void 0 && datasetClickToCall !== null) {
|
|
59087
|
+
result2.clickToCall = !["false", "0", "no", "off"].includes(datasetClickToCall.trim().toLowerCase());
|
|
59088
|
+
}
|
|
58579
59089
|
return result2;
|
|
58580
59090
|
}
|
|
59091
|
+
function normalizeClickToCallOptions(value) {
|
|
59092
|
+
if (value === false) {
|
|
59093
|
+
return { enabled: false };
|
|
59094
|
+
}
|
|
59095
|
+
if (value === true || value === void 0 || value === null) {
|
|
59096
|
+
return { enabled: true };
|
|
59097
|
+
}
|
|
59098
|
+
return { ...value, enabled: value.enabled !== false };
|
|
59099
|
+
}
|
|
58581
59100
|
class CallixDialerWidget {
|
|
58582
59101
|
constructor(options) {
|
|
58583
59102
|
this.root = null;
|
|
@@ -58608,9 +59127,11 @@ class CallixDialerWidget {
|
|
|
58608
59127
|
if (this.options.autoLogin === void 0 && derived.autoLogin !== void 0) {
|
|
58609
59128
|
this.options.autoLogin = derived.autoLogin;
|
|
58610
59129
|
}
|
|
58611
|
-
if (this.options.
|
|
58612
|
-
this.
|
|
58613
|
-
|
|
59130
|
+
if (this.options.density === void 0 && derived.density !== void 0) {
|
|
59131
|
+
this.options.density = derived.density;
|
|
59132
|
+
}
|
|
59133
|
+
if (this.options.clickToCall === void 0 && derived.clickToCall !== void 0) {
|
|
59134
|
+
this.options.clickToCall = derived.clickToCall;
|
|
58614
59135
|
}
|
|
58615
59136
|
this.root = clientExports.createRoot(this.container);
|
|
58616
59137
|
this.root.render(
|
|
@@ -58954,6 +59475,7 @@ function DialerWrapper({ options, containerEl }) {
|
|
|
58954
59475
|
}, []);
|
|
58955
59476
|
const DialerComponent = options.mode === "inline" || uiVariant === "mobile" ? InlineDialer : FloatingDialer;
|
|
58956
59477
|
const dialerMode = options.mode;
|
|
59478
|
+
const clickToCall = normalizeClickToCallOptions(options.clickToCall);
|
|
58957
59479
|
if (isDisconnecting) {
|
|
58958
59480
|
return /* @__PURE__ */ jsxRuntimeExports.jsx(DialerConfigContext.Provider, { value: { skipManualQualification }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
58959
59481
|
DialerComponent,
|
|
@@ -58967,6 +59489,7 @@ function DialerWrapper({ options, containerEl }) {
|
|
|
58967
59489
|
sessionStatus: "Encerrando sessão anterior...",
|
|
58968
59490
|
variant: uiVariant,
|
|
58969
59491
|
portalTarget,
|
|
59492
|
+
density: options.density,
|
|
58970
59493
|
mode: dialerMode
|
|
58971
59494
|
}
|
|
58972
59495
|
) });
|
|
@@ -58986,6 +59509,7 @@ function DialerWrapper({ options, containerEl }) {
|
|
|
58986
59509
|
onCancelLoginConfirmation: handleCancelLoginConfirmation,
|
|
58987
59510
|
variant: uiVariant,
|
|
58988
59511
|
portalTarget,
|
|
59512
|
+
density: options.density,
|
|
58989
59513
|
mode: dialerMode
|
|
58990
59514
|
}
|
|
58991
59515
|
) });
|
|
@@ -58995,21 +59519,33 @@ function DialerWrapper({ options, containerEl }) {
|
|
|
58995
59519
|
{
|
|
58996
59520
|
domain: callixDomain,
|
|
58997
59521
|
userSessionToken: sessionToken,
|
|
58998
|
-
children: /* @__PURE__ */ jsxRuntimeExports.
|
|
58999
|
-
|
|
59000
|
-
|
|
59001
|
-
|
|
59002
|
-
|
|
59003
|
-
|
|
59004
|
-
|
|
59005
|
-
|
|
59006
|
-
|
|
59007
|
-
|
|
59008
|
-
|
|
59009
|
-
|
|
59010
|
-
|
|
59011
|
-
|
|
59012
|
-
|
|
59522
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsxs(SdkCleanupManager, { ref: cleanupRef, children: [
|
|
59523
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
59524
|
+
DialerComponent,
|
|
59525
|
+
{
|
|
59526
|
+
isAuthenticated,
|
|
59527
|
+
username,
|
|
59528
|
+
onLogin: handleLogin,
|
|
59529
|
+
onLogout: handleLogout,
|
|
59530
|
+
isLoadingSession: isLoading,
|
|
59531
|
+
sessionError: error2,
|
|
59532
|
+
sessionStatus: loginStatus,
|
|
59533
|
+
variant: uiVariant,
|
|
59534
|
+
portalTarget,
|
|
59535
|
+
density: options.density,
|
|
59536
|
+
mode: dialerMode
|
|
59537
|
+
}
|
|
59538
|
+
),
|
|
59539
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
59540
|
+
ClickToCallAgent,
|
|
59541
|
+
{
|
|
59542
|
+
enabled: clickToCall.enabled,
|
|
59543
|
+
pollIntervalMs: clickToCall.pollIntervalMs,
|
|
59544
|
+
sessionToken,
|
|
59545
|
+
onTask: clickToCall.onTask
|
|
59546
|
+
}
|
|
59547
|
+
)
|
|
59548
|
+
] })
|
|
59013
59549
|
},
|
|
59014
59550
|
providerKey
|
|
59015
59551
|
) });
|