@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/react/index.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
|
-
import { S as Softphone, A as AudioDevices } from '../softphone-
|
|
4
|
-
import { f as CallState, R as RemoteParty, a as Call, h as FatalSoftphoneError, P as PresenceEntry,
|
|
3
|
+
import { S as Softphone, A as AudioDevices } from '../softphone-CY5d2WWY.cjs';
|
|
4
|
+
import { f as CallState, R as RemoteParty, a as Call, h as FatalSoftphoneError, P as PresenceEntry, w as SoftphoneState } from '../call-C6YpT6uR.cjs';
|
|
5
5
|
|
|
6
6
|
interface SoftphoneProviderProps {
|
|
7
7
|
readonly softphone: Softphone;
|
package/dist/react/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
|
-
import { S as Softphone, A as AudioDevices } from '../softphone-
|
|
4
|
-
import { f as CallState, R as RemoteParty, a as Call, h as FatalSoftphoneError, P as PresenceEntry,
|
|
3
|
+
import { S as Softphone, A as AudioDevices } from '../softphone-DXgmTyrX.js';
|
|
4
|
+
import { f as CallState, R as RemoteParty, a as Call, h as FatalSoftphoneError, P as PresenceEntry, w as SoftphoneState } from '../call-C6YpT6uR.js';
|
|
5
5
|
|
|
6
6
|
interface SoftphoneProviderProps {
|
|
7
7
|
readonly softphone: Softphone;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { D as ContactsSource, G as HistorySource, g as Contact, J as AgentsDirectory, K as TransferOutcomesPage, M as PresenceSource, r as RingtoneSource, o as OutboundNumbersSource, y as TypedEmitter, v as SoftphoneEventMap, w as SoftphoneState, h as FatalSoftphoneError, e as CallOptions, a as Call, P as PresenceEntry } from './call-C6YpT6uR.cjs';
|
|
2
2
|
|
|
3
3
|
/** Contacts, history, caller ID, the agents directory, transfer outcomes, presence and ringtone
|
|
4
4
|
* settings, all from one config. */
|
|
@@ -16,6 +16,8 @@ interface BackendSources {
|
|
|
16
16
|
readonly presence: PresenceSource;
|
|
17
17
|
/** The caller's ringtone settings (custom-ringtone.md §4.4). Always Coventia's — no override. */
|
|
18
18
|
readonly ringtones: RingtoneSource;
|
|
19
|
+
/** The caller's outbound number (outbound-number-per-agent.md §5.5). Always Coventia's — no override. */
|
|
20
|
+
readonly outboundNumbers: OutboundNumbersSource;
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { D as ContactsSource, G as HistorySource, g as Contact, J as AgentsDirectory, K as TransferOutcomesPage, M as PresenceSource, r as RingtoneSource, o as OutboundNumbersSource, y as TypedEmitter, v as SoftphoneEventMap, w as SoftphoneState, h as FatalSoftphoneError, e as CallOptions, a as Call, P as PresenceEntry } from './call-C6YpT6uR.js';
|
|
2
2
|
|
|
3
3
|
/** Contacts, history, caller ID, the agents directory, transfer outcomes, presence and ringtone
|
|
4
4
|
* settings, all from one config. */
|
|
@@ -16,6 +16,8 @@ interface BackendSources {
|
|
|
16
16
|
readonly presence: PresenceSource;
|
|
17
17
|
/** The caller's ringtone settings (custom-ringtone.md §4.4). Always Coventia's — no override. */
|
|
18
18
|
readonly ringtones: RingtoneSource;
|
|
19
|
+
/** The caller's outbound number (outbound-number-per-agent.md §5.5). Always Coventia's — no override. */
|
|
20
|
+
readonly outboundNumbers: OutboundNumbersSource;
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
/**
|
package/dist/softphone.css
CHANGED
|
@@ -237,16 +237,13 @@
|
|
|
237
237
|
the gutters cost more than they give, and a cramped keypad is worse than a tight one. */
|
|
238
238
|
@container cv (max-width: 300px) {
|
|
239
239
|
.cv-keypad { padding: 0 0.6rem; gap: 6px; }
|
|
240
|
-
.cv-dial-
|
|
241
|
-
.cv-dial-head { padding: 0.3rem 0.6rem 0.6rem; }
|
|
242
|
-
.cv-display { font-size: 1.5rem; }
|
|
240
|
+
.cv-dial-head { margin: 0 0.6rem 0.6rem; }
|
|
243
241
|
}
|
|
244
242
|
|
|
245
243
|
/* Short hosts. The flex chain already lets the keypad absorb what is left, but below this the keys
|
|
246
244
|
stop being tappable — so buy the height back from the chrome instead of from the keys. */
|
|
247
245
|
@container cv (max-height: 440px) {
|
|
248
|
-
.cv-dial-
|
|
249
|
-
.cv-dial-head { padding-top: 0.2rem; padding-bottom: 0.4rem; }
|
|
246
|
+
.cv-dial-head { margin-bottom: 0.4rem; }
|
|
250
247
|
.cv-dial-foot { padding-bottom: 0.5rem; }
|
|
251
248
|
.cv-controls { gap: 0.4rem; padding-bottom: 0.6rem; }
|
|
252
249
|
}
|
|
@@ -482,21 +479,51 @@
|
|
|
482
479
|
.cv-round--hangup:hover:not(:disabled) { filter: brightness(0.94); }
|
|
483
480
|
|
|
484
481
|
/* ── Dialpad ─────────────────────────────────────────────────────────────────── */
|
|
485
|
-
/* The
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
.
|
|
489
|
-
|
|
490
|
-
display: flex;
|
|
491
|
-
justify-content: center;
|
|
492
|
-
padding: 1rem 1rem 0;
|
|
493
|
-
}
|
|
482
|
+
/* The number: ONE bordered field, the prefix inside it on the left and erase on the right — the pattern of the
|
|
483
|
+
providers' dialers (Talkdesk "[🇺🇸 +1 ▾ | Type or paste a number]", Zendesk, Aircall; outbound-number-per-agent.md
|
|
484
|
+
§5.5, 2026-10-26). The prefix is part of the number being dialled, so it sits inside the same box. The number
|
|
485
|
+
shrinks to fit (`DISPLAY_SIZES` in Dialpad.tsx). The field is the positioned ancestor of the country list, so the
|
|
486
|
+
list spans its width (`left: 0; right: 0`). */
|
|
494
487
|
.cv-dial-head {
|
|
495
488
|
flex-shrink: 0;
|
|
489
|
+
position: relative;
|
|
496
490
|
display: flex;
|
|
497
491
|
align-items: center;
|
|
498
|
-
|
|
499
|
-
|
|
492
|
+
height: 46px;
|
|
493
|
+
margin: 0 1rem 0.75rem;
|
|
494
|
+
padding: 0 0.2rem 0 0;
|
|
495
|
+
border: 1px solid var(--cv-border-strong);
|
|
496
|
+
border-radius: 10px;
|
|
497
|
+
background: var(--cv-bg);
|
|
498
|
+
transition: border-color 0.15s ease, box-shadow 0.15s ease;
|
|
499
|
+
}
|
|
500
|
+
/* With no "Llamar desde" line above it (an org with one number), the field opens the view. */
|
|
501
|
+
.cv-view > .cv-dial-head:first-child { margin-top: 1rem; }
|
|
502
|
+
/* Focus shows on the field, as on any input (WCAG 2.4.7): the accent border and a soft ring. */
|
|
503
|
+
.cv-dial-head:focus-within {
|
|
504
|
+
border-color: var(--cv-accent);
|
|
505
|
+
box-shadow: 0 0 0 3px color-mix(in srgb, var(--cv-accent) 18%, transparent);
|
|
506
|
+
}
|
|
507
|
+
.cv-dial-head > .cv-cp {
|
|
508
|
+
position: static;
|
|
509
|
+
width: auto;
|
|
510
|
+
flex-shrink: 0;
|
|
511
|
+
align-self: stretch;
|
|
512
|
+
}
|
|
513
|
+
/* The prefix as the field's leading segment: the same chip, flush with the field, divided from the number. */
|
|
514
|
+
.cv-dial-head .cv-cp-chip {
|
|
515
|
+
height: 100%;
|
|
516
|
+
padding: 0 0.45rem 0 0.65rem;
|
|
517
|
+
border: 0;
|
|
518
|
+
border-right: 1px solid var(--cv-border);
|
|
519
|
+
border-radius: 9px 0 0 9px;
|
|
520
|
+
background: var(--cv-surface);
|
|
521
|
+
}
|
|
522
|
+
.cv-dial-head .cv-cp-chip:focus-visible { outline: 2px solid var(--cv-accent); outline-offset: -2px; }
|
|
523
|
+
/* Following a number typed in full ("+44 …"): read-only — the flag alone, no caret, no hover. */
|
|
524
|
+
.cv-cp-chip[data-from-number] {
|
|
525
|
+
cursor: default;
|
|
526
|
+
padding: 0 0.6rem;
|
|
500
527
|
}
|
|
501
528
|
/*
|
|
502
529
|
* The outcome of the last attempt, under the number.
|
|
@@ -538,20 +565,25 @@
|
|
|
538
565
|
}
|
|
539
566
|
}
|
|
540
567
|
|
|
568
|
+
/* Left-aligned after the prefix segment, as a phone field reads ("+34 | 600 11 12 22"). 1.375rem is the start of
|
|
569
|
+
`DISPLAY_SIZES`, which steps it down until a long number fits the field. */
|
|
541
570
|
.cv-display {
|
|
542
571
|
flex: 1;
|
|
543
572
|
min-width: 0;
|
|
544
|
-
|
|
573
|
+
height: 100%;
|
|
574
|
+
font: 500 1.375rem var(--cv-font);
|
|
545
575
|
font-variant-numeric: tabular-nums;
|
|
546
|
-
letter-spacing: -0.
|
|
547
|
-
text-align:
|
|
576
|
+
letter-spacing: -0.01em;
|
|
577
|
+
text-align: left;
|
|
548
578
|
color: var(--cv-text);
|
|
549
579
|
border: none;
|
|
550
580
|
background: none;
|
|
551
|
-
padding: 0;
|
|
581
|
+
padding: 0 0.6rem;
|
|
552
582
|
caret-color: var(--cv-accent);
|
|
553
583
|
}
|
|
554
|
-
|
|
584
|
+
/* `--cv-muted`, not `--cv-faint`: a placeholder is read like any text (4.5:1). */
|
|
585
|
+
.cv-display::placeholder { color: var(--cv-muted); font-weight: 400; }
|
|
586
|
+
/* The field around it shows focus (`.cv-dial-head:focus-within`). */
|
|
555
587
|
.cv-display:focus { outline: none; }
|
|
556
588
|
|
|
557
589
|
/* The spacer/erase pair keeps the number optically centred. */
|
|
@@ -607,8 +639,9 @@
|
|
|
607
639
|
font-size: 9px;
|
|
608
640
|
font-weight: 600;
|
|
609
641
|
letter-spacing: 0.14em;
|
|
610
|
-
/*
|
|
611
|
-
|
|
642
|
+
/* `muted` (was `faint`, 2.5:1): the letters are read when dialling a number written in letters (900-FLORES),
|
|
643
|
+
so they are text, held to 4.5:1 like any other (design critique, 2026-10-26). */
|
|
644
|
+
color: var(--cv-muted);
|
|
612
645
|
line-height: 1;
|
|
613
646
|
}
|
|
614
647
|
|
|
@@ -687,6 +720,23 @@
|
|
|
687
720
|
|
|
688
721
|
.cv-call-name { font-size: 1rem; font-weight: 600; line-height: 1.2; }
|
|
689
722
|
.cv-call-number { font-size: 0.75rem; color: var(--cv-muted); margin-top: 2px; }
|
|
723
|
+
/* Which of the org's numbers this outbound call shows. Smaller than the callee: context, not identity — but muted,
|
|
724
|
+
not faint: --cv-faint is under 4.5:1 at this size in both themes, and the agent may need to read it mid-call. */
|
|
725
|
+
.cv-call-from {
|
|
726
|
+
display: inline-flex;
|
|
727
|
+
align-items: center;
|
|
728
|
+
gap: 0.25rem;
|
|
729
|
+
max-width: 100%;
|
|
730
|
+
margin-top: 4px;
|
|
731
|
+
font-size: 0.72rem;
|
|
732
|
+
color: var(--cv-muted);
|
|
733
|
+
}
|
|
734
|
+
.cv-call-from span {
|
|
735
|
+
min-width: 0;
|
|
736
|
+
overflow: hidden;
|
|
737
|
+
text-overflow: ellipsis;
|
|
738
|
+
white-space: nowrap;
|
|
739
|
+
}
|
|
690
740
|
|
|
691
741
|
.cv-timer {
|
|
692
742
|
display: flex;
|
|
@@ -1867,6 +1917,16 @@
|
|
|
1867
1917
|
text-overflow: ellipsis;
|
|
1868
1918
|
}
|
|
1869
1919
|
.cv-detail-row-chevron { color: var(--cv-faint); flex-shrink: 0; }
|
|
1920
|
+
/* A second line under a row's value, for two facts that would each be cut off sharing one line ("Llamada desde":
|
|
1921
|
+
the name the org gave the number, then the number). */
|
|
1922
|
+
.cv-detail-row-sub {
|
|
1923
|
+
display: block;
|
|
1924
|
+
font-size: 0.75rem;
|
|
1925
|
+
font-weight: 400;
|
|
1926
|
+
color: var(--cv-muted);
|
|
1927
|
+
overflow: hidden;
|
|
1928
|
+
text-overflow: ellipsis;
|
|
1929
|
+
}
|
|
1870
1930
|
|
|
1871
1931
|
.cv-detail-foot { flex-shrink: 0; padding: 0.85rem 1.25rem 1.1rem; }
|
|
1872
1932
|
.cv-detail-call { width: 100%; display: flex; align-items: center; justify-content: center; gap: 0.4rem; }
|
|
@@ -1956,6 +2016,18 @@
|
|
|
1956
2016
|
/* `--cv-danger-strong` is the AS-TEXT danger token (see its definition): red-600 on the light `--cv-bg`,
|
|
1957
2017
|
red-400 on the dark one. */
|
|
1958
2018
|
.cv-settings-error { margin: 0.6rem 0.2rem 0; font-size: 0.78rem; line-height: 1.4; color: var(--cv-danger-strong); }
|
|
2019
|
+
/* Why the choice cannot change right now, and until when (Número de salida). Calm, like the dialpad's notice: the
|
|
2020
|
+
phone keeps working. Above the list, so it is in sight of the row just tapped. */
|
|
2021
|
+
.cv-settings-notice {
|
|
2022
|
+
margin: 0 0 0.75rem;
|
|
2023
|
+
padding: 0.6rem 0.75rem;
|
|
2024
|
+
border-radius: 10px;
|
|
2025
|
+
background: var(--cv-surface-2);
|
|
2026
|
+
color: var(--cv-text);
|
|
2027
|
+
font-size: 0.78rem;
|
|
2028
|
+
line-height: 1.4;
|
|
2029
|
+
}
|
|
2030
|
+
.cv-settings-notice[data-kind='error'] { color: var(--cv-danger-strong); }
|
|
1959
2031
|
|
|
1960
2032
|
/*
|
|
1961
2033
|
Ajustes as a list (custom-ringtone.md §4.6, revised 2026-10-14): each row names a setting, shows its CURRENT
|
|
@@ -2043,6 +2115,15 @@ button.cv-settings-nav:focus-visible { outline: 2px solid var(--cv-accent); outl
|
|
|
2043
2115
|
.cv-choice-check { flex-shrink: 0; color: var(--cv-accent-strong); visibility: hidden; }
|
|
2044
2116
|
.cv-choice[data-checked] .cv-choice-check { visibility: visible; }
|
|
2045
2117
|
.cv-choice-playing { display: inline-flex; flex-shrink: 0; color: var(--cv-accent-strong); }
|
|
2118
|
+
/* A tagged choice (Número de salida): the label and its tag on one line, like the dialpad's list. */
|
|
2119
|
+
.cv-choice-line { display: flex; align-items: center; gap: 0.35rem; min-width: 0; }
|
|
2120
|
+
/* Locked while a change is in flight or must wait: the chosen row stays clear, the others step back. */
|
|
2121
|
+
.cv-choice[data-disabled] { cursor: default; }
|
|
2122
|
+
.cv-choice[data-disabled]:not([data-checked]) { opacity: 0.55; }
|
|
2123
|
+
.cv-choice[data-disabled]:hover { background: none; }
|
|
2124
|
+
.cv-choice-applying { display: inline-flex; flex-shrink: 0; color: var(--cv-muted); }
|
|
2125
|
+
/* Exempt from reduced-motion like `.cv-empty-spinner`: the rotation is the information. */
|
|
2126
|
+
.cv-choice-applying-icon { animation: cv-spin 0.8s linear infinite; }
|
|
2046
2127
|
|
|
2047
2128
|
.cv-settings-test,
|
|
2048
2129
|
.cv-settings-retry {
|
|
@@ -2461,3 +2542,153 @@ button.cv-settings-nav:focus-visible { outline: 2px solid var(--cv-accent); outl
|
|
|
2461
2542
|
color: var(--cv-muted);
|
|
2462
2543
|
font-size: 0.78rem;
|
|
2463
2544
|
}
|
|
2545
|
+
|
|
2546
|
+
/* ── "Llamar desde" (outbound-number-per-agent.md §5.5) ─────────────────────── */
|
|
2547
|
+
/* "Llamar desde: Oficina ▾" — a light line right above the number field, as the providers' dialers label their
|
|
2548
|
+
caller ID ("Caller ID: … ▾", "Outbound on: … ▾", "From: … ▾"; outbound-number-per-agent.md §5.5, 2026-10-26). Not a
|
|
2549
|
+
strip with a divider: under the host's own header that read as a second title bar. The line is the positioned
|
|
2550
|
+
ancestor, so its list and callout drop under it. */
|
|
2551
|
+
.cv-on {
|
|
2552
|
+
position: relative;
|
|
2553
|
+
flex-shrink: 0;
|
|
2554
|
+
display: flex;
|
|
2555
|
+
padding: 0.9rem 1rem 0.4rem;
|
|
2556
|
+
}
|
|
2557
|
+
.cv-on-chip {
|
|
2558
|
+
display: inline-flex;
|
|
2559
|
+
align-items: center;
|
|
2560
|
+
gap: 0.3rem;
|
|
2561
|
+
max-width: 100%;
|
|
2562
|
+
min-width: 0;
|
|
2563
|
+
height: 26px;
|
|
2564
|
+
margin-left: -0.3rem;
|
|
2565
|
+
padding: 0 0.3rem;
|
|
2566
|
+
border: 0;
|
|
2567
|
+
border-radius: 6px;
|
|
2568
|
+
background: none;
|
|
2569
|
+
color: var(--cv-text);
|
|
2570
|
+
font: 0.8rem var(--cv-font);
|
|
2571
|
+
text-align: left;
|
|
2572
|
+
cursor: pointer;
|
|
2573
|
+
transition: background 0.15s;
|
|
2574
|
+
}
|
|
2575
|
+
.cv-on-chip:hover { background: var(--cv-surface-2); }
|
|
2576
|
+
.cv-on-chip:focus-visible { outline: 2px solid var(--cv-accent); outline-offset: 0; }
|
|
2577
|
+
.cv-on-label { flex-shrink: 0; color: var(--cv-muted); }
|
|
2578
|
+
.cv-on-chip .cv-on-current { font-weight: 600; }
|
|
2579
|
+
.cv-on-icon { color: var(--cv-accent-strong); flex-shrink: 0; }
|
|
2580
|
+
.cv-on-spin { animation: cv-spin 0.9s linear infinite; }
|
|
2581
|
+
@media (prefers-reduced-motion: reduce) {
|
|
2582
|
+
.cv-on-spin { animation: none; }
|
|
2583
|
+
}
|
|
2584
|
+
.cv-on-current {
|
|
2585
|
+
min-width: 0;
|
|
2586
|
+
overflow: hidden;
|
|
2587
|
+
text-overflow: ellipsis;
|
|
2588
|
+
white-space: nowrap;
|
|
2589
|
+
}
|
|
2590
|
+
/* Drops under the strip, over the number and the keypad, inset to the strip's edges. Capped so that in the CRM's
|
|
2591
|
+
473px panel it never reaches the tab bar: the LIST gives way (it scrolls), never the title or a refusal message. */
|
|
2592
|
+
.cv-on-pop {
|
|
2593
|
+
top: calc(100% + 4px);
|
|
2594
|
+
left: 0.5rem;
|
|
2595
|
+
right: 0.5rem;
|
|
2596
|
+
max-width: none;
|
|
2597
|
+
max-height: 330px;
|
|
2598
|
+
}
|
|
2599
|
+
.cv-on-pop .cv-cp-list {
|
|
2600
|
+
flex: 1 1 auto;
|
|
2601
|
+
min-height: 0;
|
|
2602
|
+
max-height: none;
|
|
2603
|
+
}
|
|
2604
|
+
.cv-on-title {
|
|
2605
|
+
flex-shrink: 0;
|
|
2606
|
+
margin: 0;
|
|
2607
|
+
padding: 0.5rem 0.75rem 0.4rem;
|
|
2608
|
+
border-bottom: 1px solid var(--cv-border);
|
|
2609
|
+
font: 600 0.7rem var(--cv-font);
|
|
2610
|
+
letter-spacing: 0.06em;
|
|
2611
|
+
text-transform: uppercase;
|
|
2612
|
+
color: var(--cv-muted);
|
|
2613
|
+
}
|
|
2614
|
+
.cv-on-item { align-items: flex-start; }
|
|
2615
|
+
/* Locked while a change is applying or the limit says wait: still legible (the choice is visible), not usable. */
|
|
2616
|
+
.cv-on-item[aria-disabled='true'] { cursor: default; }
|
|
2617
|
+
.cv-on-item[aria-disabled='true']:not([aria-selected='true']) { opacity: 0.55; }
|
|
2618
|
+
.cv-on-item[aria-disabled='true']:not([aria-selected='true']):hover { background: none; }
|
|
2619
|
+
.cv-on-text {
|
|
2620
|
+
flex: 1;
|
|
2621
|
+
min-width: 0;
|
|
2622
|
+
display: flex;
|
|
2623
|
+
flex-direction: column;
|
|
2624
|
+
gap: 1px;
|
|
2625
|
+
}
|
|
2626
|
+
.cv-on-line {
|
|
2627
|
+
display: flex;
|
|
2628
|
+
align-items: center;
|
|
2629
|
+
gap: 0.35rem;
|
|
2630
|
+
min-width: 0;
|
|
2631
|
+
}
|
|
2632
|
+
.cv-on-sub {
|
|
2633
|
+
color: var(--cv-muted);
|
|
2634
|
+
font-size: 0.74rem;
|
|
2635
|
+
font-variant-numeric: tabular-nums;
|
|
2636
|
+
}
|
|
2637
|
+
/* A quiet, neutral pill: it tells the agent what the number is for, it is not a warning. Shared with Ajustes. */
|
|
2638
|
+
.cv-on-tag,
|
|
2639
|
+
.cv-choice-tag {
|
|
2640
|
+
flex-shrink: 0;
|
|
2641
|
+
padding: 0 0.35rem;
|
|
2642
|
+
border: 1px solid var(--cv-border-strong);
|
|
2643
|
+
border-radius: 999px;
|
|
2644
|
+
color: var(--cv-muted);
|
|
2645
|
+
font-size: 0.66rem;
|
|
2646
|
+
font-weight: 600;
|
|
2647
|
+
line-height: 1.4;
|
|
2648
|
+
}
|
|
2649
|
+
/* The usage rule IS information (when not to call from this number): --cv-muted, not --cv-faint, which is under
|
|
2650
|
+
4.5:1 at this size in both themes (see `.cv-empty-sub`). */
|
|
2651
|
+
.cv-on-hint,
|
|
2652
|
+
.cv-choice-hint {
|
|
2653
|
+
color: var(--cv-muted);
|
|
2654
|
+
font-size: 0.7rem;
|
|
2655
|
+
line-height: 1.3;
|
|
2656
|
+
}
|
|
2657
|
+
.cv-on-item .cv-cp-check { margin-top: 2px; }
|
|
2658
|
+
/* Why a change cannot happen right now, and until when. Calm, not alarming: the phone keeps working. */
|
|
2659
|
+
.cv-on-notice {
|
|
2660
|
+
flex-shrink: 0;
|
|
2661
|
+
margin: 0;
|
|
2662
|
+
padding: 0.55rem 0.75rem;
|
|
2663
|
+
border-top: 1px solid var(--cv-border);
|
|
2664
|
+
background: var(--cv-surface-2);
|
|
2665
|
+
color: var(--cv-text);
|
|
2666
|
+
font-size: 0.74rem;
|
|
2667
|
+
line-height: 1.4;
|
|
2668
|
+
}
|
|
2669
|
+
.cv-on-notice[data-kind='error'] { color: var(--cv-danger-strong); }
|
|
2670
|
+
/* A change that did not go through, after the (optimistic) list already closed: the same words, where the list
|
|
2671
|
+
was (under the strip). Same place and surface as the list; dismissed by a tap elsewhere, when the wait is over,
|
|
2672
|
+
or after a few seconds. */
|
|
2673
|
+
.cv-on-callout {
|
|
2674
|
+
position: absolute;
|
|
2675
|
+
top: calc(100% + 4px);
|
|
2676
|
+
left: 0.5rem;
|
|
2677
|
+
right: 0.5rem;
|
|
2678
|
+
margin: 0;
|
|
2679
|
+
z-index: 20;
|
|
2680
|
+
padding: 0.6rem 0.75rem;
|
|
2681
|
+
background: var(--cv-surface);
|
|
2682
|
+
border: 1px solid var(--cv-border);
|
|
2683
|
+
border-radius: var(--cv-radius);
|
|
2684
|
+
box-shadow: var(--cv-shadow);
|
|
2685
|
+
color: var(--cv-text);
|
|
2686
|
+
font-size: 0.74rem;
|
|
2687
|
+
line-height: 1.4;
|
|
2688
|
+
transform-origin: top center;
|
|
2689
|
+
animation: cv-cp-in 0.14s cubic-bezier(0.2, 0, 0.2, 1);
|
|
2690
|
+
}
|
|
2691
|
+
.cv-on-callout[data-kind='error'] { color: var(--cv-danger-strong); }
|
|
2692
|
+
@media (prefers-reduced-motion: reduce) {
|
|
2693
|
+
.cv-on-callout { animation: none; }
|
|
2694
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { outboundNumberRefused } from './chunk-5E5OEXS2.js';
|
|
1
2
|
import { invalidateToken } from './chunk-MHOJHG5E.js';
|
|
2
3
|
|
|
3
4
|
// src/sources.ts
|
|
@@ -39,10 +40,12 @@ function withNameResolution(source, resolve) {
|
|
|
39
40
|
// src/coventia/api.ts
|
|
40
41
|
var ApiError = class extends Error {
|
|
41
42
|
status;
|
|
42
|
-
|
|
43
|
+
body;
|
|
44
|
+
constructor(status, message, body = null) {
|
|
43
45
|
super(message);
|
|
44
46
|
this.name = "ApiError";
|
|
45
47
|
this.status = status;
|
|
48
|
+
this.body = body;
|
|
46
49
|
}
|
|
47
50
|
};
|
|
48
51
|
function createRequest(config, method) {
|
|
@@ -63,9 +66,9 @@ function createRequest(config, method) {
|
|
|
63
66
|
});
|
|
64
67
|
const body = await res.json().catch(() => null);
|
|
65
68
|
const message = body?.message ?? `${path} \u2014 HTTP ${res.status}`;
|
|
66
|
-
if (!res.ok) throw new ApiError(res.status, message);
|
|
69
|
+
if (!res.ok) throw new ApiError(res.status, message, body);
|
|
67
70
|
if (body?.success === false) {
|
|
68
|
-
throw new ApiError(res.status, message);
|
|
71
|
+
throw new ApiError(res.status, message, body);
|
|
69
72
|
}
|
|
70
73
|
return body;
|
|
71
74
|
}
|
|
@@ -206,6 +209,8 @@ function coventiaSources(config) {
|
|
|
206
209
|
// row's `called_did` is the OTHER party (already `number` above); showing it again as "DID"
|
|
207
210
|
// would just repeat the row under a wrong label.
|
|
208
211
|
...toDirection(row.direction) === "inbound" && row.called_did ? { did: row.called_did } : {},
|
|
212
|
+
// And the other way round: which of the org's numbers an outbound call showed.
|
|
213
|
+
...toDirection(row.direction) === "outbound" && row.from_number ? { from: row.from_number } : {},
|
|
209
214
|
recorded,
|
|
210
215
|
handledBy,
|
|
211
216
|
// The detail page's one enrichment fetch — signed recording URLs, plus this SAME chain with
|
|
@@ -323,10 +328,10 @@ function coventiaSources(config) {
|
|
|
323
328
|
return { catalogue, orgDefault: body.orgDefault ?? null, mine: body.user ?? null, effective };
|
|
324
329
|
};
|
|
325
330
|
const CACHE_PREFIX = "coventia-softphone:ringtones:";
|
|
326
|
-
const cacheKey = async () => {
|
|
331
|
+
const cacheKey = async (prefix = CACHE_PREFIX) => {
|
|
327
332
|
try {
|
|
328
333
|
const { identity } = await config.tokenSource.getToken();
|
|
329
|
-
return `${
|
|
334
|
+
return `${prefix}${fileBase}|${config.organizationId ?? "-"}|${identity}`;
|
|
330
335
|
} catch {
|
|
331
336
|
return null;
|
|
332
337
|
}
|
|
@@ -359,6 +364,68 @@ function coventiaSources(config) {
|
|
|
359
364
|
),
|
|
360
365
|
cached: recall
|
|
361
366
|
};
|
|
367
|
+
const KINDS = /* @__PURE__ */ new Set(["landline", "mobile", "commercial", "other"]);
|
|
368
|
+
const STATES = /* @__PURE__ */ new Set(["applied", "pending", "failed", "unassigned"]);
|
|
369
|
+
const toOutboundSettings = (body) => {
|
|
370
|
+
const numbers = (body.numbers ?? []).map((n) => ({
|
|
371
|
+
id: n.id,
|
|
372
|
+
number: n.number,
|
|
373
|
+
label: n.label ?? null,
|
|
374
|
+
kind: KINDS.has(n.kind ?? "") ? n.kind : "other"
|
|
375
|
+
}));
|
|
376
|
+
const known = (id) => id && numbers.some((n) => n.id === id) ? id : null;
|
|
377
|
+
return {
|
|
378
|
+
numbers,
|
|
379
|
+
orgDefault: body.orgDefault ?? null,
|
|
380
|
+
mine: known(body.mine),
|
|
381
|
+
// Defensive: a malformed answer naming a number that is not in the list reads as the org default.
|
|
382
|
+
effective: known(body.effective) ?? known(body.orgDefault),
|
|
383
|
+
extension: body.extension ?? null,
|
|
384
|
+
state: STATES.has(body.state ?? "") ? body.state : "applied",
|
|
385
|
+
changeAvailableInSeconds: Math.max(0, Math.ceil(Number(body.changeAvailableInSeconds) || 0))
|
|
386
|
+
};
|
|
387
|
+
};
|
|
388
|
+
const OUTBOUND_PREFIX = "coventia-softphone:outbound-number:";
|
|
389
|
+
const rememberOutbound = async (settings) => {
|
|
390
|
+
const key = await cacheKey(OUTBOUND_PREFIX);
|
|
391
|
+
try {
|
|
392
|
+
if (key) globalThis.localStorage?.setItem(key, JSON.stringify(settings));
|
|
393
|
+
} catch {
|
|
394
|
+
}
|
|
395
|
+
return settings;
|
|
396
|
+
};
|
|
397
|
+
const recallOutbound = async () => {
|
|
398
|
+
const key = await cacheKey(OUTBOUND_PREFIX);
|
|
399
|
+
try {
|
|
400
|
+
const raw = key ? globalThis.localStorage?.getItem(key) : null;
|
|
401
|
+
const s = raw ? JSON.parse(raw) : null;
|
|
402
|
+
const ok = s && Array.isArray(s.numbers) && s.numbers.every((n) => typeof n?.id === "string" && typeof n.number === "string") && (s.effective === null || s.numbers.some((n) => n.id === s.effective));
|
|
403
|
+
return ok ? { ...s, changeAvailableInSeconds: 0 } : null;
|
|
404
|
+
} catch {
|
|
405
|
+
return null;
|
|
406
|
+
}
|
|
407
|
+
};
|
|
408
|
+
const outboundNumbers = {
|
|
409
|
+
get: async (signal) => rememberOutbound(toOutboundSettings(await get(`${base}/outbound-numbers`, org, signal))),
|
|
410
|
+
// `null` = back to the org default: the empty id is dropped from the query, which the backend reads that way.
|
|
411
|
+
setMine: async (id) => {
|
|
412
|
+
try {
|
|
413
|
+
return rememberOutbound(
|
|
414
|
+
toOutboundSettings(await post(`${base}/outbound-numbers/user`, { ...org, did_id: id ?? "" }))
|
|
415
|
+
);
|
|
416
|
+
} catch (error) {
|
|
417
|
+
const body = error instanceof ApiError ? error.body : null;
|
|
418
|
+
if (error instanceof ApiError && error.status === 429 && body?.code === "rate_limited") {
|
|
419
|
+
throw outboundNumberRefused({
|
|
420
|
+
reason: body.reason === "user" ? "user" : "platform",
|
|
421
|
+
retryAfterSeconds: Math.max(1, Math.ceil(Number(body.retryAfterSeconds) || 1))
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
throw error;
|
|
425
|
+
}
|
|
426
|
+
},
|
|
427
|
+
cached: recallOutbound
|
|
428
|
+
};
|
|
362
429
|
const contacts = config.contacts ?? coventiaContacts;
|
|
363
430
|
const resolve = config.resolveContact ?? (config.contacts ? resolverFromContacts(config.contacts) : coventiaResolve);
|
|
364
431
|
const history = withNameResolution(rawHistory, resolve);
|
|
@@ -371,10 +438,11 @@ function coventiaSources(config) {
|
|
|
371
438
|
listAgents: coventiaListAgents,
|
|
372
439
|
transferOutcomes,
|
|
373
440
|
presence,
|
|
374
|
-
ringtones
|
|
441
|
+
ringtones,
|
|
442
|
+
outboundNumbers
|
|
375
443
|
};
|
|
376
444
|
}
|
|
377
445
|
|
|
378
446
|
export { coventiaSources, resolverFromContacts };
|
|
379
|
-
//# sourceMappingURL=sources-
|
|
380
|
-
//# sourceMappingURL=sources-
|
|
447
|
+
//# sourceMappingURL=sources-ONYQW733.js.map
|
|
448
|
+
//# sourceMappingURL=sources-ONYQW733.js.map
|