@coventia/softphone 0.3.0 → 0.4.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/dist/{call-CaPDWVk3.d.cts → call-C6YpT6uR.d.cts} +64 -1
- package/dist/{call-CaPDWVk3.d.ts → call-C6YpT6uR.d.ts} +64 -1
- package/dist/chunk-5E5OEXS2.js +14 -0
- package/dist/chunk-5E5OEXS2.js.map +1 -0
- package/dist/element/index.d.ts +56 -0
- package/dist/element/index.js +1064 -488
- package/dist/element/index.js.map +1 -1
- package/dist/{engine-CU2rEo3g.d.cts → engine-CDdaSojx.d.cts} +1 -1
- package/dist/{engine-BgBsIcEa.d.ts → engine-DPft99Wj.d.ts} +1 -1
- package/dist/index.cjs +97 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -6
- package/dist/index.d.ts +16 -6
- package/dist/index.js +8 -2
- package/dist/index.js.map +1 -1
- package/dist/react/index.d.cts +2 -2
- package/dist/react/index.d.ts +2 -2
- package/dist/{softphone-dZMkW8V1.d.cts → softphone-CY5d2WWY.d.cts} +3 -1
- package/dist/{softphone-DEt0TtQw.d.ts → softphone-DXgmTyrX.d.ts} +3 -1
- package/dist/softphone.css +254 -23
- package/dist/{sources-M3GYMS6V.js → sources-ONYQW733.js} +76 -8
- package/dist/sources-ONYQW733.js.map +1 -0
- package/dist/testing/index.d.cts +2 -2
- package/dist/testing/index.d.ts +2 -2
- package/dist/ui/index.cjs +578 -18
- package/dist/ui/index.cjs.map +1 -1
- package/dist/ui/index.d.cts +2 -2
- package/dist/ui/index.d.ts +2 -2
- package/dist/ui/index.js +573 -18
- package/dist/ui/index.js.map +1 -1
- package/dist/zadarma/index.d.cts +2 -2
- package/dist/zadarma/index.d.ts +2 -2
- package/package.json +1 -1
- package/dist/sources-M3GYMS6V.js.map +0 -1
package/dist/ui/index.cjs
CHANGED
|
@@ -13540,6 +13540,36 @@ var PACKED = "AC247 AD376 AE971 AF93 AG1 AI1 AL355 AM374 AO244 AR54 AS1 AT43 AU6
|
|
|
13540
13540
|
var DIAL_CODES = new Map(
|
|
13541
13541
|
PACKED.split(" ").map((token) => [token.slice(0, 2), Number(token.slice(2))])
|
|
13542
13542
|
);
|
|
13543
|
+
var REGIONS_BY_CODE = (() => {
|
|
13544
|
+
const map = /* @__PURE__ */ new Map();
|
|
13545
|
+
for (const [region, code] of DIAL_CODES) map.set(code, [...map.get(code) ?? [], region]);
|
|
13546
|
+
return map;
|
|
13547
|
+
})();
|
|
13548
|
+
var MAIN_REGION = {
|
|
13549
|
+
1: "US",
|
|
13550
|
+
7: "RU",
|
|
13551
|
+
39: "IT",
|
|
13552
|
+
44: "GB",
|
|
13553
|
+
47: "NO",
|
|
13554
|
+
61: "AU",
|
|
13555
|
+
212: "MA",
|
|
13556
|
+
262: "RE",
|
|
13557
|
+
290: "SH",
|
|
13558
|
+
358: "FI",
|
|
13559
|
+
590: "GP",
|
|
13560
|
+
599: "CW"
|
|
13561
|
+
};
|
|
13562
|
+
function regionOfInternational(typed) {
|
|
13563
|
+
const text = String(typed ?? "").trim();
|
|
13564
|
+
if (!text.startsWith("+")) return null;
|
|
13565
|
+
const digits = text.slice(1).replace(/\D/g, "");
|
|
13566
|
+
for (let length = 1; length <= Math.min(3, digits.length); length++) {
|
|
13567
|
+
const code = Number(digits.slice(0, length));
|
|
13568
|
+
const regions = REGIONS_BY_CODE.get(code);
|
|
13569
|
+
if (regions) return MAIN_REGION[code] ?? regions[0] ?? null;
|
|
13570
|
+
}
|
|
13571
|
+
return null;
|
|
13572
|
+
}
|
|
13543
13573
|
var DEFAULT_COUNTRY = "ES";
|
|
13544
13574
|
var REGION_NAMES = (() => {
|
|
13545
13575
|
try {
|
|
@@ -13591,12 +13621,16 @@ function CountryMark({ code }) {
|
|
|
13591
13621
|
}
|
|
13592
13622
|
function CountryPicker({
|
|
13593
13623
|
value,
|
|
13594
|
-
onChange
|
|
13624
|
+
onChange,
|
|
13625
|
+
fromNumber = false
|
|
13595
13626
|
}) {
|
|
13596
13627
|
const [open, setOpen] = React.useState(false);
|
|
13597
13628
|
const [query, setQuery] = React.useState("");
|
|
13598
13629
|
const rootRef = React.useRef(null);
|
|
13599
13630
|
const inputRef = React.useRef(null);
|
|
13631
|
+
React.useEffect(() => {
|
|
13632
|
+
if (fromNumber) setOpen(false);
|
|
13633
|
+
}, [fromNumber]);
|
|
13600
13634
|
const results = React.useMemo(() => {
|
|
13601
13635
|
const q = query.trim().toLowerCase().replace(/^\+/, "");
|
|
13602
13636
|
if (!q) return COUNTRIES;
|
|
@@ -13625,6 +13659,12 @@ function CountryPicker({
|
|
|
13625
13659
|
else setQuery("");
|
|
13626
13660
|
}, [open]);
|
|
13627
13661
|
const dial = DIAL_CODES.get(value);
|
|
13662
|
+
if (fromNumber) {
|
|
13663
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "cv-cp", ref: rootRef, children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "cv-cp-chip", "data-from-number": true, title: "El prefijo viene del n\xFAmero marcado", part: "country-chip", children: [
|
|
13664
|
+
/* @__PURE__ */ jsxRuntime.jsx(CountryMark, { code: value || "+" }),
|
|
13665
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "cv-sr-only", children: dial ? `Prefijo del n\xFAmero marcado: ${countryName(value)} (+${dial})` : "Prefijo del n\xFAmero marcado" })
|
|
13666
|
+
] }) });
|
|
13667
|
+
}
|
|
13628
13668
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "cv-cp", ref: rootRef, children: [
|
|
13629
13669
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
13630
13670
|
"button",
|
|
@@ -14191,18 +14231,384 @@ function playRingback() {
|
|
|
14191
14231
|
}
|
|
14192
14232
|
};
|
|
14193
14233
|
}
|
|
14234
|
+
|
|
14235
|
+
// src/core/outbound-numbers.ts
|
|
14236
|
+
function isOutboundNumberRefused(value) {
|
|
14237
|
+
const refusal = value?.refusal;
|
|
14238
|
+
return value instanceof Error && !!refusal && (refusal.reason === "platform" || refusal.reason === "user") && typeof refusal.retryAfterSeconds === "number";
|
|
14239
|
+
}
|
|
14240
|
+
var stores = /* @__PURE__ */ new WeakMap();
|
|
14241
|
+
function outboundNumberStore(softphone) {
|
|
14242
|
+
const source = softphone.sources?.outboundNumbers;
|
|
14243
|
+
if (!source) return null;
|
|
14244
|
+
let store = stores.get(softphone);
|
|
14245
|
+
if (!store) {
|
|
14246
|
+
store = createOutboundNumberStore(source);
|
|
14247
|
+
stores.set(softphone, store);
|
|
14248
|
+
}
|
|
14249
|
+
return store;
|
|
14250
|
+
}
|
|
14251
|
+
function createOutboundNumberStore(source) {
|
|
14252
|
+
let settings = null;
|
|
14253
|
+
let inFlight = null;
|
|
14254
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
14255
|
+
const apply = (next) => {
|
|
14256
|
+
settings = next;
|
|
14257
|
+
for (const l of listeners) l();
|
|
14258
|
+
};
|
|
14259
|
+
return {
|
|
14260
|
+
getSettings: () => settings,
|
|
14261
|
+
refresh() {
|
|
14262
|
+
inFlight ??= (async () => {
|
|
14263
|
+
if (!settings && source.cached) {
|
|
14264
|
+
const early = await source.cached().catch(() => null);
|
|
14265
|
+
if (early && !settings) apply(early);
|
|
14266
|
+
}
|
|
14267
|
+
try {
|
|
14268
|
+
apply(await source.get());
|
|
14269
|
+
} catch (error) {
|
|
14270
|
+
console.warn("[softphone] outbound numbers could not be loaded; keeping the previous ones", error);
|
|
14271
|
+
} finally {
|
|
14272
|
+
inFlight = null;
|
|
14273
|
+
}
|
|
14274
|
+
})();
|
|
14275
|
+
return inFlight;
|
|
14276
|
+
},
|
|
14277
|
+
async setMine(id) {
|
|
14278
|
+
apply(await source.setMine(id));
|
|
14279
|
+
},
|
|
14280
|
+
subscribe(listener) {
|
|
14281
|
+
listeners.add(listener);
|
|
14282
|
+
return () => listeners.delete(listener);
|
|
14283
|
+
}
|
|
14284
|
+
};
|
|
14285
|
+
}
|
|
14286
|
+
var noSubscribe = () => () => {
|
|
14287
|
+
};
|
|
14288
|
+
var noSettings = () => null;
|
|
14289
|
+
function useOutboundNumbers(store) {
|
|
14290
|
+
const settings = React.useSyncExternalStore(store?.subscribe ?? noSubscribe, store?.getSettings ?? noSettings);
|
|
14291
|
+
const [failed, setFailed] = React.useState(false);
|
|
14292
|
+
const load = React.useCallback(() => {
|
|
14293
|
+
if (!store) return () => {
|
|
14294
|
+
};
|
|
14295
|
+
let live = true;
|
|
14296
|
+
setFailed(false);
|
|
14297
|
+
void store.refresh().then(() => {
|
|
14298
|
+
if (live) setFailed(store.getSettings() === null);
|
|
14299
|
+
});
|
|
14300
|
+
return () => {
|
|
14301
|
+
live = false;
|
|
14302
|
+
};
|
|
14303
|
+
}, [store]);
|
|
14304
|
+
React.useEffect(load, [load]);
|
|
14305
|
+
return { settings, failed, retry: load };
|
|
14306
|
+
}
|
|
14307
|
+
function useKnownOutboundNumbers(store) {
|
|
14308
|
+
return React.useSyncExternalStore(store?.subscribe ?? noSubscribe, store?.getSettings ?? noSettings);
|
|
14309
|
+
}
|
|
14310
|
+
function useCountdown(until) {
|
|
14311
|
+
const [, setTick] = React.useState(0);
|
|
14312
|
+
React.useEffect(() => {
|
|
14313
|
+
if (!until) return void 0;
|
|
14314
|
+
const timer = setInterval(() => {
|
|
14315
|
+
setTick((n) => n + 1);
|
|
14316
|
+
if (secondsLeft(until) === 0) clearInterval(timer);
|
|
14317
|
+
}, 1e3);
|
|
14318
|
+
return () => clearInterval(timer);
|
|
14319
|
+
}, [until]);
|
|
14320
|
+
return secondsLeft(until);
|
|
14321
|
+
}
|
|
14322
|
+
function secondsLeft(until) {
|
|
14323
|
+
return until ? Math.max(0, Math.ceil((until - Date.now()) / 1e3)) : 0;
|
|
14324
|
+
}
|
|
14325
|
+
function numberName(n, format = formatIntl) {
|
|
14326
|
+
if (!n) return "N\xFAmero de la organizaci\xF3n";
|
|
14327
|
+
return n.label || format(`+${n.number}`);
|
|
14328
|
+
}
|
|
14329
|
+
function effectiveNumber(settings) {
|
|
14330
|
+
return settings?.numbers.find((n) => n.id === settings.effective);
|
|
14331
|
+
}
|
|
14332
|
+
|
|
14333
|
+
// src/ui/outbound/outbound-change.ts
|
|
14334
|
+
var KIND_TAG = {
|
|
14335
|
+
mobile: { tag: "M\xF3vil", hint: "No usar para atenci\xF3n al cliente ni para llamadas comerciales no solicitadas." },
|
|
14336
|
+
commercial: { tag: "Comercial (400)", hint: "Solo para llamadas comerciales. No recibe llamadas." }
|
|
14337
|
+
};
|
|
14338
|
+
function noticeText(situation, seconds, current) {
|
|
14339
|
+
switch (situation) {
|
|
14340
|
+
case "platform":
|
|
14341
|
+
return `El cambio de n\xFAmero de salida no est\xE1 disponible temporalmente. Vuelve a intentarlo en ${seconds} s. Hasta entonces, tus llamadas seguir\xE1n saliendo desde ${current}.`;
|
|
14342
|
+
case "user":
|
|
14343
|
+
return `Acabas de cambiar el n\xFAmero de salida. Podr\xE1s cambiarlo de nuevo en ${seconds} s. Hasta entonces, tus llamadas saldr\xE1n desde ${current}.`;
|
|
14344
|
+
case "wait":
|
|
14345
|
+
return `Podr\xE1s cambiar el n\xFAmero de salida en ${seconds} s.`;
|
|
14346
|
+
case "pending":
|
|
14347
|
+
return seconds > 0 ? `Tu n\xFAmero de salida todav\xEDa no se ha aplicado. Podr\xE1s volver a elegirlo en ${seconds} s.` : "Tu n\xFAmero de salida todav\xEDa no se ha aplicado. Vuelve a elegirlo para aplicarlo.";
|
|
14348
|
+
}
|
|
14349
|
+
}
|
|
14350
|
+
function useOutboundNumberChange(store, settings, current) {
|
|
14351
|
+
const [busy, setBusy] = React.useState(false);
|
|
14352
|
+
const [notice, setNotice] = React.useState(null);
|
|
14353
|
+
const [waitUntil, setWaitUntil] = React.useState(null);
|
|
14354
|
+
React.useEffect(() => {
|
|
14355
|
+
const s = settings?.changeAvailableInSeconds ?? 0;
|
|
14356
|
+
setWaitUntil(s > 0 ? Date.now() + s * 1e3 : null);
|
|
14357
|
+
}, [settings]);
|
|
14358
|
+
const refusedUntil = notice?.kind === "refused" ? notice.until : null;
|
|
14359
|
+
const blockedFor = useCountdown(refusedUntil ?? waitUntil);
|
|
14360
|
+
React.useEffect(() => {
|
|
14361
|
+
if (notice?.kind === "refused" && blockedFor === 0) setNotice(null);
|
|
14362
|
+
}, [notice, blockedFor]);
|
|
14363
|
+
const locked = busy || blockedFor > 0;
|
|
14364
|
+
const choose = async (id) => {
|
|
14365
|
+
if (!store || !settings || locked) return false;
|
|
14366
|
+
if (id === settings.mine) return true;
|
|
14367
|
+
setBusy(true);
|
|
14368
|
+
setNotice(null);
|
|
14369
|
+
try {
|
|
14370
|
+
await store.setMine(id);
|
|
14371
|
+
return true;
|
|
14372
|
+
} catch (error) {
|
|
14373
|
+
setNotice(
|
|
14374
|
+
isOutboundNumberRefused(error) ? { kind: "refused", reason: error.refusal.reason, until: Date.now() + error.refusal.retryAfterSeconds * 1e3 } : { kind: "error", text: errorText(error) }
|
|
14375
|
+
);
|
|
14376
|
+
return false;
|
|
14377
|
+
} finally {
|
|
14378
|
+
setBusy(false);
|
|
14379
|
+
}
|
|
14380
|
+
};
|
|
14381
|
+
return {
|
|
14382
|
+
busy,
|
|
14383
|
+
locked,
|
|
14384
|
+
choose,
|
|
14385
|
+
/** What to say about the choice right now, if anything. */
|
|
14386
|
+
message: settings ? currentMessage(notice, settings.state, blockedFor, current) : null,
|
|
14387
|
+
/** The message is an error (the change failed), not information (wait, pending). */
|
|
14388
|
+
isError: notice?.kind === "error"
|
|
14389
|
+
};
|
|
14390
|
+
}
|
|
14391
|
+
function currentMessage(notice, state, blockedFor, current) {
|
|
14392
|
+
if (notice?.kind === "refused") return blockedFor > 0 ? noticeText(notice.reason, blockedFor, current) : null;
|
|
14393
|
+
if (notice?.kind === "error") return notice.text;
|
|
14394
|
+
if (state === "pending" || state === "failed") return noticeText("pending", blockedFor, current);
|
|
14395
|
+
return blockedFor > 0 ? noticeText("wait", blockedFor, current) : null;
|
|
14396
|
+
}
|
|
14397
|
+
function errorText(error) {
|
|
14398
|
+
const message = error instanceof Error ? error.message : "";
|
|
14399
|
+
return message && !/HTTP \d+/.test(message) ? message : "No se ha podido cambiar el n\xFAmero de salida. Int\xE9ntalo de nuevo.";
|
|
14400
|
+
}
|
|
14401
|
+
var CALLOUT_MS = 6e3;
|
|
14402
|
+
function OutboundNumberPicker({ onBusyChange }) {
|
|
14403
|
+
const softphone = useSoftphone();
|
|
14404
|
+
const store = outboundNumberStore(softphone);
|
|
14405
|
+
const { settings } = useOutboundNumbers(store);
|
|
14406
|
+
const formatIntl2 = useIntlFormatter();
|
|
14407
|
+
const current = settings ? numberName(effectiveNumber(settings), formatIntl2) : "";
|
|
14408
|
+
const { busy, locked, choose: apply, message, isError } = useOutboundNumberChange(store, settings, current);
|
|
14409
|
+
const [open, setOpen] = React.useState(false);
|
|
14410
|
+
const [applying, setApplying] = React.useState(void 0);
|
|
14411
|
+
const [callout, setCallout] = React.useState(false);
|
|
14412
|
+
const rootRef = React.useRef(null);
|
|
14413
|
+
const chipRef = React.useRef(null);
|
|
14414
|
+
const keys = useListKeyboard(open);
|
|
14415
|
+
React.useEffect(() => onBusyChange?.(busy), [busy, onBusyChange]);
|
|
14416
|
+
React.useEffect(() => {
|
|
14417
|
+
if (!message) setCallout(false);
|
|
14418
|
+
}, [message]);
|
|
14419
|
+
React.useEffect(() => {
|
|
14420
|
+
if (!callout) return void 0;
|
|
14421
|
+
const timer = setTimeout(() => setCallout(false), CALLOUT_MS);
|
|
14422
|
+
return () => clearTimeout(timer);
|
|
14423
|
+
}, [callout]);
|
|
14424
|
+
const floating = open || callout;
|
|
14425
|
+
React.useEffect(() => {
|
|
14426
|
+
if (!floating) return;
|
|
14427
|
+
const close = () => {
|
|
14428
|
+
setOpen(false);
|
|
14429
|
+
setCallout(false);
|
|
14430
|
+
};
|
|
14431
|
+
const root = rootRef.current?.getRootNode() ?? document;
|
|
14432
|
+
const onDown = (e) => {
|
|
14433
|
+
if (!rootRef.current?.contains(e.target)) close();
|
|
14434
|
+
};
|
|
14435
|
+
const onKey = (e) => {
|
|
14436
|
+
if (e.key !== "Escape") return;
|
|
14437
|
+
if (rootRef.current?.contains(e.target)) chipRef.current?.focus();
|
|
14438
|
+
close();
|
|
14439
|
+
};
|
|
14440
|
+
root.addEventListener("pointerdown", onDown);
|
|
14441
|
+
document.addEventListener("keydown", onKey);
|
|
14442
|
+
return () => {
|
|
14443
|
+
root.removeEventListener("pointerdown", onDown);
|
|
14444
|
+
document.removeEventListener("keydown", onKey);
|
|
14445
|
+
};
|
|
14446
|
+
}, [floating]);
|
|
14447
|
+
if (!store || !settings || settings.numbers.length < 2) return null;
|
|
14448
|
+
const orgDefault = settings.numbers.find((n) => n.id === settings.orgDefault);
|
|
14449
|
+
const applyingNumber = applying === null ? orgDefault : settings.numbers.find((n) => n.id === applying);
|
|
14450
|
+
const shown = applying === void 0 ? current : numberName(applyingNumber, formatIntl2);
|
|
14451
|
+
const choose = async (id) => {
|
|
14452
|
+
if (locked) return;
|
|
14453
|
+
setOpen(false);
|
|
14454
|
+
chipRef.current?.focus();
|
|
14455
|
+
if (id === settings.mine) return;
|
|
14456
|
+
setCallout(false);
|
|
14457
|
+
setApplying(id);
|
|
14458
|
+
const applied = await apply(id);
|
|
14459
|
+
setApplying(void 0);
|
|
14460
|
+
if (!applied) setCallout(true);
|
|
14461
|
+
};
|
|
14462
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "cv-on", ref: rootRef, children: [
|
|
14463
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
14464
|
+
"button",
|
|
14465
|
+
{
|
|
14466
|
+
ref: chipRef,
|
|
14467
|
+
type: "button",
|
|
14468
|
+
className: "cv-on-chip",
|
|
14469
|
+
onClick: () => {
|
|
14470
|
+
setCallout(false);
|
|
14471
|
+
setOpen((o) => !o);
|
|
14472
|
+
},
|
|
14473
|
+
"aria-haspopup": "listbox",
|
|
14474
|
+
"aria-expanded": open,
|
|
14475
|
+
"aria-label": `Llamar desde: ${shown}${busy ? " (aplicando)" : ""}. Cambiar n\xFAmero de salida`,
|
|
14476
|
+
"aria-busy": busy,
|
|
14477
|
+
part: "outbound-number-chip",
|
|
14478
|
+
children: [
|
|
14479
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "cv-on-label", children: "Llamar desde:" }),
|
|
14480
|
+
busy ? /* @__PURE__ */ jsxRuntime.jsx(LoaderCircle, { size: 13, className: "cv-on-icon cv-on-spin", "aria-hidden": true }) : null,
|
|
14481
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "cv-on-current", children: shown }),
|
|
14482
|
+
/* @__PURE__ */ jsxRuntime.jsx(ChevronDown, { size: 13, className: "cv-cp-caret", "data-open": open, "aria-hidden": true })
|
|
14483
|
+
]
|
|
14484
|
+
}
|
|
14485
|
+
),
|
|
14486
|
+
open ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
14487
|
+
"div",
|
|
14488
|
+
{
|
|
14489
|
+
className: "cv-cp-pop cv-on-pop",
|
|
14490
|
+
role: "dialog",
|
|
14491
|
+
"aria-label": "Llamar desde",
|
|
14492
|
+
part: "outbound-number-list",
|
|
14493
|
+
onBlur: (e) => {
|
|
14494
|
+
if (!e.currentTarget.contains(e.relatedTarget)) setOpen(false);
|
|
14495
|
+
},
|
|
14496
|
+
children: [
|
|
14497
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "cv-on-title", children: "Llamar desde" }),
|
|
14498
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "cv-cp-list", role: "listbox", "aria-disabled": locked, ref: keys.listRef, onKeyDown: keys.onKeyDown, children: [
|
|
14499
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14500
|
+
OptionRow,
|
|
14501
|
+
{
|
|
14502
|
+
selected: settings.mine === null,
|
|
14503
|
+
disabled: locked,
|
|
14504
|
+
title: "Por defecto de la organizaci\xF3n",
|
|
14505
|
+
sub: orgDefault ? numberName(orgDefault, formatIntl2) : "Sin n\xFAmero por defecto",
|
|
14506
|
+
onSelect: () => void choose(null)
|
|
14507
|
+
}
|
|
14508
|
+
),
|
|
14509
|
+
settings.numbers.map((n) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
14510
|
+
OptionRow,
|
|
14511
|
+
{
|
|
14512
|
+
selected: settings.mine === n.id,
|
|
14513
|
+
disabled: locked,
|
|
14514
|
+
title: numberName(n, formatIntl2),
|
|
14515
|
+
sub: n.label ? formatIntl2(`+${n.number}`) : null,
|
|
14516
|
+
tag: KIND_TAG[n.kind],
|
|
14517
|
+
onSelect: () => void choose(n.id)
|
|
14518
|
+
},
|
|
14519
|
+
n.id
|
|
14520
|
+
))
|
|
14521
|
+
] }),
|
|
14522
|
+
message ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "cv-on-notice", role: "status", "data-kind": isError ? "error" : "info", children: message }) : null
|
|
14523
|
+
]
|
|
14524
|
+
}
|
|
14525
|
+
) : null,
|
|
14526
|
+
callout && !open && message ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "cv-on-callout", role: "status", "data-kind": isError ? "error" : "info", part: "outbound-number-notice", children: message }) : null
|
|
14527
|
+
] });
|
|
14528
|
+
}
|
|
14529
|
+
function OptionRow({
|
|
14530
|
+
selected,
|
|
14531
|
+
disabled,
|
|
14532
|
+
title,
|
|
14533
|
+
sub,
|
|
14534
|
+
tag,
|
|
14535
|
+
onSelect
|
|
14536
|
+
}) {
|
|
14537
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
14538
|
+
"button",
|
|
14539
|
+
{
|
|
14540
|
+
type: "button",
|
|
14541
|
+
role: "option",
|
|
14542
|
+
"aria-selected": selected,
|
|
14543
|
+
"aria-disabled": disabled,
|
|
14544
|
+
className: "cv-cp-item cv-on-item",
|
|
14545
|
+
tabIndex: -1,
|
|
14546
|
+
onClick: onSelect,
|
|
14547
|
+
children: [
|
|
14548
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "cv-on-text", children: [
|
|
14549
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "cv-on-line", children: [
|
|
14550
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "cv-cp-name", children: title }),
|
|
14551
|
+
tag ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "cv-on-tag", children: tag.tag }) : null
|
|
14552
|
+
] }),
|
|
14553
|
+
sub ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "cv-on-sub", children: sub }) : null,
|
|
14554
|
+
tag ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "cv-on-hint", children: tag.hint }) : null
|
|
14555
|
+
] }),
|
|
14556
|
+
/* @__PURE__ */ jsxRuntime.jsx(Check, { size: 14, className: "cv-cp-check", "data-on": selected, "aria-hidden": true })
|
|
14557
|
+
]
|
|
14558
|
+
}
|
|
14559
|
+
);
|
|
14560
|
+
}
|
|
14561
|
+
var optionsOf = (list) => list ? [...list.querySelectorAll('[role="option"]')] : [];
|
|
14562
|
+
var fold = (text) => text.normalize("NFD").replace(/\p{Diacritic}/gu, "").toLowerCase();
|
|
14563
|
+
var TYPEAHEAD_MS = 700;
|
|
14564
|
+
function useListKeyboard(open) {
|
|
14565
|
+
const listRef = React.useRef(null);
|
|
14566
|
+
const typed = React.useRef({ text: "", at: 0 });
|
|
14567
|
+
React.useEffect(() => {
|
|
14568
|
+
if (!open) return;
|
|
14569
|
+
const options = optionsOf(listRef.current);
|
|
14570
|
+
(options.find((o) => o.getAttribute("aria-selected") === "true") ?? options[0])?.focus();
|
|
14571
|
+
}, [open]);
|
|
14572
|
+
const onKeyDown = (e) => {
|
|
14573
|
+
const options = optionsOf(listRef.current);
|
|
14574
|
+
const at = options.indexOf(e.target);
|
|
14575
|
+
const move = {
|
|
14576
|
+
ArrowDown: Math.min(at + 1, options.length - 1),
|
|
14577
|
+
ArrowUp: Math.max(at - 1, 0),
|
|
14578
|
+
Home: 0,
|
|
14579
|
+
End: options.length - 1
|
|
14580
|
+
};
|
|
14581
|
+
let next = move[e.key];
|
|
14582
|
+
if (next === void 0 && e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey) {
|
|
14583
|
+
const now = Date.now();
|
|
14584
|
+
const text = now - typed.current.at < TYPEAHEAD_MS ? typed.current.text + e.key : e.key;
|
|
14585
|
+
typed.current = { text, at: now };
|
|
14586
|
+
const wanted = fold(text);
|
|
14587
|
+
const match = options.findIndex((o) => fold(o.querySelector(".cv-cp-name")?.textContent ?? "").startsWith(wanted));
|
|
14588
|
+
next = match >= 0 ? match : void 0;
|
|
14589
|
+
}
|
|
14590
|
+
if (next === void 0) return;
|
|
14591
|
+
e.preventDefault();
|
|
14592
|
+
options[next]?.focus();
|
|
14593
|
+
};
|
|
14594
|
+
return { listRef, onKeyDown };
|
|
14595
|
+
}
|
|
14194
14596
|
var NOT_DIALABLE = /* @__PURE__ */ new Set(["*", "#"]);
|
|
14597
|
+
var DISPLAY_SIZES = ["1.375rem", "1.25rem", "1.125rem", "1rem"];
|
|
14195
14598
|
function Dialpad({ outcome = null, onIntent, keyTones = true } = {}) {
|
|
14196
14599
|
const softphone = useSoftphone();
|
|
14197
14600
|
const state = useSoftphoneState();
|
|
14198
14601
|
const [value, setValue] = React.useState("");
|
|
14199
14602
|
const [country2, setCountry] = React.useState(DEFAULT_COUNTRY);
|
|
14603
|
+
const [changingNumber, setChangingNumber] = React.useState(false);
|
|
14200
14604
|
const format = useNumberFormatter();
|
|
14201
14605
|
const inputRef = React.useRef(null);
|
|
14202
14606
|
const caretRef = React.useRef(null);
|
|
14203
14607
|
const display = format(country2, value);
|
|
14204
14608
|
const target = toE164(country2, value);
|
|
14205
|
-
const canCall = state === "online" && target.length > 1;
|
|
14609
|
+
const canCall = state === "online" && target.length > 1 && !changingNumber;
|
|
14610
|
+
const typedInternational = value.trim().startsWith("+");
|
|
14611
|
+
const numberRegion = regionOfInternational(value);
|
|
14206
14612
|
React.useLayoutEffect(() => {
|
|
14207
14613
|
const caret = caretRef.current;
|
|
14208
14614
|
if (caret === null || !inputRef.current) return;
|
|
@@ -14210,6 +14616,14 @@ function Dialpad({ outcome = null, onIntent, keyTones = true } = {}) {
|
|
|
14210
14616
|
const pos = caretAfterDigits(display, caret);
|
|
14211
14617
|
inputRef.current.setSelectionRange(pos, pos);
|
|
14212
14618
|
}, [display]);
|
|
14619
|
+
React.useLayoutEffect(() => {
|
|
14620
|
+
const input = inputRef.current;
|
|
14621
|
+
if (!input) return;
|
|
14622
|
+
for (const size of DISPLAY_SIZES) {
|
|
14623
|
+
input.style.fontSize = size;
|
|
14624
|
+
if (input.scrollWidth <= input.clientWidth) break;
|
|
14625
|
+
}
|
|
14626
|
+
}, [display]);
|
|
14213
14627
|
const append = (key) => {
|
|
14214
14628
|
onIntent?.();
|
|
14215
14629
|
setValue((v) => v + key);
|
|
@@ -14225,9 +14639,16 @@ function Dialpad({ outcome = null, onIntent, keyTones = true } = {}) {
|
|
|
14225
14639
|
void softphone.call(target);
|
|
14226
14640
|
};
|
|
14227
14641
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "cv-view", children: [
|
|
14228
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14642
|
+
/* @__PURE__ */ jsxRuntime.jsx(OutboundNumberPicker, { onBusyChange: setChangingNumber }),
|
|
14229
14643
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "cv-dial-head", children: [
|
|
14230
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14644
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14645
|
+
CountryPicker,
|
|
14646
|
+
{
|
|
14647
|
+
value: numberRegion ?? country2,
|
|
14648
|
+
onChange: setCountry,
|
|
14649
|
+
fromNumber: typedInternational
|
|
14650
|
+
}
|
|
14651
|
+
),
|
|
14231
14652
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14232
14653
|
"input",
|
|
14233
14654
|
{
|
|
@@ -14251,6 +14672,8 @@ function Dialpad({ outcome = null, onIntent, keyTones = true } = {}) {
|
|
|
14251
14672
|
type: "button",
|
|
14252
14673
|
className: "cv-dial-side",
|
|
14253
14674
|
"data-hidden": value.length === 0,
|
|
14675
|
+
tabIndex: value.length === 0 ? -1 : void 0,
|
|
14676
|
+
"aria-hidden": value.length === 0 || void 0,
|
|
14254
14677
|
onClick: backspace,
|
|
14255
14678
|
"aria-label": "Borrar",
|
|
14256
14679
|
children: /* @__PURE__ */ jsxRuntime.jsx(Delete, { size: 19 })
|
|
@@ -14675,6 +15098,9 @@ function CallScreen({
|
|
|
14675
15098
|
}) {
|
|
14676
15099
|
const view = useCall(call);
|
|
14677
15100
|
const softphone = useSoftphone();
|
|
15101
|
+
const outbound = useOutboundNumbers(call.direction === "outbound" ? outboundNumberStore(softphone) : null).settings;
|
|
15102
|
+
const formatIntl2 = useIntlFormatter();
|
|
15103
|
+
const fromName = outbound && outbound.numbers.length > 1 ? numberName(effectiveNumber(outbound), formatIntl2) : null;
|
|
14678
15104
|
const [panel, setPanel] = React.useState(null);
|
|
14679
15105
|
const showTransfer = panel === "transfer";
|
|
14680
15106
|
const showKeypad = panel === "keypad";
|
|
@@ -14885,6 +15311,13 @@ function CallScreen({
|
|
|
14885
15311
|
] }),
|
|
14886
15312
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "cv-call-name", children: name }),
|
|
14887
15313
|
showNumber ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "cv-call-number", children: number }) : null,
|
|
15314
|
+
fromName ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "cv-call-from", children: [
|
|
15315
|
+
/* @__PURE__ */ jsxRuntime.jsx(PhoneOutgoing, { size: 11, "aria-hidden": true }),
|
|
15316
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
15317
|
+
"Desde ",
|
|
15318
|
+
fromName
|
|
15319
|
+
] })
|
|
15320
|
+
] }) : null,
|
|
14888
15321
|
s === "active" ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "cv-timer", "aria-label": "Duraci\xF3n de la llamada", children: [
|
|
14889
15322
|
/* @__PURE__ */ jsxRuntime.jsx("b", { children: mm }),
|
|
14890
15323
|
/* @__PURE__ */ jsxRuntime.jsx("i", { children: ":" }),
|
|
@@ -15300,12 +15733,23 @@ function HandlerChain({ handlers }) {
|
|
|
15300
15733
|
] }, `${h.extension}-${i}`);
|
|
15301
15734
|
}) });
|
|
15302
15735
|
}
|
|
15736
|
+
function outboundFrom(entry, known, formatIntl2) {
|
|
15737
|
+
if (entry.direction !== "outbound" || !entry.from) return null;
|
|
15738
|
+
const number = formatIntl2(`+${entry.from}`);
|
|
15739
|
+
const label = known?.numbers.find((n) => n.number === entry.from)?.label;
|
|
15740
|
+
if (!label) return number;
|
|
15741
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
15742
|
+
label,
|
|
15743
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "cv-detail-row-sub", children: number })
|
|
15744
|
+
] });
|
|
15745
|
+
}
|
|
15303
15746
|
function HistoryDetail({
|
|
15304
15747
|
entry,
|
|
15305
15748
|
onBack
|
|
15306
15749
|
}) {
|
|
15307
15750
|
const softphone = useSoftphone();
|
|
15308
15751
|
const formatIntl2 = useIntlFormatter();
|
|
15752
|
+
const knownNumbers = useKnownOutboundNumbers(outboundNumberStore(softphone));
|
|
15309
15753
|
const [detail, setDetail] = React.useState(null);
|
|
15310
15754
|
const [loadingDetail, setLoadingDetail] = React.useState(false);
|
|
15311
15755
|
React.useEffect(() => {
|
|
@@ -15321,6 +15765,7 @@ function HistoryDetail({
|
|
|
15321
15765
|
}, [entry]);
|
|
15322
15766
|
const formatted = formatIntl2(entry.number);
|
|
15323
15767
|
const name = entry.name ?? formatted;
|
|
15768
|
+
const from = outboundFrom(entry, knownNumbers, formatIntl2);
|
|
15324
15769
|
const handledBy = detail?.handledBy ?? entry.handledBy;
|
|
15325
15770
|
const recordingUrls = detail?.recordingUrls ?? [];
|
|
15326
15771
|
const loadingRecording = entry.recorded && loadingDetail && recordingUrls.length === 0;
|
|
@@ -15357,7 +15802,8 @@ function HistoryDetail({
|
|
|
15357
15802
|
entry.durationSec > 0 ? /* @__PURE__ */ jsxRuntime.jsx(DetailRow, { icon: Timer, eyebrow: "Duraci\xF3n", text: formatDuration(entry.durationSec) }) : null,
|
|
15358
15803
|
/* @__PURE__ */ jsxRuntime.jsx(DetailRow, { icon: Phone, eyebrow: "N\xFAmero", text: formatted }),
|
|
15359
15804
|
handledBy.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(DetailRow, { icon: User, eyebrow: handlerLabel, text: /* @__PURE__ */ jsxRuntime.jsx(HandlerChain, { handlers: handledBy }) }) : null,
|
|
15360
|
-
entry.direction === "inbound" && entry.did ? /* @__PURE__ */ jsxRuntime.jsx(DetailRow, { icon: Hash, eyebrow: "N\xFAmero marcado (DID)", text: formatIntl2(entry.did) }) : null
|
|
15805
|
+
entry.direction === "inbound" && entry.did ? /* @__PURE__ */ jsxRuntime.jsx(DetailRow, { icon: Hash, eyebrow: "N\xFAmero marcado (DID)", text: formatIntl2(entry.did) }) : null,
|
|
15806
|
+
from ? /* @__PURE__ */ jsxRuntime.jsx(DetailRow, { icon: PhoneOutgoing, eyebrow: "Llamada desde", text: from }) : null
|
|
15361
15807
|
] })
|
|
15362
15808
|
] }),
|
|
15363
15809
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "cv-detail-foot", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -15552,14 +15998,14 @@ function HistoryTab({ source }) {
|
|
|
15552
15998
|
}
|
|
15553
15999
|
|
|
15554
16000
|
// src/ui/audio/ringtone-store.ts
|
|
15555
|
-
var
|
|
16001
|
+
var stores2 = /* @__PURE__ */ new WeakMap();
|
|
15556
16002
|
function ringtoneStore(softphone) {
|
|
15557
16003
|
const source = softphone.sources?.ringtones;
|
|
15558
16004
|
if (!source) return null;
|
|
15559
|
-
let store =
|
|
16005
|
+
let store = stores2.get(softphone);
|
|
15560
16006
|
if (!store) {
|
|
15561
16007
|
store = createRingtoneStore(source);
|
|
15562
|
-
|
|
16008
|
+
stores2.set(softphone, store);
|
|
15563
16009
|
}
|
|
15564
16010
|
return store;
|
|
15565
16011
|
}
|
|
@@ -15685,17 +16131,19 @@ function ChoiceList({
|
|
|
15685
16131
|
choices,
|
|
15686
16132
|
value,
|
|
15687
16133
|
onSelect,
|
|
15688
|
-
onReselect
|
|
16134
|
+
onReselect,
|
|
16135
|
+
disabled = false
|
|
15689
16136
|
}) {
|
|
15690
16137
|
const name = React.useId();
|
|
15691
16138
|
const pointer = React.useRef(false);
|
|
15692
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "cv-choices", role: "radiogroup", "aria-label": label, children: choices.map((c) => {
|
|
16139
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "cv-choices", role: "radiogroup", "aria-label": label, "aria-disabled": disabled || void 0, children: choices.map((c) => {
|
|
15693
16140
|
const checked = c.value === value;
|
|
15694
16141
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
15695
16142
|
"label",
|
|
15696
16143
|
{
|
|
15697
16144
|
className: "cv-choice",
|
|
15698
16145
|
"data-checked": checked || void 0,
|
|
16146
|
+
"data-disabled": disabled || void 0,
|
|
15699
16147
|
onPointerDown: () => {
|
|
15700
16148
|
pointer.current = true;
|
|
15701
16149
|
},
|
|
@@ -15711,19 +16159,23 @@ function ChoiceList({
|
|
|
15711
16159
|
onChange: () => {
|
|
15712
16160
|
const via = pointer.current ? "pointer" : "keyboard";
|
|
15713
16161
|
pointer.current = false;
|
|
15714
|
-
onSelect(c.value, via);
|
|
16162
|
+
if (!disabled) onSelect(c.value, via);
|
|
15715
16163
|
},
|
|
15716
16164
|
onClick: () => {
|
|
15717
16165
|
if (c.value === value) {
|
|
15718
16166
|
pointer.current = false;
|
|
15719
|
-
onReselect?.(c.value);
|
|
16167
|
+
if (!disabled) onReselect?.(c.value);
|
|
15720
16168
|
}
|
|
15721
16169
|
}
|
|
15722
16170
|
}
|
|
15723
16171
|
),
|
|
15724
16172
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "cv-choice-text", children: [
|
|
15725
|
-
/* @__PURE__ */ jsxRuntime.
|
|
15726
|
-
|
|
16173
|
+
c.tag ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "cv-choice-line", children: [
|
|
16174
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "cv-choice-label", children: c.label }),
|
|
16175
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "cv-choice-tag", children: c.tag })
|
|
16176
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "cv-choice-label", children: c.label }),
|
|
16177
|
+
c.sub ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "cv-choice-sub", children: c.sub }) : null,
|
|
16178
|
+
c.hint ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "cv-choice-hint", children: c.hint }) : null
|
|
15727
16179
|
] }),
|
|
15728
16180
|
c.trailing,
|
|
15729
16181
|
/* @__PURE__ */ jsxRuntime.jsx(Check, { size: 16, className: "cv-choice-check", "aria-hidden": true })
|
|
@@ -15885,11 +16337,11 @@ function previewRingtone(ringtone, options = {}) {
|
|
|
15885
16337
|
}
|
|
15886
16338
|
|
|
15887
16339
|
// src/ui/views/settings/ringtone-state.ts
|
|
15888
|
-
var
|
|
16340
|
+
var noSubscribe2 = () => () => {
|
|
15889
16341
|
};
|
|
15890
|
-
var
|
|
16342
|
+
var noSettings2 = () => null;
|
|
15891
16343
|
function useRingtoneSettings(store) {
|
|
15892
|
-
const settings = React.useSyncExternalStore(store?.subscribe ??
|
|
16344
|
+
const settings = React.useSyncExternalStore(store?.subscribe ?? noSubscribe2, store?.getSettings ?? noSettings2);
|
|
15893
16345
|
const [failed, setFailed] = React.useState(false);
|
|
15894
16346
|
const load = React.useCallback(() => {
|
|
15895
16347
|
if (!store) return () => {
|
|
@@ -16090,11 +16542,109 @@ function useSerialSave(store, handlers) {
|
|
|
16090
16542
|
});
|
|
16091
16543
|
return save;
|
|
16092
16544
|
}
|
|
16545
|
+
var ORG_DEFAULT2 = "";
|
|
16546
|
+
var KEYBOARD_SETTLE_MS2 = 800;
|
|
16547
|
+
function OutboundNumberPage({
|
|
16548
|
+
store,
|
|
16549
|
+
settings,
|
|
16550
|
+
onBack
|
|
16551
|
+
}) {
|
|
16552
|
+
const formatIntl2 = useIntlFormatter();
|
|
16553
|
+
const current = numberName(effectiveNumber(settings), formatIntl2);
|
|
16554
|
+
const change = useOutboundNumberChange(store, settings, current);
|
|
16555
|
+
const [pending, setPending] = React.useState(void 0);
|
|
16556
|
+
const settle = React.useRef(null);
|
|
16557
|
+
const choose = React.useRef(change.choose);
|
|
16558
|
+
choose.current = change.choose;
|
|
16559
|
+
React.useEffect(
|
|
16560
|
+
() => () => {
|
|
16561
|
+
if (settle.current) clearTimeout(settle.current);
|
|
16562
|
+
},
|
|
16563
|
+
[]
|
|
16564
|
+
);
|
|
16565
|
+
const notice = React.useRef(null);
|
|
16566
|
+
const apply = async (value) => {
|
|
16567
|
+
setPending(value);
|
|
16568
|
+
const applied = await choose.current(value || null);
|
|
16569
|
+
setPending(void 0);
|
|
16570
|
+
if (!applied) requestAnimationFrame(() => notice.current?.scrollIntoView?.({ block: "nearest" }));
|
|
16571
|
+
};
|
|
16572
|
+
const onSelect = (value, via) => {
|
|
16573
|
+
if (settle.current) clearTimeout(settle.current);
|
|
16574
|
+
settle.current = null;
|
|
16575
|
+
if (via === "pointer") {
|
|
16576
|
+
void apply(value);
|
|
16577
|
+
return;
|
|
16578
|
+
}
|
|
16579
|
+
setPending(value);
|
|
16580
|
+
settle.current = setTimeout(() => {
|
|
16581
|
+
settle.current = null;
|
|
16582
|
+
void apply(value);
|
|
16583
|
+
}, KEYBOARD_SETTLE_MS2);
|
|
16584
|
+
};
|
|
16585
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
16586
|
+
SettingsPage,
|
|
16587
|
+
{
|
|
16588
|
+
title: "N\xFAmero de salida",
|
|
16589
|
+
intro: "El n\xFAmero que ve la persona a la que llamas. Es el mismo en todos tus dispositivos y tambi\xE9n puedes cambiarlo desde el teclado.",
|
|
16590
|
+
onBack,
|
|
16591
|
+
children: [
|
|
16592
|
+
change.message ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "cv-settings-notice", role: "status", "data-kind": change.isError ? "error" : "info", ref: notice, children: change.message }) : null,
|
|
16593
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
16594
|
+
ChoiceList,
|
|
16595
|
+
{
|
|
16596
|
+
label: "N\xFAmero de salida",
|
|
16597
|
+
choices: choicesFor2(settings, formatIntl2, change.busy ? pending : void 0),
|
|
16598
|
+
value: pending ?? currentValue2(settings),
|
|
16599
|
+
onSelect,
|
|
16600
|
+
disabled: change.locked
|
|
16601
|
+
}
|
|
16602
|
+
)
|
|
16603
|
+
]
|
|
16604
|
+
}
|
|
16605
|
+
);
|
|
16606
|
+
}
|
|
16607
|
+
function currentValue2(settings) {
|
|
16608
|
+
return settings.mine && settings.numbers.some((n) => n.id === settings.mine) ? settings.mine : ORG_DEFAULT2;
|
|
16609
|
+
}
|
|
16610
|
+
function choicesFor2(settings, formatIntl2, applying) {
|
|
16611
|
+
const orgDefault = settings.numbers.find((n) => n.id === settings.orgDefault);
|
|
16612
|
+
const spinner = (value) => applying === value ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "cv-choice-applying", children: [
|
|
16613
|
+
/* @__PURE__ */ jsxRuntime.jsx(LoaderCircle, { size: 15, className: "cv-choice-applying-icon", "aria-hidden": true }),
|
|
16614
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "cv-sr-only", children: "Aplicando" })
|
|
16615
|
+
] }) : void 0;
|
|
16616
|
+
return [
|
|
16617
|
+
{
|
|
16618
|
+
value: ORG_DEFAULT2,
|
|
16619
|
+
label: "Por defecto de la organizaci\xF3n",
|
|
16620
|
+
sub: orgDefault ? numberName(orgDefault, formatIntl2) : "Sin n\xFAmero por defecto",
|
|
16621
|
+
trailing: spinner(ORG_DEFAULT2)
|
|
16622
|
+
},
|
|
16623
|
+
...settings.numbers.map((n) => {
|
|
16624
|
+
const kind = KIND_TAG[n.kind];
|
|
16625
|
+
return {
|
|
16626
|
+
value: n.id,
|
|
16627
|
+
label: numberName(n, formatIntl2),
|
|
16628
|
+
...n.label ? { sub: formatIntl2(`+${n.number}`) } : {},
|
|
16629
|
+
...kind ? { tag: kind.tag, hint: kind.hint } : {},
|
|
16630
|
+
trailing: spinner(n.id)
|
|
16631
|
+
};
|
|
16632
|
+
})
|
|
16633
|
+
];
|
|
16634
|
+
}
|
|
16635
|
+
function outboundSummary(settings, formatIntl2) {
|
|
16636
|
+
const effective = effectiveNumber(settings);
|
|
16637
|
+
const name = numberName(effective, formatIntl2);
|
|
16638
|
+
return settings.mine || !effective ? name : `${name} \xB7 organizaci\xF3n`;
|
|
16639
|
+
}
|
|
16093
16640
|
function SettingsTab() {
|
|
16094
16641
|
const softphone = useSoftphone();
|
|
16095
16642
|
const devices = useDevices();
|
|
16096
16643
|
const store = ringtoneStore(softphone);
|
|
16097
16644
|
const ringtone = useRingtoneSettings(store);
|
|
16645
|
+
const outStore = outboundNumberStore(softphone);
|
|
16646
|
+
const outbound = useOutboundNumbers(outStore).settings;
|
|
16647
|
+
const formatIntl2 = useIntlFormatter();
|
|
16098
16648
|
const [page, setPage] = React.useState(null);
|
|
16099
16649
|
const list = React.useRef(null);
|
|
16100
16650
|
const rows = React.useRef({});
|
|
@@ -16129,6 +16679,16 @@ function SettingsTab() {
|
|
|
16129
16679
|
rowRef: rowRef("tone")
|
|
16130
16680
|
}
|
|
16131
16681
|
) }) : null,
|
|
16682
|
+
outStore && outbound && outbound.numbers.length > 1 ? /* @__PURE__ */ jsxRuntime.jsx(SettingsSection, { title: "Llamadas salientes", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
16683
|
+
SettingsNavRow,
|
|
16684
|
+
{
|
|
16685
|
+
icon: PhoneOutgoing,
|
|
16686
|
+
title: "N\xFAmero de salida",
|
|
16687
|
+
value: outboundSummary(outbound, formatIntl2),
|
|
16688
|
+
onOpen: open("outbound"),
|
|
16689
|
+
rowRef: rowRef("outbound")
|
|
16690
|
+
}
|
|
16691
|
+
) }) : null,
|
|
16132
16692
|
/* @__PURE__ */ jsxRuntime.jsxs(SettingsSection, { title: "Dispositivos", children: [
|
|
16133
16693
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
16134
16694
|
SettingsNavRow,
|
|
@@ -16182,7 +16742,7 @@ function SettingsTab() {
|
|
|
16182
16742
|
onRetry: ringtone.retry,
|
|
16183
16743
|
onBack: back
|
|
16184
16744
|
}
|
|
16185
|
-
) : page !== null && page !== "tone" ? /* @__PURE__ */ jsxRuntime.jsx(DevicePage, { kind: page, onBack: back }) : null
|
|
16745
|
+
) : page === "outbound" && outStore && outbound ? /* @__PURE__ */ jsxRuntime.jsx(OutboundNumberPage, { store: outStore, settings: outbound, onBack: back }) : page !== null && page !== "tone" && page !== "outbound" ? /* @__PURE__ */ jsxRuntime.jsx(DevicePage, { kind: page, onBack: back }) : null
|
|
16186
16746
|
] });
|
|
16187
16747
|
}
|
|
16188
16748
|
|