@edvak99/voice-receptionist-widget 1.1.11 → 1.1.13
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/README.md +23 -14
- package/fesm2022/{edvak99-voice-receptionist-widget-activities-page.component-CACfxM4x.mjs → edvak99-voice-receptionist-widget-activities-page.component-Br2Vi1Im.mjs} +3 -4
- package/fesm2022/edvak99-voice-receptionist-widget-activities-page.component-Br2Vi1Im.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-analytics-page.component-Dj9vw97B.mjs → edvak99-voice-receptionist-widget-analytics-page.component-CglgGV6H.mjs} +2 -3
- package/fesm2022/edvak99-voice-receptionist-widget-analytics-page.component-CglgGV6H.mjs.map +1 -0
- package/fesm2022/edvak99-voice-receptionist-widget-api-log.util-C0TOKF1q.mjs.map +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-api-logs-page.component-jKBA1N2A.mjs → edvak99-voice-receptionist-widget-api-logs-page.component-DPJiuNjk.mjs} +7 -6
- package/fesm2022/edvak99-voice-receptionist-widget-api-logs-page.component-DPJiuNjk.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-api-logs-table.component-CEf4NPe5.mjs → edvak99-voice-receptionist-widget-api-logs-table.component-CiNc65dO.mjs} +2 -3
- package/fesm2022/edvak99-voice-receptionist-widget-api-logs-table.component-CiNc65dO.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-call-history-detail-page.component-DEplWBbz.mjs → edvak99-voice-receptionist-widget-call-history-detail-page.component-ENq2c-sm.mjs} +5 -7
- package/fesm2022/edvak99-voice-receptionist-widget-call-history-detail-page.component-ENq2c-sm.mjs.map +1 -0
- package/fesm2022/edvak99-voice-receptionist-widget-call-history-page.component-DoYJFpSa.mjs +200 -0
- package/fesm2022/edvak99-voice-receptionist-widget-call-history-page.component-DoYJFpSa.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-call-recording-player.component-j1mY5wU0.mjs → edvak99-voice-receptionist-widget-call-recording-player.component-GVg1g-Vq.mjs} +2 -3
- package/fesm2022/edvak99-voice-receptionist-widget-call-recording-player.component-GVg1g-Vq.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-call-review.service-DQ4TT_Su.mjs → edvak99-voice-receptionist-widget-call-review.service-WG30w6Jl.mjs} +2 -2
- package/fesm2022/edvak99-voice-receptionist-widget-call-review.service-WG30w6Jl.mjs.map +1 -0
- package/fesm2022/edvak99-voice-receptionist-widget-call-review.util-Deh3jPgo.mjs.map +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-dashboard-page.component-DPxQ-wst.mjs → edvak99-voice-receptionist-widget-dashboard-page.component-B_EYljRs.mjs} +4 -5
- package/fesm2022/edvak99-voice-receptionist-widget-dashboard-page.component-B_EYljRs.mjs.map +1 -0
- package/fesm2022/edvak99-voice-receptionist-widget-eds-avatar.component-BJs_TH8X.mjs.map +1 -1
- package/fesm2022/edvak99-voice-receptionist-widget-eds-elapsed.pipe-BFCiJOT3.mjs.map +1 -1
- package/fesm2022/edvak99-voice-receptionist-widget-eds-pulse-dot.component-B8yxY-7p.mjs +14 -0
- package/fesm2022/edvak99-voice-receptionist-widget-eds-pulse-dot.component-B8yxY-7p.mjs.map +1 -0
- package/fesm2022/edvak99-voice-receptionist-widget-eds-search-field.component-OGRDvYBp.mjs +83 -0
- package/fesm2022/edvak99-voice-receptionist-widget-eds-search-field.component-OGRDvYBp.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-ai-receptionist-api.service-DcRiHn8q.mjs → edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-pS2jeB4x.mjs} +612 -8
- package/fesm2022/edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-pS2jeB4x.mjs.map +1 -0
- package/fesm2022/edvak99-voice-receptionist-widget-live-calls-page.component-1woGuh0J.mjs +74 -0
- package/fesm2022/edvak99-voice-receptionist-widget-live-calls-page.component-1woGuh0J.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-live-monitor-page.component-BOQeTD3P.mjs → edvak99-voice-receptionist-widget-live-monitor-page.component-ihwm1LNn.mjs} +5 -7
- package/fesm2022/edvak99-voice-receptionist-widget-live-monitor-page.component-ihwm1LNn.mjs.map +1 -0
- package/fesm2022/edvak99-voice-receptionist-widget-modal.component-uYApl1KF.mjs.map +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-outbound-purposes-page.component-D407n7l0.mjs → edvak99-voice-receptionist-widget-outbound-purposes-page.component-B2koBFU3.mjs} +2 -3
- package/fesm2022/edvak99-voice-receptionist-widget-outbound-purposes-page.component-B2koBFU3.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-settings-page.component-YAvQ_XV6.mjs → edvak99-voice-receptionist-widget-settings-page.component-C6F-Hgmk.mjs} +2 -3
- package/fesm2022/edvak99-voice-receptionist-widget-settings-page.component-C6F-Hgmk.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-task-detail-drawer.component-B3KmFJNH.mjs → edvak99-voice-receptionist-widget-task-detail-drawer.component-BojdiNNx.mjs} +2 -2
- package/fesm2022/edvak99-voice-receptionist-widget-task-detail-drawer.component-BojdiNNx.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-tasks-page.component-BIOGiTgM.mjs → edvak99-voice-receptionist-widget-tasks-page.component-Cf76XyCz.mjs} +3 -4
- package/fesm2022/edvak99-voice-receptionist-widget-tasks-page.component-Cf76XyCz.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-wizard-page.component-DpF6y1go.mjs → edvak99-voice-receptionist-widget-wizard-page.component-BQTlz2F5.mjs} +2 -3
- package/fesm2022/edvak99-voice-receptionist-widget-wizard-page.component-BQTlz2F5.mjs.map +1 -0
- package/fesm2022/edvak99-voice-receptionist-widget.mjs +1 -262
- package/fesm2022/edvak99-voice-receptionist-widget.mjs.map +1 -1
- package/lib/layout/eds-app-shell.component.d.ts +5 -0
- package/lib/layout/eds-route-progress.component.d.ts +15 -0
- package/lib/models/ai-receptionist.types.d.ts +2 -0
- package/lib/models/api-dto.types.d.ts +2 -0
- package/lib/pages/live-calls-page/live-calls-page.component.d.ts +1 -4
- package/lib/pages/live-calls-page/live-calls-shell.component.d.ts +13 -0
- package/lib/services/live-calls-list.service.d.ts +2 -0
- package/lib/ui/eds-search-field.component.d.ts +22 -0
- package/lib/utils/call-history-display.util.d.ts +1 -0
- package/package.json +1 -1
- package/public-api.d.ts +1 -0
- package/fesm2022/edvak99-voice-receptionist-widget-activities-page.component-CACfxM4x.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-ai-receptionist-api.service-DcRiHn8q.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-analytics-page.component-Dj9vw97B.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-api-logs-page.component-jKBA1N2A.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-api-logs-table.component-CEf4NPe5.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-call-history-detail-page.component-DEplWBbz.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-call-history-page.component-CkjKCteR.mjs +0 -193
- package/fesm2022/edvak99-voice-receptionist-widget-call-history-page.component-CkjKCteR.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-call-recording-player.component-j1mY5wU0.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-call-review.service-DQ4TT_Su.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-dashboard-page.component-DPxQ-wst.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-dashboard-socket.service-tTQIsZO6.mjs +0 -120
- package/fesm2022/edvak99-voice-receptionist-widget-dashboard-socket.service-tTQIsZO6.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-eds-pulse-dot.component-CUWZfYRR.mjs +0 -130
- package/fesm2022/edvak99-voice-receptionist-widget-eds-pulse-dot.component-CUWZfYRR.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-live-calls-page.component-BG9cB3zW.mjs +0 -81
- package/fesm2022/edvak99-voice-receptionist-widget-live-calls-page.component-BG9cB3zW.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-live-monitor-page.component-BOQeTD3P.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-outbound-purposes-page.component-D407n7l0.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-settings-page.component-YAvQ_XV6.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-task-detail-drawer.component-B3KmFJNH.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-tasks-page.component-BIOGiTgM.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-wizard-page.component-DpF6y1go.mjs.map +0 -1
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, signal, Injectable, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
|
-
import { interval, filter, switchMap, catchError, of } from 'rxjs';
|
|
4
|
-
import { VOICE_RECEPTIONIST_CONFIG } from './edvak99-voice-receptionist-widget.mjs';
|
|
5
|
-
import { A as AiReceptionistApiService } from './edvak99-voice-receptionist-widget-ai-receptionist-api.service-DcRiHn8q.mjs';
|
|
6
|
-
import { D as DashboardSocketService } from './edvak99-voice-receptionist-widget-dashboard-socket.service-tTQIsZO6.mjs';
|
|
7
|
-
|
|
8
|
-
const DEFAULT_POLL_MS = 12_000;
|
|
9
|
-
/**
|
|
10
|
-
* Shared live calls list — REST + `live_calls_updated` socket + fallback poll.
|
|
11
|
-
*/
|
|
12
|
-
class LiveCallsListService {
|
|
13
|
-
constructor() {
|
|
14
|
-
this.api = inject(AiReceptionistApiService);
|
|
15
|
-
this.socket = inject(DashboardSocketService);
|
|
16
|
-
this.config = inject(VOICE_RECEPTIONIST_CONFIG);
|
|
17
|
-
this.calls = signal([]);
|
|
18
|
-
this.loading = signal(false);
|
|
19
|
-
this.error = signal(null);
|
|
20
|
-
this.lastUpdated = signal(null);
|
|
21
|
-
this.subscriberCount = 0;
|
|
22
|
-
this.mockPollTimer = null;
|
|
23
|
-
this.onLiveCallsUpdated = () => this.refresh(false);
|
|
24
|
-
this.onSocketConnect = () => this.refresh(false);
|
|
25
|
-
}
|
|
26
|
-
start() {
|
|
27
|
-
this.subscriberCount++;
|
|
28
|
-
if (this.subscriberCount > 1) {
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
this.socket.acquire();
|
|
32
|
-
this.socket.on('live_calls_updated', this.onLiveCallsUpdated);
|
|
33
|
-
this.socket.onConnect(this.onSocketConnect);
|
|
34
|
-
this.bindVisibility();
|
|
35
|
-
this.refresh(true);
|
|
36
|
-
this.startFallbackPoll();
|
|
37
|
-
}
|
|
38
|
-
stop() {
|
|
39
|
-
this.subscriberCount = Math.max(0, this.subscriberCount - 1);
|
|
40
|
-
if (this.subscriberCount > 0) {
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
this.stopFallbackPoll();
|
|
44
|
-
this.unbindVisibility();
|
|
45
|
-
this.socket.off('live_calls_updated', this.onLiveCallsUpdated);
|
|
46
|
-
this.socket.offConnect(this.onSocketConnect);
|
|
47
|
-
this.socket.release();
|
|
48
|
-
}
|
|
49
|
-
refresh(showLoading = true) {
|
|
50
|
-
if (showLoading && this.calls().length === 0) {
|
|
51
|
-
this.loading.set(true);
|
|
52
|
-
}
|
|
53
|
-
this.api.getLiveCalls().subscribe({
|
|
54
|
-
next: ({ data }) => {
|
|
55
|
-
this.calls.set(data);
|
|
56
|
-
this.lastUpdated.set(Date.now());
|
|
57
|
-
this.loading.set(false);
|
|
58
|
-
this.error.set(null);
|
|
59
|
-
},
|
|
60
|
-
error: (err) => {
|
|
61
|
-
this.loading.set(false);
|
|
62
|
-
const message = err instanceof Error ? err.message : 'Could not load live calls.';
|
|
63
|
-
this.error.set(message);
|
|
64
|
-
},
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
startFallbackPoll() {
|
|
68
|
-
const pollMs = this.config.liveCallsPollIntervalMs ?? DEFAULT_POLL_MS;
|
|
69
|
-
if (this.config.useMockApi) {
|
|
70
|
-
this.mockPollTimer = setInterval(() => {
|
|
71
|
-
if (!document.hidden) {
|
|
72
|
-
this.refresh(false);
|
|
73
|
-
}
|
|
74
|
-
}, pollMs);
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
this.pollSub = interval(pollMs)
|
|
78
|
-
.pipe(filter(() => !document.hidden), switchMap(() => this.api.getLiveCalls().pipe(catchError(() => {
|
|
79
|
-
this.error.set('Live calls refresh failed.');
|
|
80
|
-
return of(null);
|
|
81
|
-
}))))
|
|
82
|
-
.subscribe((result) => {
|
|
83
|
-
if (!result)
|
|
84
|
-
return;
|
|
85
|
-
this.calls.set(result.data);
|
|
86
|
-
this.lastUpdated.set(Date.now());
|
|
87
|
-
this.error.set(null);
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
stopFallbackPoll() {
|
|
91
|
-
this.pollSub?.unsubscribe();
|
|
92
|
-
this.pollSub = undefined;
|
|
93
|
-
if (this.mockPollTimer) {
|
|
94
|
-
clearInterval(this.mockPollTimer);
|
|
95
|
-
this.mockPollTimer = null;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
bindVisibility() {
|
|
99
|
-
this.visibilityHandler = () => {
|
|
100
|
-
if (!document.hidden) {
|
|
101
|
-
this.refresh(false);
|
|
102
|
-
}
|
|
103
|
-
};
|
|
104
|
-
document.addEventListener('visibilitychange', this.visibilityHandler);
|
|
105
|
-
}
|
|
106
|
-
unbindVisibility() {
|
|
107
|
-
if (this.visibilityHandler) {
|
|
108
|
-
document.removeEventListener('visibilitychange', this.visibilityHandler);
|
|
109
|
-
this.visibilityHandler = undefined;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: LiveCallsListService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
113
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: LiveCallsListService, providedIn: 'root' }); }
|
|
114
|
-
}
|
|
115
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: LiveCallsListService, decorators: [{
|
|
116
|
-
type: Injectable,
|
|
117
|
-
args: [{ providedIn: 'root' }]
|
|
118
|
-
}] });
|
|
119
|
-
|
|
120
|
-
class EdsPulseDotComponent {
|
|
121
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: EdsPulseDotComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
122
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: EdsPulseDotComponent, isStandalone: true, selector: "eds-pulse-dot", ngImport: i0, template: `<span class="eds-pulse-dot relative inline-flex h-2 w-2"><span class="eds-pulse-dot__core h-2 w-2 rounded-full"></span></span>`, isInline: true, styles: [".eds-pulse-dot__core{background:var(--eds-green-500)}.eds-pulse-dot__core:after{content:\"\";position:absolute;inset:0;border-radius:50%;background:var(--eds-green-500);animation:eds-ping 1.4s cubic-bezier(0,0,.2,1) infinite}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
123
|
-
}
|
|
124
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: EdsPulseDotComponent, decorators: [{
|
|
125
|
-
type: Component,
|
|
126
|
-
args: [{ selector: 'eds-pulse-dot', standalone: true, template: `<span class="eds-pulse-dot relative inline-flex h-2 w-2"><span class="eds-pulse-dot__core h-2 w-2 rounded-full"></span></span>`, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".eds-pulse-dot__core{background:var(--eds-green-500)}.eds-pulse-dot__core:after{content:\"\";position:absolute;inset:0;border-radius:50%;background:var(--eds-green-500);animation:eds-ping 1.4s cubic-bezier(0,0,.2,1) infinite}\n"] }]
|
|
127
|
-
}] });
|
|
128
|
-
|
|
129
|
-
export { EdsPulseDotComponent as E, LiveCallsListService as L };
|
|
130
|
-
//# sourceMappingURL=edvak99-voice-receptionist-widget-eds-pulse-dot.component-CUWZfYRR.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"edvak99-voice-receptionist-widget-eds-pulse-dot.component-CUWZfYRR.mjs","sources":["../../../projects/voice-receptionist-widget/src/lib/services/live-calls-list.service.ts","../../../projects/voice-receptionist-widget/src/lib/ui/eds-pulse-dot.component.ts"],"sourcesContent":["import { Injectable, inject, signal } from '@angular/core';\nimport { Subscription, catchError, filter, interval, of, switchMap } from 'rxjs';\n\nimport { VOICE_RECEPTIONIST_CONFIG } from '../config';\nimport { LiveCall } from '../models/ai-receptionist.types';\nimport { AiReceptionistApiService } from './ai-receptionist-api.service';\nimport { DashboardSocketService } from './dashboard-socket.service';\n\nconst DEFAULT_POLL_MS = 12_000;\n\n/**\n * Shared live calls list — REST + `live_calls_updated` socket + fallback poll.\n */\n@Injectable({ providedIn: 'root' })\nexport class LiveCallsListService {\n private readonly api = inject(AiReceptionistApiService);\n private readonly socket = inject(DashboardSocketService);\n private readonly config = inject(VOICE_RECEPTIONIST_CONFIG);\n\n readonly calls = signal<LiveCall[]>([]);\n readonly loading = signal(false);\n readonly error = signal<string | null>(null);\n readonly lastUpdated = signal<number | null>(null);\n\n private subscriberCount = 0;\n private pollSub?: Subscription;\n private visibilityHandler?: () => void;\n private mockPollTimer: ReturnType<typeof setInterval> | null = null;\n\n private readonly onLiveCallsUpdated = () => this.refresh(false);\n private readonly onSocketConnect = () => this.refresh(false);\n\n start(): void {\n this.subscriberCount++;\n if (this.subscriberCount > 1) {\n return;\n }\n\n this.socket.acquire();\n this.socket.on('live_calls_updated', this.onLiveCallsUpdated);\n this.socket.onConnect(this.onSocketConnect);\n this.bindVisibility();\n this.refresh(true);\n this.startFallbackPoll();\n }\n\n stop(): void {\n this.subscriberCount = Math.max(0, this.subscriberCount - 1);\n if (this.subscriberCount > 0) {\n return;\n }\n\n this.stopFallbackPoll();\n this.unbindVisibility();\n this.socket.off('live_calls_updated', this.onLiveCallsUpdated);\n this.socket.offConnect(this.onSocketConnect);\n this.socket.release();\n }\n\n refresh(showLoading = true): void {\n if (showLoading && this.calls().length === 0) {\n this.loading.set(true);\n }\n\n this.api.getLiveCalls().subscribe({\n next: ({ data }) => {\n this.calls.set(data);\n this.lastUpdated.set(Date.now());\n this.loading.set(false);\n this.error.set(null);\n },\n error: (err: unknown) => {\n this.loading.set(false);\n const message =\n err instanceof Error ? err.message : 'Could not load live calls.';\n this.error.set(message);\n },\n });\n }\n\n private startFallbackPoll(): void {\n const pollMs = this.config.liveCallsPollIntervalMs ?? DEFAULT_POLL_MS;\n\n if (this.config.useMockApi) {\n this.mockPollTimer = setInterval(() => {\n if (!document.hidden) {\n this.refresh(false);\n }\n }, pollMs);\n return;\n }\n\n this.pollSub = interval(pollMs)\n .pipe(\n filter(() => !document.hidden),\n switchMap(() =>\n this.api.getLiveCalls().pipe(\n catchError(() => {\n this.error.set('Live calls refresh failed.');\n return of(null);\n }),\n ),\n ),\n )\n .subscribe((result) => {\n if (!result) return;\n this.calls.set(result.data);\n this.lastUpdated.set(Date.now());\n this.error.set(null);\n });\n }\n\n private stopFallbackPoll(): void {\n this.pollSub?.unsubscribe();\n this.pollSub = undefined;\n if (this.mockPollTimer) {\n clearInterval(this.mockPollTimer);\n this.mockPollTimer = null;\n }\n }\n\n private bindVisibility(): void {\n this.visibilityHandler = () => {\n if (!document.hidden) {\n this.refresh(false);\n }\n };\n document.addEventListener('visibilitychange', this.visibilityHandler);\n }\n\n private unbindVisibility(): void {\n if (this.visibilityHandler) {\n document.removeEventListener('visibilitychange', this.visibilityHandler);\n this.visibilityHandler = undefined;\n }\n }\n}\n","import { ChangeDetectionStrategy, Component } from '@angular/core';\n\n@Component({\n selector: 'eds-pulse-dot',\n standalone: true,\n template: `<span class=\"eds-pulse-dot relative inline-flex h-2 w-2\"><span class=\"eds-pulse-dot__core h-2 w-2 rounded-full\"></span></span>`,\n styleUrl: './eds-pulse-dot.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class EdsPulseDotComponent {}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, computed, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
|
-
import { Router, ActivatedRoute } from '@angular/router';
|
|
4
|
-
import { L as LiveCallsListService, E as EdsPulseDotComponent } from './edvak99-voice-receptionist-widget-eds-pulse-dot.component-CUWZfYRR.mjs';
|
|
5
|
-
import { c as callerMetaLine, d as ageFromDob, i as isUnknownCaller } from './edvak99-voice-receptionist-widget-ai-receptionist-api.service-DcRiHn8q.mjs';
|
|
6
|
-
import { E as EdsAvatarComponent } from './edvak99-voice-receptionist-widget-eds-avatar.component-BJs_TH8X.mjs';
|
|
7
|
-
import { EdsIconComponent } from './edvak99-voice-receptionist-widget.mjs';
|
|
8
|
-
|
|
9
|
-
class LiveCallsPageComponent {
|
|
10
|
-
constructor() {
|
|
11
|
-
this.router = inject(Router);
|
|
12
|
-
this.route = inject(ActivatedRoute);
|
|
13
|
-
this.liveCallsList = inject(LiveCallsListService);
|
|
14
|
-
this.calls = this.liveCallsList.calls;
|
|
15
|
-
this.loading = this.liveCallsList.loading;
|
|
16
|
-
this.error = this.liveCallsList.error;
|
|
17
|
-
this.emptyState = computed(() => {
|
|
18
|
-
if (this.calls().length > 0)
|
|
19
|
-
return null;
|
|
20
|
-
return {
|
|
21
|
-
title: 'No active calls right now',
|
|
22
|
-
detail: 'When a patient calls your practice, their conversation will appear here for real-time monitoring.',
|
|
23
|
-
icon: 'phone_disabled',
|
|
24
|
-
};
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
ngOnInit() {
|
|
28
|
-
this.liveCallsList.start();
|
|
29
|
-
}
|
|
30
|
-
ngOnDestroy() {
|
|
31
|
-
this.liveCallsList.stop();
|
|
32
|
-
}
|
|
33
|
-
openMonitor(id) {
|
|
34
|
-
void this.router.navigate(['../live', id], { relativeTo: this.route });
|
|
35
|
-
}
|
|
36
|
-
displayName(call) {
|
|
37
|
-
return this.isUnknown(call) ? 'Unknown Caller' : call.name.trim();
|
|
38
|
-
}
|
|
39
|
-
displayMeta(call) {
|
|
40
|
-
return callerMetaLine({
|
|
41
|
-
name: call.name,
|
|
42
|
-
matched: call.matched,
|
|
43
|
-
phone: call.phone,
|
|
44
|
-
dob: call.dob,
|
|
45
|
-
age: call.age ?? ageFromDob(call.dob),
|
|
46
|
-
gender: call.gender,
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
isUnknown(call) {
|
|
50
|
-
return isUnknownCaller(call.name, call.matched);
|
|
51
|
-
}
|
|
52
|
-
sentimentLabel(sentiment) {
|
|
53
|
-
const key = String(sentiment ?? 'neutral').toLowerCase();
|
|
54
|
-
switch (key) {
|
|
55
|
-
case 'calm':
|
|
56
|
-
return 'Calm';
|
|
57
|
-
case 'frustrated':
|
|
58
|
-
return 'Frustrated';
|
|
59
|
-
case 'urgent':
|
|
60
|
-
return 'Urgent';
|
|
61
|
-
case 'neutral':
|
|
62
|
-
default:
|
|
63
|
-
return 'Neutral';
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
avatarInitials(call) {
|
|
67
|
-
return this.isUnknown(call) ? '?' : call.initials || '?';
|
|
68
|
-
}
|
|
69
|
-
avatarTone(call) {
|
|
70
|
-
return this.isUnknown(call) ? 'gray' : 'brand';
|
|
71
|
-
}
|
|
72
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: LiveCallsPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
73
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: LiveCallsPageComponent, isStandalone: true, selector: "eds-live-calls-page", ngImport: i0, template: "<div class=\"eds-page live-calls-page\">\n <header class=\"mb-5 flex items-center justify-between\">\n <div>\n <h1 class=\"eds-h1\">Live Calls</h1>\n <p class=\"eds-body-sm\">Monitor active conversations in real time</p>\n </div>\n <eds-pulse-dot />\n </header>\n\n @if (error()) {\n <p class=\"eds-body-sm mb-3 text-sm text-red-600\" role=\"alert\">{{ error() }}</p>\n }\n\n @if (loading()) {\n <p class=\"eds-body-sm\">Loading live calls\u2026</p>\n } @else {\n <div class=\"flex w-1/2 min-w-80 max-w-1/2 flex-col gap-3\">\n @for (call of calls(); track call.id) {\n <button\n type=\"button\"\n class=\"flex w-full cursor-pointer items-center gap-3 rounded-xl border border-zinc-200 bg-white px-4 py-4 text-left transition hover:border-slate-300 hover:shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-blue-600 focus-visible:outline-offset-2\"\n (click)=\"openMonitor(call.id)\"\n >\n <eds-avatar\n class=\"live-calls-page__avatar shrink-0\"\n [initials]=\"avatarInitials(call)\"\n [tone]=\"avatarTone(call)\"\n />\n <div class=\"flex min-w-0 flex-1 flex-col gap-1\">\n <span class=\"text-sm font-bold text-zinc-700\">{{ displayName(call) }}</span>\n <span class=\"text-xs text-zinc-600\">{{ displayMeta(call) }}</span>\n </div>\n <span\n class=\"live-calls-page__sentiment shrink-0 text-xs font-semibold capitalize whitespace-nowrap text-zinc-600\"\n [attr.data-sentiment]=\"call.sentiment\"\n >\n {{ sentimentLabel(call.sentiment) }}\n </span>\n </button>\n } @empty {\n @if (emptyState(); as state) {\n <div class=\"eds-card flex flex-col items-center gap-2 px-6 py-12 text-center text-zinc-500 shadow-sm\" role=\"status\">\n <eds-icon [name]=\"state.icon\" [size]=\"32\" />\n <p class=\"eds-h2 mb-2 text-zinc-800\">{{ state.title }}</p>\n <p class=\"eds-body-sm m-0 max-w-md\">{{ state.detail }}</p>\n </div>\n }\n }\n </div>\n }\n</div>\n", styles: [".live-calls-page__avatar ::ng-deep .eds-avatar{width:40px;height:40px;border-radius:10px;font-size:13px}.live-calls-page__avatar ::ng-deep .eds-avatar[data-tone=brand]{background:#fef3c7;color:#92400e}.live-calls-page__sentiment[data-sentiment=calm]{color:#16a34a}.live-calls-page__sentiment[data-sentiment=neutral]{color:#71717a}.live-calls-page__sentiment[data-sentiment=frustrated]{color:#d97706}.live-calls-page__sentiment[data-sentiment=urgent]{color:#dc2626}\n"], dependencies: [{ kind: "component", type: EdsAvatarComponent, selector: "eds-avatar", inputs: ["initials", "tone", "shape", "gradient"] }, { kind: "component", type: EdsIconComponent, selector: "eds-icon", inputs: ["name", "size", "fill", "weight"] }, { kind: "component", type: EdsPulseDotComponent, selector: "eds-pulse-dot" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
74
|
-
}
|
|
75
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: LiveCallsPageComponent, decorators: [{
|
|
76
|
-
type: Component,
|
|
77
|
-
args: [{ selector: 'eds-live-calls-page', imports: [EdsAvatarComponent, EdsIconComponent, EdsPulseDotComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"eds-page live-calls-page\">\n <header class=\"mb-5 flex items-center justify-between\">\n <div>\n <h1 class=\"eds-h1\">Live Calls</h1>\n <p class=\"eds-body-sm\">Monitor active conversations in real time</p>\n </div>\n <eds-pulse-dot />\n </header>\n\n @if (error()) {\n <p class=\"eds-body-sm mb-3 text-sm text-red-600\" role=\"alert\">{{ error() }}</p>\n }\n\n @if (loading()) {\n <p class=\"eds-body-sm\">Loading live calls\u2026</p>\n } @else {\n <div class=\"flex w-1/2 min-w-80 max-w-1/2 flex-col gap-3\">\n @for (call of calls(); track call.id) {\n <button\n type=\"button\"\n class=\"flex w-full cursor-pointer items-center gap-3 rounded-xl border border-zinc-200 bg-white px-4 py-4 text-left transition hover:border-slate-300 hover:shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-blue-600 focus-visible:outline-offset-2\"\n (click)=\"openMonitor(call.id)\"\n >\n <eds-avatar\n class=\"live-calls-page__avatar shrink-0\"\n [initials]=\"avatarInitials(call)\"\n [tone]=\"avatarTone(call)\"\n />\n <div class=\"flex min-w-0 flex-1 flex-col gap-1\">\n <span class=\"text-sm font-bold text-zinc-700\">{{ displayName(call) }}</span>\n <span class=\"text-xs text-zinc-600\">{{ displayMeta(call) }}</span>\n </div>\n <span\n class=\"live-calls-page__sentiment shrink-0 text-xs font-semibold capitalize whitespace-nowrap text-zinc-600\"\n [attr.data-sentiment]=\"call.sentiment\"\n >\n {{ sentimentLabel(call.sentiment) }}\n </span>\n </button>\n } @empty {\n @if (emptyState(); as state) {\n <div class=\"eds-card flex flex-col items-center gap-2 px-6 py-12 text-center text-zinc-500 shadow-sm\" role=\"status\">\n <eds-icon [name]=\"state.icon\" [size]=\"32\" />\n <p class=\"eds-h2 mb-2 text-zinc-800\">{{ state.title }}</p>\n <p class=\"eds-body-sm m-0 max-w-md\">{{ state.detail }}</p>\n </div>\n }\n }\n </div>\n }\n</div>\n", styles: [".live-calls-page__avatar ::ng-deep .eds-avatar{width:40px;height:40px;border-radius:10px;font-size:13px}.live-calls-page__avatar ::ng-deep .eds-avatar[data-tone=brand]{background:#fef3c7;color:#92400e}.live-calls-page__sentiment[data-sentiment=calm]{color:#16a34a}.live-calls-page__sentiment[data-sentiment=neutral]{color:#71717a}.live-calls-page__sentiment[data-sentiment=frustrated]{color:#d97706}.live-calls-page__sentiment[data-sentiment=urgent]{color:#dc2626}\n"] }]
|
|
78
|
-
}] });
|
|
79
|
-
|
|
80
|
-
export { LiveCallsPageComponent };
|
|
81
|
-
//# sourceMappingURL=edvak99-voice-receptionist-widget-live-calls-page.component-BG9cB3zW.mjs.map
|
package/fesm2022/edvak99-voice-receptionist-widget-live-calls-page.component-BG9cB3zW.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"edvak99-voice-receptionist-widget-live-calls-page.component-BG9cB3zW.mjs","sources":["../../../projects/voice-receptionist-widget/src/lib/pages/live-calls-page/live-calls-page.component.ts","../../../projects/voice-receptionist-widget/src/lib/pages/live-calls-page/live-calls-page.component.html"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n computed,\n inject,\n OnDestroy,\n OnInit,\n} from '@angular/core';\nimport { ActivatedRoute, Router } from '@angular/router';\n\nimport { LiveCall, Sentiment } from '../../models/ai-receptionist.types';\nimport { LiveCallsListService } from '../../services/live-calls-list.service';\nimport {\n ageFromDob,\n callerMetaLine,\n isUnknownCaller,\n} from '../../utils/call-history-display.util';\nimport { EdsAvatarComponent } from '../../ui/eds-avatar.component';\nimport { EdsIconComponent } from '../../ui/eds-icon.component';\nimport { EdsPulseDotComponent } from '../../ui/eds-pulse-dot.component';\n\n@Component({\n selector: 'eds-live-calls-page',\n imports: [EdsAvatarComponent, EdsIconComponent, EdsPulseDotComponent],\n templateUrl: './live-calls-page.component.html',\n styleUrl: './live-calls-page.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class LiveCallsPageComponent implements OnInit, OnDestroy {\n private readonly router = inject(Router);\n private readonly route = inject(ActivatedRoute);\n private readonly liveCallsList = inject(LiveCallsListService);\n\n protected readonly calls = this.liveCallsList.calls;\n protected readonly loading = this.liveCallsList.loading;\n protected readonly error = this.liveCallsList.error;\n\n protected readonly emptyState = computed(() => {\n if (this.calls().length > 0) return null;\n return {\n title: 'No active calls right now',\n detail:\n 'When a patient calls your practice, their conversation will appear here for real-time monitoring.',\n icon: 'phone_disabled',\n };\n });\n\n ngOnInit(): void {\n this.liveCallsList.start();\n }\n\n ngOnDestroy(): void {\n this.liveCallsList.stop();\n }\n\n protected openMonitor(id: string): void {\n void this.router.navigate(['../live', id], { relativeTo: this.route });\n }\n\n protected displayName(call: LiveCall): string {\n return this.isUnknown(call) ? 'Unknown Caller' : call.name.trim();\n }\n\n protected displayMeta(call: LiveCall): string {\n return callerMetaLine({\n name: call.name,\n matched: call.matched,\n phone: call.phone,\n dob: call.dob,\n age: call.age ?? ageFromDob(call.dob),\n gender: call.gender,\n });\n }\n\n protected isUnknown(call: LiveCall): boolean {\n return isUnknownCaller(call.name, call.matched);\n }\n\n protected sentimentLabel(sentiment: Sentiment | string | null | undefined): string {\n const key = String(sentiment ?? 'neutral').toLowerCase();\n switch (key) {\n case 'calm':\n return 'Calm';\n case 'frustrated':\n return 'Frustrated';\n case 'urgent':\n return 'Urgent';\n case 'neutral':\n default:\n return 'Neutral';\n }\n }\n\n protected avatarInitials(call: LiveCall): string {\n return this.isUnknown(call) ? '?' : call.initials || '?';\n }\n\n protected avatarTone(call: LiveCall): 'gray' | 'brand' {\n return this.isUnknown(call) ? 'gray' : 'brand';\n }\n}\n","<div class=\"eds-page live-calls-page\">\n <header class=\"mb-5 flex items-center justify-between\">\n <div>\n <h1 class=\"eds-h1\">Live Calls</h1>\n <p class=\"eds-body-sm\">Monitor active conversations in real time</p>\n </div>\n <eds-pulse-dot />\n </header>\n\n @if (error()) {\n <p class=\"eds-body-sm mb-3 text-sm text-red-600\" role=\"alert\">{{ error() }}</p>\n }\n\n @if (loading()) {\n <p class=\"eds-body-sm\">Loading live calls…</p>\n } @else {\n <div class=\"flex w-1/2 min-w-80 max-w-1/2 flex-col gap-3\">\n @for (call of calls(); track call.id) {\n <button\n type=\"button\"\n class=\"flex w-full cursor-pointer items-center gap-3 rounded-xl border border-zinc-200 bg-white px-4 py-4 text-left transition hover:border-slate-300 hover:shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-blue-600 focus-visible:outline-offset-2\"\n (click)=\"openMonitor(call.id)\"\n >\n <eds-avatar\n class=\"live-calls-page__avatar shrink-0\"\n [initials]=\"avatarInitials(call)\"\n [tone]=\"avatarTone(call)\"\n />\n <div class=\"flex min-w-0 flex-1 flex-col gap-1\">\n <span class=\"text-sm font-bold text-zinc-700\">{{ displayName(call) }}</span>\n <span class=\"text-xs text-zinc-600\">{{ displayMeta(call) }}</span>\n </div>\n <span\n class=\"live-calls-page__sentiment shrink-0 text-xs font-semibold capitalize whitespace-nowrap text-zinc-600\"\n [attr.data-sentiment]=\"call.sentiment\"\n >\n {{ sentimentLabel(call.sentiment) }}\n </span>\n </button>\n } @empty {\n @if (emptyState(); as state) {\n <div class=\"eds-card flex flex-col items-center gap-2 px-6 py-12 text-center text-zinc-500 shadow-sm\" role=\"status\">\n <eds-icon [name]=\"state.icon\" [size]=\"32\" />\n <p class=\"eds-h2 mb-2 text-zinc-800\">{{ state.title }}</p>\n <p class=\"eds-body-sm m-0 max-w-md\">{{ state.detail }}</p>\n </div>\n }\n }\n </div>\n }\n</div>\n"],"names":[],"mappings":"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"}
|
package/fesm2022/edvak99-voice-receptionist-widget-live-monitor-page.component-BOQeTD3P.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"edvak99-voice-receptionist-widget-live-monitor-page.component-BOQeTD3P.mjs","sources":["../../../projects/voice-receptionist-widget/src/lib/models/live-transcript.types.ts","../../../projects/voice-receptionist-widget/src/lib/services/live-transcript.service.ts","../../../projects/voice-receptionist-widget/src/lib/components/live-transcript-panel/live-transcript-panel.component.ts","../../../projects/voice-receptionist-widget/src/lib/components/live-transcript-panel/live-transcript-panel.component.html","../../../projects/voice-receptionist-widget/src/lib/services/staff-media.service.ts","../../../projects/voice-receptionist-widget/src/lib/pages/live-monitor-page/live-monitor-page.component.ts","../../../projects/voice-receptionist-widget/src/lib/pages/live-monitor-page/live-monitor-page.component.html"],"sourcesContent":["import { ToolEvent, TranscriptLine } from './ai-receptionist.types';\nimport { resolveToolDisplayName, resolveToolKey } from '../utils/tool-labels.util';\n\n/** Socket.io `new_chunk` payload from /dashboard namespace */\nexport interface TranscriptChunk {\n /** `staff` is a human agent speaking after a softphone takeover. */\n role: 'user' | 'assistant' | 'staff' | 'system';\n text: string;\n isFinal: boolean;\n timestamp: string;\n}\n\n/** Socket.io `call_event` payload — tools + lifecycle */\nexport interface CallEventStreamPayload {\n eventType: string;\n occurredAt: string;\n payload: Record<string, unknown>;\n}\n\nexport interface LiveTranscriptState {\n lines: TranscriptLine[];\n patientInterim: string | null;\n aiInterim: string | null;\n connected: boolean;\n error: string | null;\n}\n\nexport function mapChunkToLine(chunk: TranscriptChunk): TranscriptLine {\n const at = Date.parse(chunk.timestamp);\n return {\n who:\n chunk.role === 'staff'\n ? 'staff'\n : chunk.role === 'system'\n ? 'system'\n : chunk.role === 'assistant'\n ? 'ai'\n : 'patient',\n text: chunk.text,\n at: Number.isFinite(at) ? at : Date.now(),\n };\n}\n\nexport function formatEventTime(iso: string): string {\n return new Date(iso).toLocaleTimeString('en-US', {\n hour: 'numeric',\n minute: '2-digit',\n second: '2-digit',\n hour12: false,\n });\n}\n\nexport function mapCallEventToTool(event: CallEventStreamPayload): ToolEvent {\n const p = event.payload;\n const state = p['state'];\n const rawName = String(p['name'] ?? event.eventType.replace(/^tool_/, ''));\n const tech = String(p['tech'] ?? event.eventType);\n const key = resolveToolKey(\n p['key'] != null ? String(p['key']) : undefined,\n rawName,\n tech,\n );\n return {\n t: formatEventTime(event.occurredAt),\n key,\n name: resolveToolDisplayName(key, rawName),\n tech,\n result: String(p['result'] ?? ''),\n state:\n state === 'ok' || state === 'warn' || state === 'error' || state === 'active'\n ? state\n : 'ok',\n };\n}\n\nexport function mapLifecycleEventToTool(event: CallEventStreamPayload): ToolEvent {\n const p = event.payload;\n return {\n t: formatEventTime(event.occurredAt),\n name: event.eventType.replace(/_/g, ' '),\n tech: event.eventType,\n result: String(p['detail'] ?? p['message'] ?? p['result'] ?? ''),\n state: 'ok',\n };\n}\n\nexport function isDuplicateTranscriptLine(lines: TranscriptLine[], line: TranscriptLine): boolean {\n return lines.some((l) => l.who === line.who && l.text.trim() === line.text.trim());\n}\n","import { Injectable, inject, signal } from '@angular/core';\n\nimport { VOICE_RECEPTIONIST_CONFIG } from '../config';\nimport { ToolEvent, TranscriptLine } from '../models/ai-receptionist.types';\nimport {\n CallEventStreamPayload,\n isDuplicateTranscriptLine,\n mapCallEventToTool,\n mapChunkToLine,\n mapLifecycleEventToTool,\n TranscriptChunk,\n} from '../models/live-transcript.types';\nimport { DashboardSocketService } from './dashboard-socket.service';\n\n/**\n * Live call stream over shared Socket.io (`/dashboard` namespace).\n * REST seeds transcript/tools once; socket delivers `new_chunk` + `call_event`.\n */\n@Injectable({ providedIn: 'root' })\nexport class LiveTranscriptService {\n private readonly socket = inject(DashboardSocketService);\n private readonly config = inject(VOICE_RECEPTIONIST_CONFIG);\n\n readonly lines = signal<TranscriptLine[]>([]);\n readonly patientInterim = signal<string | null>(null);\n readonly aiInterim = signal<string | null>(null);\n readonly staffInterim = signal<string | null>(null);\n readonly tools = signal<ToolEvent[]>([]);\n readonly connected = this.socket.connected;\n readonly error = signal<string | null>(null);\n readonly callEnded = signal(false);\n readonly summaryRequested = signal(false);\n\n private activeCallId: string | null = null;\n private watching = false;\n private mockTimer: ReturnType<typeof setInterval> | null = null;\n private mockIndex = 0;\n\n private readonly chunkHandler = (chunk: TranscriptChunk) => this.handleChunk(chunk);\n private readonly eventHandler = (event: CallEventStreamPayload) => this.handleCallEvent(event);\n private readonly onSocketConnect = () => {\n if (this.activeCallId) {\n this.socket.emit('watch_call', { callId: this.activeCallId });\n }\n };\n\n seed(transcript: TranscriptLine[], toolEvents: ToolEvent[]): void {\n this.lines.set(transcript.map((line) => ({ ...line })));\n this.tools.set(toolEvents.map((tool) => ({ ...tool })));\n }\n\n watch(callId: string, live = true): void {\n const id = callId.trim();\n if (!id || !live) return;\n\n const switchingCall = this.activeCallId !== id;\n if (switchingCall) {\n this.unsubscribeSocketEvents();\n this.clearInterim();\n this.callEnded.set(false);\n this.summaryRequested.set(false);\n this.activeCallId = id;\n } else if (this.watching) {\n return;\n }\n\n if (this.config.useMockApi) {\n this.watching = true;\n this.startMockStream(id);\n return;\n }\n\n if (!this.watching) {\n this.socket.acquire();\n this.socket.on('new_chunk', this.chunkHandler);\n this.socket.on('call_event', this.eventHandler);\n this.socket.onConnect(this.onSocketConnect);\n this.watching = true;\n }\n\n if (this.socket.connected()) {\n this.socket.emit('watch_call', { callId: id });\n }\n }\n\n stop(): void {\n this.activeCallId = null;\n this.unsubscribeSocketEvents();\n this.resetStreamState();\n }\n\n markCompleted(): void {\n this.callEnded.set(true);\n this.unsubscribeSocketEvents();\n this.clearInterim();\n }\n\n private unsubscribeSocketEvents(): void {\n this.stopMockStream();\n if (!this.watching) return;\n\n this.socket.off('new_chunk', this.chunkHandler);\n this.socket.off('call_event', this.eventHandler);\n this.socket.offConnect(this.onSocketConnect);\n this.socket.release();\n this.watching = false;\n }\n\n private handleChunk(chunk: TranscriptChunk): void {\n if (!chunk?.text?.trim()) return;\n\n if (chunk.role === 'user') {\n if (chunk.isFinal) {\n this.patientInterim.set(null);\n this.appendLineIfNew(mapChunkToLine(chunk));\n } else {\n this.patientInterim.set(chunk.text);\n }\n return;\n }\n\n if (chunk.role === 'system') {\n this.appendLineIfNew(mapChunkToLine(chunk));\n return;\n }\n\n if (chunk.role === 'staff') {\n if (chunk.isFinal) {\n this.staffInterim.set(null);\n this.appendLineIfNew(mapChunkToLine(chunk));\n } else {\n this.staffInterim.set(chunk.text);\n }\n return;\n }\n\n if (chunk.isFinal) {\n this.aiInterim.set(null);\n this.appendLineIfNew(mapChunkToLine(chunk));\n } else {\n this.aiInterim.set(chunk.text);\n }\n }\n\n private handleCallEvent(event: CallEventStreamPayload): void {\n if (!event?.eventType) return;\n\n if (event.eventType.startsWith('tool_')) {\n this.tools.update((prev) => [...prev, mapCallEventToTool(event)]);\n return;\n }\n\n if (event.eventType === 'call_completed') {\n this.markCompleted();\n return;\n }\n\n if (event.eventType === 'summary_generated') {\n this.summaryRequested.set(true);\n return;\n }\n\n this.tools.update((prev) => [...prev, mapLifecycleEventToTool(event)]);\n }\n\n private appendLineIfNew(line: TranscriptLine): void {\n this.lines.update((prev) => {\n if (isDuplicateTranscriptLine(prev, line)) return prev;\n return [...prev, line];\n });\n }\n\n private startMockStream(callId: string): void {\n this.stopMockStream();\n this.mockIndex = 0;\n\n const mockChunks: TranscriptChunk[] = [\n {\n role: 'user',\n text: 'Hi, I need to schedule an appointment.',\n isFinal: false,\n timestamp: new Date().toISOString(),\n },\n {\n role: 'user',\n text: 'Hi, I need to schedule an appointment.',\n isFinal: true,\n timestamp: new Date().toISOString(),\n },\n {\n role: 'assistant',\n text: 'Of course — I can help with that. Which provider would you prefer?',\n isFinal: true,\n timestamp: new Date().toISOString(),\n },\n ];\n\n const mockEvents: CallEventStreamPayload[] = [\n {\n eventType: 'tool_check_doctor_availability',\n occurredAt: new Date().toISOString(),\n payload: {\n key: 'check_doctor_availability',\n name: 'Checked Doctor Availability',\n tech: 'tool_check_doctor_availability',\n result: 'Found 3 available time slots',\n state: 'ok',\n },\n },\n ];\n\n this.mockTimer = setInterval(() => {\n if (this.activeCallId !== callId) {\n this.stopMockStream();\n return;\n }\n if (this.mockIndex < mockChunks.length) {\n this.handleChunk(mockChunks[this.mockIndex]);\n this.mockIndex++;\n return;\n }\n if (this.mockIndex === mockChunks.length) {\n this.handleCallEvent(mockEvents[0]);\n this.mockIndex++;\n }\n }, 1500);\n }\n\n private stopMockStream(): void {\n if (this.mockTimer) {\n clearInterval(this.mockTimer);\n this.mockTimer = null;\n }\n }\n\n private clearInterim(): void {\n this.patientInterim.set(null);\n this.aiInterim.set(null);\n this.staffInterim.set(null);\n }\n\n private resetStreamState(): void {\n this.lines.set([]);\n this.tools.set([]);\n this.clearInterim();\n this.error.set(null);\n this.callEnded.set(false);\n this.summaryRequested.set(false);\n }\n}\n","import {\n AfterViewChecked,\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n ViewChild,\n computed,\n effect,\n inject,\n input,\n output,\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { TranscriptWho } from '../../models/ai-receptionist.types';\nimport { LiveTranscriptService } from '../../services/live-transcript.service';\nimport { isUnknownCaller } from '../../utils/call-history-display.util';\nimport { EdsIconComponent } from '../../ui/eds-icon.component';\n\n@Component({\n selector: 'eds-live-transcript-panel',\n imports: [FormsModule, EdsIconComponent],\n templateUrl: './live-transcript-panel.component.html',\n styleUrl: './live-transcript-panel.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n class: 'flex h-full min-h-0 flex-1 flex-col max-[900px]:h-auto max-[900px]:max-h-none max-[900px]:min-h-[360px]',\n },\n})\nexport class LiveTranscriptPanelComponent implements AfterViewChecked {\n readonly live = input(true);\n readonly paused = input(false);\n readonly humanTakeover = input(false);\n readonly showStaffInput = input(false);\n readonly staffMessage = input('');\n /** Resolved patient display name from the live call. */\n readonly callerName = input<string | null>(null);\n /** Whether the caller was matched to a patient chart. */\n readonly callerMatched = input(false);\n readonly staffMessageChange = output<string>();\n readonly sendMessage = output<void>();\n\n private readonly stream = inject(LiveTranscriptService);\n\n @ViewChild('scrollHost') private scrollHost?: ElementRef<HTMLElement>;\n\n protected readonly lines = this.stream.lines;\n protected readonly patientInterim = this.stream.patientInterim;\n protected readonly aiInterim = this.stream.aiInterim;\n protected readonly staffInterim = this.stream.staffInterim;\n protected readonly connected = this.stream.connected;\n protected readonly error = this.stream.error;\n\n protected readonly callerLabel = computed(() => {\n const name = this.callerName()?.trim() ?? '';\n if (isUnknownCaller(name, this.callerMatched())) return 'Unknown caller';\n return name || 'Unknown caller';\n });\n\n private shouldScroll = false;\n\n constructor() {\n effect(() => {\n this.lines();\n this.patientInterim();\n this.aiInterim();\n this.staffInterim();\n this.requestScroll();\n });\n }\n\n ngAfterViewChecked(): void {\n if (this.shouldScroll && this.scrollHost) {\n const el = this.scrollHost.nativeElement;\n el.scrollTop = el.scrollHeight;\n this.shouldScroll = false;\n }\n }\n\n protected roleLabel(who: TranscriptWho): string {\n switch (who) {\n case 'ai':\n return 'Ava · AI';\n case 'patient':\n return this.callerLabel();\n case 'staff':\n return 'Staff';\n default:\n return 'System';\n }\n }\n\n protected speakerIcon(who: TranscriptWho): string {\n switch (who) {\n case 'ai':\n return 'graphic_eq';\n case 'staff':\n return 'support_agent';\n case 'patient':\n return 'person';\n default:\n return 'info';\n }\n }\n\n protected systemIcon(flag?: string): string {\n if (flag === 'verify') return 'verified_user';\n if (flag === 'fail' || flag === 'escalate') return 'bolt';\n return 'info';\n }\n\n protected onStaffInput(value: string): void {\n this.staffMessageChange.emit(value);\n }\n\n protected onSend(): void {\n this.sendMessage.emit();\n }\n\n private requestScroll(): void {\n this.shouldScroll = true;\n }\n}\n","<section class=\"flex h-full min-h-0 flex-1 flex-col rounded-xl border border-zinc-200 bg-white max-[900px]:h-auto max-[900px]:max-h-none max-[900px]:min-h-[360px]\" aria-labelledby=\"live-transcript-title\">\n <header class=\"flex shrink-0 items-center justify-between gap-3 border-b border-zinc-200 px-4 py-4\">\n <h2 id=\"live-transcript-title\" class=\"m-0 font-mono text-xs font-semibold uppercase tracking-wider text-zinc-500\">Live transcript</h2>\n </header>\n\n <div #scrollHost class=\"flex flex-1 flex-col gap-4 overflow-auto bg-zinc-50 p-4\" role=\"log\" aria-live=\"polite\">\n @for (line of lines(); track $index) {\n @if (line.who === 'system') {\n <div\n class=\"inline-flex max-w-[90%] items-center gap-2 self-center rounded-full border px-3 py-2 text-center text-xs font-medium eds-animate-fade-up\"\n [class]=\"line.flag === 'verify' ? 'border-emerald-200 bg-emerald-50 text-emerald-700' : line.flag === 'fail' || line.flag === 'escalate' ? 'border-amber-200 bg-amber-50 text-amber-700' : 'border-zinc-200 bg-white text-zinc-600'\"\n >\n <eds-icon [name]=\"systemIcon(line.flag)\" [size]=\"14\" />\n <span>{{ line.text }}</span>\n </div>\n } @else {\n <article\n class=\"flex max-w-[72%] gap-3 eds-animate-fade-up\"\n [class]=\"line.who === 'patient' ? 'mr-auto self-start' : 'ml-auto flex-row-reverse self-end'\"\n >\n <div\n class=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-full\"\n [class]=\"line.who === 'ai' ? 'live-transcript-panel__avatar--ai text-white' : line.who === 'staff' ? 'border border-violet-200 bg-violet-50 text-violet-700' : 'bg-zinc-200 text-zinc-600'\"\n >\n <eds-icon [name]=\"speakerIcon(line.who)\" [size]=\"16\" />\n </div>\n <div\n class=\"flex min-w-0 flex-col gap-1\"\n [class]=\"line.who === 'patient' ? 'items-start' : 'items-end'\"\n >\n <span\n class=\"font-mono text-xs font-semibold tracking-wide\"\n [class]=\"line.who === 'ai' ? 'text-blue-600' : line.who === 'staff' ? 'text-violet-700' : 'text-zinc-400'\"\n >{{ roleLabel(line.who) }}</span>\n <div\n class=\"px-4 py-2\"\n [class]=\"line.who === 'patient' ? 'rounded-tl rounded-tr-xl rounded-br-xl rounded-bl-xl border border-zinc-200 bg-white' : line.who === 'staff' ? 'rounded-tl-xl rounded-tr rounded-br-xl rounded-bl-xl border border-violet-200 bg-violet-50' : 'rounded-tl-xl rounded-tr rounded-br-xl rounded-bl-xl border border-blue-200 bg-blue-50'\"\n >\n <p class=\"m-0 text-sm leading-snug\" [class]=\"line.who === 'staff' ? 'text-violet-900' : 'text-zinc-900'\">{{ line.text }}</p>\n </div>\n </div>\n </article>\n }\n }\n\n @if (patientInterim(); as interim) {\n <article class=\"mr-auto flex max-w-[72%] gap-3 self-start eds-animate-fade-up\">\n <div class=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-zinc-200 text-zinc-600\">\n <eds-icon name=\"person\" [size]=\"16\" />\n </div>\n <div class=\"flex min-w-0 flex-col items-start gap-1\">\n <span class=\"font-mono text-xs font-semibold tracking-wide text-zinc-400\">{{ callerLabel() }} · listening</span>\n <div class=\"rounded-tl rounded-tr-xl rounded-br-xl rounded-bl-xl border border-zinc-200 bg-white px-4 py-2 italic opacity-90\">\n <p class=\"m-0 text-sm leading-snug text-zinc-900\">{{ interim }}</p>\n </div>\n </div>\n </article>\n }\n\n @if (staffInterim(); as interim) {\n <article class=\"ml-auto flex max-w-[72%] flex-row-reverse gap-3 self-end eds-animate-fade-up\">\n <div class=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-full border border-violet-200 bg-violet-50 text-violet-700\">\n <eds-icon name=\"support_agent\" [size]=\"16\" />\n </div>\n <div class=\"flex min-w-0 flex-col items-end gap-1\">\n <span class=\"font-mono text-xs font-semibold tracking-wide text-violet-700\">Staff · speaking</span>\n <div class=\"rounded-tl-xl rounded-tr rounded-br-xl rounded-bl-xl border border-violet-200 bg-violet-50 px-4 py-2 italic opacity-90\">\n <p class=\"m-0 text-sm leading-snug text-violet-900\">{{ interim }}</p>\n </div>\n </div>\n </article>\n }\n\n @if (aiInterim(); as interim) {\n <article class=\"ml-auto flex max-w-[72%] flex-row-reverse gap-3 self-end eds-animate-fade-up\">\n <div class=\"live-transcript-panel__avatar--ai flex h-8 w-8 shrink-0 items-center justify-center rounded-full text-white\">\n <eds-icon name=\"graphic_eq\" [size]=\"16\" />\n </div>\n <div class=\"flex min-w-0 flex-col items-end gap-1\">\n <span class=\"font-mono text-xs font-semibold tracking-wide text-blue-600\">Ava · AI</span>\n <div class=\"rounded-tl-xl rounded-tr rounded-br-xl rounded-bl-xl border border-blue-200 bg-blue-50 px-4 py-2 italic opacity-90\">\n <p class=\"m-0 text-sm leading-snug text-zinc-900\">{{ interim }}<span class=\"live-transcript-panel__caret\" aria-hidden=\"true\"></span></p>\n </div>\n </div>\n </article>\n }\n\n @if (lines().length === 0 && !patientInterim() && !aiInterim() && !staffInterim()) {\n <p class=\"m-0 px-3 py-8 text-center text-sm leading-snug text-zinc-500\">Waiting for conversation…</p>\n }\n </div>\n\n @if (showStaffInput()) {\n <footer class=\"flex shrink-0 gap-2 border-t border-zinc-200 bg-white p-3\">\n <input\n type=\"text\"\n class=\"h-9 flex-1 rounded-md border border-zinc-200 bg-white px-4 text-sm text-zinc-900 placeholder:text-zinc-400 focus:border-blue-500 focus:outline-none\"\n placeholder=\"Type to speak as staff…\"\n [ngModel]=\"staffMessage()\"\n (ngModelChange)=\"onStaffInput($event)\"\n (keyup.enter)=\"onSend()\"\n autocomplete=\"off\"\n />\n </footer>\n }\n</section>\n","import { Injectable, signal } from '@angular/core';\nimport {\n ConnectionState,\n RemoteParticipant,\n RemoteTrack,\n RemoteTrackPublication,\n Room,\n RoomEvent,\n Track,\n} from 'livekit-client';\n\nimport { StaffMediaJoinResult, StaffMediaMode } from '../models/staff-media.types';\n\nexport type StaffMediaConnectionState =\n | 'idle'\n | 'connecting'\n | 'connected'\n | 'disconnecting'\n | 'error';\n\nconst STAFF_IDENTITY_PREFIX = 'staff-';\n\n/**\n * Browser softphone for staff Listen / Take Over via LiveKit.\n * Secrets stay on the server — FE only uses short-lived clientToken + livekitUrl.\n *\n * Root-provided on purpose: the session must survive navigating away from the\n * Live Monitor page, otherwise switching dashboard tabs would drop the call.\n */\n@Injectable({ providedIn: 'root' })\nexport class StaffMediaService {\n readonly connectionState = signal<StaffMediaConnectionState>('idle');\n readonly mode = signal<StaffMediaMode | null>(null);\n readonly micEnabled = signal(false);\n readonly error = signal<string | null>(null);\n readonly activeCallId = signal<string | null>(null);\n /** False when the browser blocks autoplay — UI should offer an \"enable sound\" action. */\n readonly audioPlaybackAllowed = signal(true);\n /** True once remote caller audio is actually attached and playing. */\n readonly remoteAudioAttached = signal(false);\n\n private room: Room | null = null;\n private audioContainer: HTMLElement | null = null;\n private readonly attached = new Map<string, HTMLMediaElement[]>();\n\n get isConnected(): boolean {\n return this.connectionState() === 'connected';\n }\n\n /** True when a softphone session is live for this call, regardless of page. */\n isConnectedTo(callId: string): boolean {\n return this.isConnected && this.activeCallId() === callId;\n }\n\n /**\n * getUserMedia only exists in a secure context (https or localhost) and, inside an\n * iframe, requires allow=\"microphone\". Returns null when capture is possible.\n */\n microphoneBlockedReason(): string | null {\n if (typeof navigator === 'undefined') return 'Microphone is not available in this environment.';\n if (!navigator.mediaDevices?.getUserMedia) {\n const secure = typeof window !== 'undefined' && window.isSecureContext;\n return secure\n ? 'Microphone access is blocked by the browser. If the dashboard is embedded, the host page must allow microphone access.'\n : 'Microphone access needs a secure connection. Open the dashboard over https (or localhost) to talk to callers.';\n }\n return null;\n }\n\n async join(join: StaffMediaJoinResult): Promise<void> {\n if (join.provider && join.provider !== 'livekit') {\n throw new Error(`Unsupported media provider: ${join.provider}`);\n }\n if (!join.livekitUrl || !join.clientToken) {\n throw new Error('Missing LiveKit URL or client token from media/join');\n }\n if (join.mode === 'takeover') {\n const blocked = this.microphoneBlockedReason();\n if (blocked) throw new Error(blocked);\n }\n\n await this.disconnect();\n\n this.connectionState.set('connecting');\n this.error.set(null);\n this.mode.set(join.mode);\n this.activeCallId.set(join.callId || null);\n this.micEnabled.set(false);\n\n const room = new Room({\n adaptiveStream: true,\n dynacast: true,\n audioCaptureDefaults: {\n echoCancellation: true,\n noiseSuppression: true,\n autoGainControl: true,\n },\n });\n\n room.on(RoomEvent.Disconnected, () => {\n if (this.room !== room) return;\n void this.cleanupLocal(false);\n this.connectionState.set('idle');\n this.mode.set(null);\n this.activeCallId.set(null);\n this.micEnabled.set(false);\n });\n\n room.on(RoomEvent.ConnectionStateChanged, (state: ConnectionState) => {\n if (this.room !== room) return;\n if (state === ConnectionState.Connected) {\n this.connectionState.set('connected');\n } else if (state === ConnectionState.Connecting || state === ConnectionState.Reconnecting) {\n this.connectionState.set('connecting');\n }\n });\n\n room.on(RoomEvent.AudioPlaybackStatusChanged, () => {\n if (this.room === room) {\n this.audioPlaybackAllowed.set(room.canPlaybackAudio);\n }\n });\n\n room.on(RoomEvent.TrackSubscribed, this.onTrackSubscribed);\n room.on(RoomEvent.TrackUnsubscribed, this.onTrackUnsubscribed);\n room.on(RoomEvent.ParticipantDisconnected, this.onParticipantDisconnected);\n room.on(RoomEvent.TrackPublished, this.onTrackPublished);\n\n try {\n this.room = room;\n this.ensureAudioContainer();\n await room.connect(join.livekitUrl, join.clientToken);\n\n // Publish mic only for takeover (listen stays receive-only).\n if (join.mode === 'takeover') {\n await this.enableMicrophone(true);\n }\n\n this.attachExistingRemoteTracks(room);\n await this.startAudioPlayback();\n this.connectionState.set('connected');\n } catch (err) {\n const message = this.friendlyError(err);\n this.error.set(message);\n this.connectionState.set('error');\n await this.cleanupLocal(true);\n this.mode.set(null);\n this.activeCallId.set(null);\n throw new Error(message);\n }\n }\n\n async setMicrophoneEnabled(enabled: boolean): Promise<void> {\n if (!this.room || this.connectionState() !== 'connected') return;\n if (this.mode() !== 'takeover' && enabled) {\n // Listen mode stays muted unless upgraded to takeover.\n return;\n }\n await this.enableMicrophone(enabled);\n }\n\n async toggleMicrophone(): Promise<void> {\n await this.setMicrophoneEnabled(!this.micEnabled());\n }\n\n /** Retry blocked autoplay — must be called from a user gesture. */\n async startAudioPlayback(): Promise<void> {\n const room = this.room;\n if (!room) return;\n try {\n await room.startAudio();\n this.audioPlaybackAllowed.set(true);\n } catch {\n this.audioPlaybackAllowed.set(room.canPlaybackAudio);\n }\n for (const elements of this.attached.values()) {\n for (const el of elements) {\n void el.play().catch(() => undefined);\n }\n }\n }\n\n async disconnect(): Promise<void> {\n if (!this.room && this.connectionState() === 'idle') return;\n this.connectionState.set('disconnecting');\n await this.cleanupLocal(true);\n this.connectionState.set('idle');\n this.mode.set(null);\n this.activeCallId.set(null);\n this.micEnabled.set(false);\n this.error.set(null);\n this.audioPlaybackAllowed.set(true);\n }\n\n private readonly onTrackSubscribed = (\n track: RemoteTrack,\n publication: RemoteTrackPublication,\n participant: RemoteParticipant,\n ): void => {\n if (track.kind !== Track.Kind.Audio) return;\n\n // Never play another staff softphone back — that is a direct feedback loop\n // where the person taking over hears their own voice.\n if (this.isStaff(participant.identity)) {\n try {\n publication.setSubscribed(false);\n } catch {\n /* server may already have unsubscribed */\n }\n return;\n }\n\n const container = this.ensureAudioContainer();\n const element = track.attach();\n element.autoplay = true;\n element.setAttribute('playsinline', 'true');\n (element as HTMLAudioElement).volume = 1;\n container.appendChild(element);\n\n const key = publication.trackSid || track.sid || participant.identity;\n this.attached.set(key, [...(this.attached.get(key) ?? []), element]);\n this.remoteAudioAttached.set(true);\n void element.play().catch(() => {\n // Autoplay blocked — surfaced via the \"Enable sound\" action.\n this.audioPlaybackAllowed.set(false);\n });\n };\n\n private readonly onTrackUnsubscribed = (\n track: RemoteTrack,\n publication: RemoteTrackPublication,\n participant: RemoteParticipant,\n ): void => {\n if (track.kind !== Track.Kind.Audio) return;\n const key = publication.trackSid || track.sid || participant.identity;\n this.detachKey(key, track);\n };\n\n private readonly onParticipantDisconnected = (participant: RemoteParticipant): void => {\n for (const publication of participant.trackPublications.values()) {\n const key = publication.trackSid;\n if (key) this.detachKey(key);\n }\n };\n\n /** Staff tracks are dropped server-side as soon as they appear. */\n private readonly onTrackPublished = (\n publication: RemoteTrackPublication,\n participant: RemoteParticipant,\n ): void => {\n if (!this.isStaff(participant.identity)) return;\n try {\n publication.setSubscribed(false);\n } catch {\n /* nothing to unsubscribe */\n }\n };\n\n private attachExistingRemoteTracks(room: Room): void {\n for (const participant of room.remoteParticipants.values()) {\n for (const publication of participant.trackPublications.values()) {\n if (publication.track && publication.isSubscribed) {\n this.onTrackSubscribed(publication.track, publication, participant);\n }\n }\n }\n }\n\n private isStaff(identity?: string | null): boolean {\n return !!identity && identity.startsWith(STAFF_IDENTITY_PREFIX);\n }\n\n private detachKey(key: string, track?: RemoteTrack): void {\n const elements = this.attached.get(key);\n if (!elements) return;\n this.attached.delete(key);\n for (const el of elements) {\n try {\n track?.detach(el);\n } catch {\n /* already detached */\n }\n el.remove();\n }\n if (this.attached.size === 0) this.remoteAudioAttached.set(false);\n }\n\n private ensureAudioContainer(): HTMLElement {\n if (this.audioContainer?.isConnected) return this.audioContainer;\n const el = document.createElement('div');\n el.dataset['edsStaffAudio'] = 'true';\n el.style.position = 'fixed';\n el.style.width = '0';\n el.style.height = '0';\n el.style.overflow = 'hidden';\n document.body.appendChild(el);\n this.audioContainer = el;\n return el;\n }\n\n private async enableMicrophone(enabled: boolean): Promise<void> {\n const room = this.room;\n if (!room) return;\n await room.localParticipant.setMicrophoneEnabled(enabled);\n this.micEnabled.set(enabled);\n }\n\n private friendlyError(err: unknown): string {\n const name = (err as { name?: string } | null)?.name ?? '';\n if (name === 'NotAllowedError' || name === 'SecurityError') {\n return 'Microphone permission was denied. Allow microphone access and try again.';\n }\n if (name === 'NotFoundError' || name === 'OverconstrainedError') {\n return 'No microphone was found on this device.';\n }\n if (name === 'NotReadableError' || name === 'TrackStartError') {\n return 'Your microphone is in use by another app.';\n }\n const message = err instanceof Error ? err.message : '';\n if (message.includes('getUserMedia')) {\n return this.microphoneBlockedReason() ?? message;\n }\n return message || 'Failed to join the call audio.';\n }\n\n private async cleanupLocal(disconnectRoom: boolean): Promise<void> {\n const room = this.room;\n this.room = null;\n\n for (const key of [...this.attached.keys()]) {\n this.detachKey(key);\n }\n this.remoteAudioAttached.set(false);\n this.audioContainer?.remove();\n this.audioContainer = null;\n\n if (!room) return;\n try {\n await room.localParticipant.setMicrophoneEnabled(false);\n } catch {\n /* mic may never have been published */\n }\n try {\n if (disconnectRoom) {\n await room.disconnect(true);\n }\n room.removeAllListeners();\n } catch {\n /* already gone */\n }\n }\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n effect,\n inject,\n OnDestroy,\n OnInit,\n signal,\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { ActivatedRoute, RouterLink } from '@angular/router';\nimport { FormsModule } from '@angular/forms';\nimport { firstValueFrom } from 'rxjs';\n\nimport { LiveTranscriptPanelComponent } from '../../components/live-transcript-panel/live-transcript-panel.component';\nimport { CallRecordingPlayerComponent } from '../../components/call-recording-player/call-recording-player.component';\nimport {\n CallControlMode,\n LiveCall,\n Sentiment,\n} from '../../models/ai-receptionist.types';\nimport {\n CallControlChangedEvent,\n StaffMediaMode,\n} from '../../models/staff-media.types';\nimport { AiReceptionistApiService } from '../../services/ai-receptionist-api.service';\nimport { DashboardSocketService } from '../../services/dashboard-socket.service';\nimport { LiveTranscriptService } from '../../services/live-transcript.service';\nimport { StaffMediaService } from '../../services/staff-media.service';\nimport { ToastService } from '../../shared/toast.service';\nimport {\n ageFromDob,\n callerMetaLine,\n isUnknownCaller,\n} from '../../utils/call-history-display.util';\nimport { toolEventTrackKey } from '../../utils/tool-labels.util';\nimport { EdsElapsedPipe } from '../../pipes/eds-elapsed.pipe';\nimport { EdsAvatarComponent } from '../../ui/eds-avatar.component';\nimport { EdsIconComponent } from '../../ui/eds-icon.component';\n\n@Component({\n selector: 'eds-live-monitor-page',\n imports: [\n RouterLink,\n FormsModule,\n EdsAvatarComponent,\n EdsIconComponent,\n EdsElapsedPipe,\n LiveTranscriptPanelComponent,\n CallRecordingPlayerComponent,\n ],\n templateUrl: './live-monitor-page.component.html',\n styleUrl: './live-monitor-page.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class LiveMonitorPageComponent implements OnInit, OnDestroy {\n private readonly api = inject(AiReceptionistApiService);\n private readonly route = inject(ActivatedRoute);\n private readonly stream = inject(LiveTranscriptService);\n private readonly staffMedia = inject(StaffMediaService);\n private readonly socket = inject(DashboardSocketService);\n private readonly toast = inject(ToastService);\n private readonly destroyRef = inject(DestroyRef);\n\n protected readonly call = signal<LiveCall | null>(null);\n protected readonly staffMessage = signal('');\n protected readonly loading = signal(true);\n protected readonly callId = signal('');\n protected readonly summary = signal<string | null>(null);\n protected readonly summaryLoading = signal(false);\n protected readonly mediaBusy = signal(false);\n\n protected readonly liveTools = this.stream.tools;\n protected readonly callEnded = this.stream.callEnded;\n protected readonly mediaState = this.staffMedia.connectionState;\n protected readonly mediaMode = this.staffMedia.mode;\n protected readonly micEnabled = this.staffMedia.micEnabled;\n protected readonly audioPlaybackAllowed = this.staffMedia.audioPlaybackAllowed;\n\n private summaryLoaded = false;\n private staffJoined = false;\n\n private readonly onControlChanged = (evt: CallControlChangedEvent): void => {\n if (!evt?.callId || evt.callId !== this.callId()) return;\n this.call.update((c) => {\n if (!c) return c;\n const handedOff = evt.aiHandedOff === true || c.aiHandedOff === true;\n const controlMode = (evt.controlMode as CallControlMode | null | undefined) ?? c.controlMode;\n const next: LiveCall = {\n ...c,\n controlMode,\n aiPaused: typeof evt.aiPaused === 'boolean' ? evt.aiPaused : c.aiPaused,\n aiHandedOff: handedOff,\n assigned: evt.assigned !== undefined ? evt.assigned : c.assigned,\n };\n if (controlMode === 'takeover' || handedOff) {\n next.status = 'takeover';\n } else if (controlMode === 'ai' || controlMode === 'listen') {\n if (c.status === 'takeover') next.status = 'ai';\n }\n return next;\n });\n };\n\n constructor() {\n effect(() => {\n if (this.stream.callEnded()) {\n void this.staffMedia.disconnect();\n this.staffJoined = false;\n this.loadCallMetadataOnce();\n }\n });\n\n effect(() => {\n if (this.stream.summaryRequested() && !this.summaryLoaded) {\n this.loadPostCallSummary();\n }\n });\n }\n\n ngOnInit(): void {\n this.socket.acquire();\n this.socket.on<CallControlChangedEvent>('call_control_changed', this.onControlChanged);\n\n this.route.paramMap.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((params) => {\n const id = params.get('id') ?? '';\n this.callId.set(id);\n // The softphone lives in a root service, so a session started earlier is still\n // running when this page is re-created.\n this.staffJoined = this.staffMedia.isConnectedTo(id);\n this.loading.set(true);\n this.summary.set(null);\n this.summaryLoaded = false;\n this.stream.stop();\n this.loadCallMetadata();\n });\n }\n\n /**\n * Leaving the page must never drop the caller. The LiveKit session is owned by the\n * root StaffMediaService and keeps running until End Call or an explicit leave.\n */\n ngOnDestroy(): void {\n this.socket.off('call_control_changed', this.onControlChanged);\n this.socket.release();\n this.stream.stop();\n }\n\n /** True when this page's call is the one the softphone is connected to. */\n protected isMediaForThisCall(): boolean {\n return this.staffMedia.activeCallId() === this.callId();\n }\n\n protected isTakeover(): boolean {\n if (this.mediaMode() === 'takeover' && this.isMediaForThisCall()) return true;\n const c = this.call();\n if (!c) return false;\n if (c.aiHandedOff) return true;\n if (c.controlMode === 'listen') return false;\n return c.controlMode === 'takeover' || c.status === 'takeover' || !!c.assigned;\n }\n\n /** After takeover the AI is gone for good — no resume path is offered. */\n protected isHandedOff(): boolean {\n return this.call()?.aiHandedOff === true || this.isTakeover();\n }\n\n protected isPaused(): boolean {\n const c = this.call();\n return c?.controlMode === 'paused' || !!c?.aiPaused;\n }\n\n protected isLive(): boolean {\n return !!this.call() && !this.callEnded();\n }\n\n protected confidenceLevel(confidence: number): 'high' | 'low' | 'mid' {\n if (confidence >= 70) return 'high';\n if (confidence < 50) return 'low';\n return 'mid';\n }\n\n protected sentimentPercent(sentiment: Sentiment): number {\n const map: Record<Sentiment, number> = {\n calm: 85,\n neutral: 60,\n frustrated: 35,\n urgent: 15,\n };\n return map[sentiment];\n }\n\n protected toolStateClass(state: string): string {\n return `live-monitor-page__tool--${state}`;\n }\n\n protected readonly toolTrackKey = toolEventTrackKey;\n\n protected isUnknownCaller(call: LiveCall): boolean {\n return isUnknownCaller(call.name, call.matched);\n }\n\n protected displayName(call: LiveCall): string {\n return this.isUnknownCaller(call) ? 'Unknown Caller' : call.name.trim();\n }\n\n protected profileInitials(call: LiveCall): string {\n return this.isUnknownCaller(call) ? '?' : call.initials || '?';\n }\n\n protected profileMeta(call: LiveCall): string {\n return callerMetaLine({\n name: call.name,\n matched: call.matched,\n phone: call.phone,\n dob: call.dob,\n age: call.age ?? ageFromDob(call.dob),\n gender: call.gender,\n });\n }\n\n protected goalBadge(call: LiveCall): string | null {\n const raw = (call.goal || call.reason || '').trim();\n if (!raw) return null;\n return raw.replace(/[_-]+/g, ' ').toUpperCase();\n }\n\n protected takeover(): void {\n void this.joinMedia('takeover');\n }\n\n protected toggleMic(): void {\n void this.staffMedia.toggleMicrophone();\n }\n\n protected transfer(): void {\n this.api.postTransfer(this.callId()).subscribe(() => this.refreshMetadata());\n }\n\n protected endCall(): void {\n const id = this.callId();\n void this.staffMedia.disconnect().then(() => {\n this.staffJoined = false;\n this.api.postEnd(id).subscribe(() => {\n this.stream.markCompleted();\n this.loadCallMetadataOnce();\n this.loadPostCallSummary();\n });\n });\n }\n\n protected sendMessage(): void {\n const text = this.staffMessage().trim();\n if (!text) return;\n this.api.postMessage(this.callId(), text).subscribe(() => {\n this.staffMessage.set('');\n this.refreshMetadata();\n });\n }\n\n protected enableSound(): void {\n void this.staffMedia.startAudioPlayback();\n }\n\n private async joinMedia(mode: StaffMediaMode): Promise<void> {\n if (this.mediaBusy() || this.callEnded()) return;\n const id = this.callId();\n if (!id) return;\n\n // Check the mic before joining so a blocked browser never leaves the AI paused.\n if (mode === 'takeover' && !this.api.usesMockStreaming()) {\n const blocked = this.staffMedia.microphoneBlockedReason();\n if (blocked) {\n this.toast.show(blocked, 'error', 6000);\n return;\n }\n }\n\n this.mediaBusy.set(true);\n try {\n const { data } = await firstValueFrom(this.api.postMediaJoin(id, mode));\n this.applyJoinMetadata(data);\n\n if (!this.api.usesMockStreaming()) {\n await this.staffMedia.join(data);\n }\n this.staffJoined = true;\n this.toast.show(\n mode === 'takeover' ? 'You are on the call' : 'Listening to the call',\n 'success',\n );\n } catch (err) {\n const message =\n err instanceof Error ? err.message : `Failed to ${mode === 'takeover' ? 'take over' : 'listen'}`;\n this.toast.show(message, 'error');\n try {\n await this.staffMedia.disconnect();\n await firstValueFrom(this.api.postMediaLeave(id));\n } catch {\n /* ignore cleanup errors */\n }\n this.staffJoined = false;\n } finally {\n this.mediaBusy.set(false);\n }\n }\n\n /**\n * Disconnect LiveKit first, then tell the server to drop staff and restore AI.\n * Only valid in listen mode — a taken-over call stays with the human.\n * Does not hang up the patient.\n */\n private async leaveMedia(notifyServer: boolean): Promise<void> {\n const id = this.callId();\n const wasJoined = this.staffJoined || this.staffMedia.isConnectedTo(id);\n try {\n await this.staffMedia.disconnect();\n } catch {\n /* ignore */\n }\n this.staffJoined = false;\n\n if (!notifyServer || !wasJoined || !id || this.callEnded()) return;\n\n this.mediaBusy.set(true);\n try {\n await firstValueFrom(this.api.postResumeAi(id));\n this.call.update((c) =>\n c\n ? {\n ...c,\n status: c.status === 'takeover' ? 'ai' : c.status,\n controlMode: 'ai',\n assigned: null,\n aiPaused: false,\n }\n : c,\n );\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Failed to resume AI';\n this.toast.show(message, 'error');\n } finally {\n this.mediaBusy.set(false);\n }\n }\n\n private applyJoinMetadata(data: {\n controlMode?: string | null;\n aiPaused?: boolean;\n aiHandedOff?: boolean;\n assigned?: string | null;\n mode: StaffMediaMode;\n }): void {\n this.call.update((c) => {\n if (!c) return c;\n const controlMode = (data.controlMode as CallControlMode) || data.mode;\n return {\n ...c,\n controlMode,\n aiPaused: typeof data.aiPaused === 'boolean' ? data.aiPaused : data.mode === 'takeover',\n aiHandedOff:\n data.aiHandedOff === true || data.mode === 'takeover' || c.aiHandedOff === true,\n assigned:\n data.assigned !== undefined && data.assigned !== null\n ? data.assigned\n : data.mode === 'takeover'\n ? c.assigned || 'You'\n : c.assigned,\n status: data.mode === 'takeover' ? 'takeover' : c.status,\n };\n });\n }\n\n /** Initial load — seeds transcript/tools from REST, then starts socket. */\n private loadCallMetadata(): void {\n const id = this.callId();\n if (!id) return;\n this.api.getLiveCall(id).subscribe(({ data }) => {\n this.call.set(data);\n this.loading.set(false);\n if (data) {\n this.stream.seed(data.transcript, data.tools);\n if (!this.callEnded()) {\n this.stream.watch(id, true);\n }\n }\n });\n }\n\n /** Metadata-only refresh after staff actions — does not overwrite live transcript/tools. */\n private refreshMetadata(): void {\n const id = this.callId();\n if (!id) return;\n this.api.getLiveCall(id).subscribe(({ data }) => {\n if (data) this.call.set(data);\n });\n }\n\n /** One-time metadata refresh after call ends (no socket). */\n private loadCallMetadataOnce(): void {\n const id = this.callId();\n if (!id) return;\n this.api.getLiveCall(id).subscribe(({ data }) => {\n if (data) {\n this.call.set(data);\n }\n });\n }\n\n private loadPostCallSummary(): void {\n const id = this.callId();\n if (!id || this.summaryLoaded) return;\n this.summaryLoading.set(true);\n this.api.getCallSummary(id).subscribe(({ data }) => {\n this.summaryLoading.set(false);\n this.summaryLoaded = true;\n if (!data) return;\n this.summary.set(data.summary);\n this.stream.seed(data.transcript, data.tools);\n });\n }\n}\n","<div class=\"eds-page live-monitor-page box-border flex h-full min-h-0 flex-col overflow-hidden bg-zinc-100 p-5 text-zinc-900\">\n @if (loading()) {\n <p class=\"text-sm leading-snug text-zinc-500\">Loading call…</p>\n } @else {\n @if (call(); as c) {\n <header class=\"live-monitor-page__header mb-4 flex shrink-0 flex-wrap items-center gap-3\">\n <a routerLink=\"../live\" class=\"live-monitor-page__back inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-md border border-zinc-200 bg-white text-zinc-600 no-underline\" aria-label=\"Back to live calls\">\n <eds-icon name=\"arrow_back\" [size]=\"19\" />\n </a>\n\n <div class=\"live-monitor-page__profile flex min-w-56 flex-1 items-center gap-3\">\n <eds-avatar\n class=\"live-monitor-page__avatar shrink-0\"\n [initials]=\"profileInitials(c)\"\n [tone]=\"isUnknownCaller(c) ? 'gray' : 'brand'\"\n />\n\n <div class=\"min-w-0\">\n <div class=\"flex flex-wrap items-center gap-3\">\n <h1 class=\"m-0 text-lg font-bold leading-snug text-zinc-900\">{{ displayName(c) }}</h1>\n @if (goalBadge(c); as badge) {\n <span class=\"inline-flex items-center gap-1 whitespace-nowrap rounded-md bg-blue-50 px-3 py-1 text-xs font-bold tracking-wide text-blue-700\">{{ badge }}</span>\n }\n </div>\n <p class=\"mt-1 text-xs leading-snug text-zinc-500\">{{ profileMeta(c) }}</p>\n </div>\n </div>\n\n <div class=\"live-monitor-page__header-actions ml-auto flex flex-wrap items-center gap-2\">\n @if (!callEnded()) {\n @if (mediaState() === 'connected' && isMediaForThisCall() && !audioPlaybackAllowed()) {\n <button\n type=\"button\"\n class=\"live-monitor-page__header-btn live-monitor-page__header-btn--ghost inline-flex h-9 cursor-pointer items-center gap-2 whitespace-nowrap rounded-md border border-zinc-200 bg-white px-4 text-sm font-semibold text-zinc-700\"\n (click)=\"enableSound()\"\n >\n <eds-icon name=\"volume_up\" [size]=\"18\" />\n Enable sound\n </button>\n }\n @if (isMediaForThisCall() && (mediaState() === 'connected' || mediaState() === 'connecting')) {\n <span\n class=\"live-monitor-page__media-pill inline-flex h-7 items-center rounded-full border border-zinc-200 bg-zinc-50 px-3 text-xs font-semibold tracking-wide text-zinc-600\"\n [attr.data-mode]=\"mediaMode() || 'idle'\"\n [attr.data-state]=\"mediaState()\"\n >\n @if (mediaState() === 'connecting') {\n Connecting…\n } @else if (mediaMode() === 'takeover') {\n {{ micEnabled() ? 'On call · mic on' : 'On call · mic off' }}\n } @else {\n Joined\n }\n </span>\n }\n <button\n type=\"button\"\n class=\"live-monitor-page__header-btn live-monitor-page__header-btn--danger inline-flex h-9 cursor-pointer items-center gap-2 whitespace-nowrap rounded-md border border-red-300 bg-white px-4 text-sm font-semibold text-red-600\"\n [disabled]=\"mediaBusy()\"\n (click)=\"endCall()\"\n >\n <eds-icon name=\"call_end\" [size]=\"18\" />\n End Call\n </button>\n @if (isTakeover()) {\n @if (mediaState() === 'connected' && isMediaForThisCall()) {\n <button\n type=\"button\"\n class=\"live-monitor-page__header-btn live-monitor-page__header-btn--ghost inline-flex h-9 cursor-pointer items-center gap-2 whitespace-nowrap rounded-md border border-zinc-200 bg-white px-4 text-sm font-semibold text-zinc-700\"\n (click)=\"toggleMic()\"\n >\n <eds-icon [name]=\"micEnabled() ? 'mic' : 'mic_off'\" [size]=\"18\" />\n {{ micEnabled() ? 'Mute' : 'Unmute' }}\n </button>\n }\n } @else {\n <button\n type=\"button\"\n class=\"live-monitor-page__header-btn live-monitor-page__header-btn--primary inline-flex h-9 cursor-pointer items-center gap-2 whitespace-nowrap rounded-md border border-blue-600 bg-blue-600 px-4 text-sm font-semibold text-white\"\n [disabled]=\"mediaBusy()\"\n (click)=\"takeover()\"\n >\n <eds-icon name=\"phone_in_talk\" [size]=\"18\" />\n Take Over\n </button>\n }\n } @else {\n <span class=\"inline-flex items-center gap-2 text-lg font-bold font-mono text-zinc-900\">\n <span class=\"h-2 w-2 rounded-full bg-green-500 ring-4 ring-green-500/15\" aria-hidden=\"true\"></span>\n {{ c.started | edsElapsed }}\n </span>\n }\n </div>\n </header>\n\n @if (callEnded()) {\n <div class=\"mb-4 flex items-center gap-2 rounded-lg bg-green-50 px-4 py-3 text-sm leading-snug text-green-700\" role=\"status\">\n <eds-icon name=\"check_circle\" [size]=\"18\" />\n Call ended\n </div>\n }\n\n <div class=\"live-monitor-page__grid min-h-0 flex-1\">\n <div class=\"live-monitor-page__main flex h-full min-h-0 flex-col gap-4\">\n <eds-live-transcript-panel\n [live]=\"isLive()\"\n [paused]=\"isPaused()\"\n [humanTakeover]=\"isTakeover()\"\n [showStaffInput]=\"false\"\n [staffMessage]=\"staffMessage()\"\n [callerName]=\"c.name\"\n [callerMatched]=\"c.matched\"\n (staffMessageChange)=\"staffMessage.set($event)\"\n (sendMessage)=\"sendMessage()\"\n />\n\n @if (callEnded()) {\n <section class=\"live-monitor-page__post-call flex flex-col gap-4\">\n <div class=\"rounded-lg border border-zinc-200 bg-white p-4 text-sm leading-normal text-zinc-600\">\n <h2 class=\"mb-3 m-0 text-sm font-semibold text-zinc-600\">Call summary</h2>\n @if (summaryLoading()) {\n <p class=\"m-0 text-zinc-500\">Generating summary…</p>\n } @else if (summary()) {\n <p>{{ summary() }}</p>\n } @else {\n <p class=\"m-0 text-zinc-500\">Summary will appear when processing completes.</p>\n }\n </div>\n <eds-call-recording-player [callId]=\"callId()\" />\n </section>\n }\n </div>\n\n <aside class=\"live-monitor-page__sidebar flex h-full min-h-0 flex-col gap-3 overflow-auto\">\n @if (!callEnded()) {\n <div class=\"live-monitor-page__orb-wrap relative flex w-full min-h-0 flex-col items-center justify-center gap-1.5 rounded-lg border border-zinc-200 bg-white px-3 py-2.5\" [attr.data-mode]=\"c.status === 'transferring' ? 'transfer' : 'ai'\">\n <span class=\"live-monitor-page__ring live-monitor-page__ring--1\"></span>\n <span class=\"live-monitor-page__ring live-monitor-page__ring--2\"></span>\n <span class=\"live-monitor-page__orb relative z-[1] flex h-8 w-8 items-center justify-center rounded-full\">\n <eds-icon name=\"smart_toy\" [size]=\"16\" />\n </span>\n <span class=\"live-monitor-page__confidence max-w-full text-center text-[11px] font-medium font-mono leading-snug text-zinc-500\" [attr.data-level]=\"confidenceLevel(c.confidence)\">\n AI confidence {{ c.confidence }}%\n </span>\n </div>\n\n <section class=\"rounded-lg border border-zinc-200 bg-white p-4\">\n <h3 class=\"mb-3 m-0 text-sm font-semibold text-zinc-600\">Patient sentiment</h3>\n <div class=\"mb-2 h-[5px] overflow-hidden rounded-sm bg-zinc-200\">\n <span\n class=\"live-monitor-page__sentiment-fill block h-full rounded-sm bg-green-500\"\n [style.width.%]=\"sentimentPercent(c.sentiment)\"\n [attr.data-sentiment]=\"c.sentiment\"\n ></span>\n </div>\n <span class=\"text-xs font-medium font-mono capitalize leading-snug text-zinc-500\">{{ c.sentiment }}</span>\n </section>\n }\n\n <section class=\"live-monitor-page__sidebar-block flex min-h-0 flex-1 flex-col rounded-lg border border-zinc-200 bg-white p-4\">\n <h3 class=\"mb-3 m-0 text-sm font-semibold text-zinc-600\">Goal Timeline</h3>\n <p class=\"mb-3 m-0 text-sm leading-snug text-zinc-600\">{{ c.goal || '—' }}</p>\n <ul class=\"live-monitor-page__tools flex min-h-0 flex-1 flex-col gap-2 overflow-auto\">\n @for (tool of liveTools(); track toolTrackKey(tool, $index)) {\n <li [class]=\"toolStateClass(tool.state)\">\n <span class=\"whitespace-nowrap text-xs font-medium font-mono leading-snug text-zinc-400\">{{ tool.t }}</span>\n <div class=\"flex min-w-0 flex-col gap-1\">\n <span class=\"break-words text-sm font-semibold leading-snug text-zinc-900\">{{ tool.name }}</span>\n <span class=\"break-words text-xs leading-snug text-zinc-500\">{{ tool.result }}</span>\n </div>\n @if (tool.state === 'active') {\n <eds-icon name=\"sync\" [size]=\"14\" class=\"live-monitor-page__tool-spin col-span-full justify-self-end\" />\n }\n </li>\n } @empty {\n <li class=\"live-monitor-page__tools-empty text-xs leading-snug text-zinc-500\">No tool activity yet.</li>\n }\n </ul>\n </section>\n </aside>\n </div>\n } @else {\n <p class=\"text-sm leading-snug text-zinc-500\">Call ended or not found.</p>\n }\n }\n</div>\n"],"names":[],"mappings":"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"}
|
package/fesm2022/edvak99-voice-receptionist-widget-outbound-purposes-page.component-D407n7l0.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"edvak99-voice-receptionist-widget-outbound-purposes-page.component-D407n7l0.mjs","sources":["../../../projects/voice-receptionist-widget/src/lib/utils/outbound-purpose.util.ts","../../../projects/voice-receptionist-widget/src/lib/components/outbound-purpose-form-modal/outbound-purpose-form-modal.component.ts","../../../projects/voice-receptionist-widget/src/lib/components/outbound-purpose-form-modal/outbound-purpose-form-modal.component.html","../../../projects/voice-receptionist-widget/src/lib/pages/outbound-purposes-page/outbound-purposes-page.component.ts","../../../projects/voice-receptionist-widget/src/lib/pages/outbound-purposes-page/outbound-purposes-page.component.html"],"sourcesContent":["import {\n OutboundPurpose,\n OutboundPurposePlaceholder,\n OutboundRequiredField,\n} from '../models/outbound-purpose.types';\n\nexport const REQUIRED_FIELD_OPTIONS: { value: OutboundRequiredField; label: string }[] = [\n { value: 'appointmentDate', label: 'Appointment Date' },\n { value: 'appointmentTime', label: 'Appointment Time' },\n { value: 'providerName', label: 'Provider Name' },\n { value: 'customScript', label: 'Custom Script' },\n];\n\n/** Live dialer values used to fill opening-template tokens. */\nexport interface OpeningPreviewValues {\n patientName?: string;\n appointmentDate?: string;\n appointmentTime?: string;\n providerName?: string;\n practiceName?: string;\n locationName?: string;\n visitType?: string;\n customScript?: string;\n}\n\nconst TOKEN_KEYS: { token: string; key: keyof OpeningPreviewValues; label: string }[] = [\n { token: '{{patientName}}', key: 'patientName', label: 'Patient name' },\n { token: '{{appointmentDate}}', key: 'appointmentDate', label: 'Appointment date' },\n { token: '{{appointmentTime}}', key: 'appointmentTime', label: 'Appointment time' },\n { token: '{{providerName}}', key: 'providerName', label: 'Provider name' },\n { token: '{{practiceName}}', key: 'practiceName', label: 'Practice name' },\n { token: '{{locationName}}', key: 'locationName', label: 'Location' },\n { token: '{{visitType}}', key: 'visitType', label: 'Visit type' },\n { token: '{{customScript}}', key: 'customScript', label: 'Custom script' },\n];\n\nexport function requiredFieldLabel(field: OutboundRequiredField): string {\n return REQUIRED_FIELD_OPTIONS.find((o) => o.value === field)?.label ?? field;\n}\n\nexport function formatRequiredFields(fields: OutboundRequiredField[]): string {\n if (!fields.length) return '—';\n return fields.map(requiredFieldLabel).join(', ');\n}\n\n/** Substitute placeholder tokens with sample values. */\nexport function substitutePlaceholders(\n text: string,\n placeholders: OutboundPurposePlaceholder[],\n): string {\n let result = text;\n for (const p of placeholders) {\n result = result.split(p.token).join(p.sampleValue);\n }\n return result;\n}\n\n/** Live preview: sampleOpening if set, else openingTemplate with substitutions. */\nexport function renderOpeningPreview(\n sampleOpening: string,\n openingTemplate: string,\n placeholders: OutboundPurposePlaceholder[],\n): string {\n const source = sampleOpening?.trim() ? sampleOpening : openingTemplate;\n if (!source?.trim()) return '—';\n return substitutePlaceholders(source, placeholders);\n}\n\n/**\n * Dialer preview: prefer openingTemplate and fill with live patient/appointment values.\n * Unfilled tokens show as [Label] so staff see what is still missing.\n */\nexport function renderLiveOpeningPreview(\n purpose: Pick<OutboundPurpose, 'openingTemplate' | 'sampleOpening' | 'placeholders'>,\n live: OpeningPreviewValues,\n): string {\n const source = purpose.openingTemplate?.trim() || purpose.sampleOpening?.trim() || '';\n if (!source) return '—';\n\n const byToken = new Map<string, string>();\n for (const meta of TOKEN_KEYS) {\n const liveVal = String(live[meta.key] ?? '').trim();\n byToken.set(meta.token, liveVal || `[${meta.label}]`);\n }\n for (const p of purpose.placeholders ?? []) {\n if (!byToken.has(p.token)) {\n byToken.set(p.token, p.sampleValue?.trim() || `[${p.label}]`);\n }\n }\n\n let result = source;\n for (const [token, value] of byToken) {\n result = result.split(token).join(value);\n }\n return result;\n}\n\n/** Human-friendly date/time for opening lines (from ISO or form fields). */\nexport function formatOpeningDate(isoOrYmd: string | null | undefined): string {\n const raw = String(isoOrYmd ?? '').trim();\n if (!raw) return '';\n const d = raw.includes('T') || raw.includes('Z') ? new Date(raw) : parseLocalYmd(raw);\n if (!d || Number.isNaN(d.getTime())) return raw;\n return d.toLocaleDateString(undefined, {\n weekday: 'short',\n month: 'long',\n day: 'numeric',\n year: 'numeric',\n });\n}\n\nexport function formatOpeningTime(\n isoOrHm: string | null | undefined,\n fallbackIso?: string | null,\n): string {\n const raw = String(isoOrHm ?? '').trim();\n if (raw.includes('T') || raw.includes('Z')) {\n const d = new Date(raw);\n if (!Number.isNaN(d.getTime())) {\n return d.toLocaleTimeString(undefined, { hour: 'numeric', minute: '2-digit' });\n }\n }\n if (/^\\d{1,2}:\\d{2}/.test(raw)) {\n const [h, m] = raw.split(':').map(Number);\n const d = new Date();\n d.setHours(h, m, 0, 0);\n return d.toLocaleTimeString(undefined, { hour: 'numeric', minute: '2-digit' });\n }\n if (fallbackIso) return formatOpeningTime(fallbackIso);\n return raw;\n}\n\nfunction parseLocalYmd(ymd: string): Date | null {\n const m = /^(\\d{4})-(\\d{2})-(\\d{2})$/.exec(ymd);\n if (!m) return null;\n return new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3]));\n}\n\nexport function purposeShowsCustomScript(purpose: OutboundPurpose): boolean {\n return purpose.allowsCustomScript || purpose.requiredFields.includes('customScript');\n}\n\nexport function isCustomScriptRequired(purpose: OutboundPurpose): boolean {\n return purpose.requiredFields.includes('customScript');\n}\n\nexport function isPurposeFormValid(\n purpose: OutboundPurpose | null,\n values: Record<string, string>,\n): boolean {\n if (!purpose) return false;\n if (!values['phone']?.trim() || !values['name']?.trim()) return false;\n\n for (const field of purpose.requiredFields) {\n if (field === 'customScript') {\n if (!values['customScript']?.trim()) return false;\n } else if (!values[field]?.trim()) {\n return false;\n }\n }\n return true;\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n EventEmitter,\n Input,\n OnChanges,\n Output,\n SimpleChanges,\n ViewChild,\n inject,\n signal,\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport {\n CreateOutboundPurposeRequest,\n OutboundPurpose,\n OutboundPurposePlaceholder,\n OutboundRequiredField,\n UpdateOutboundPurposeRequest,\n} from '../../models/outbound-purpose.types';\nimport { AiReceptionistApiService } from '../../services/ai-receptionist-api.service';\nimport {\n REQUIRED_FIELD_OPTIONS,\n renderOpeningPreview,\n} from '../../utils/outbound-purpose.util';\nimport { DEFAULT_PLACEHOLDERS } from '../../mocks/outbound-purpose.seed';\nimport { EdsButtonComponent } from '../../ui/eds-button.component';\nimport { ModalComponent } from '../../shared/modal.component';\n\n@Component({\n selector: 'eds-outbound-purpose-form-modal',\n imports: [FormsModule, ModalComponent, EdsButtonComponent],\n templateUrl: './outbound-purpose-form-modal.component.html',\n styleUrl: './outbound-purpose-form-modal.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class OutboundPurposeFormModalComponent implements OnChanges {\n private readonly api = inject(AiReceptionistApiService);\n\n @Input() open = false;\n @Input() purpose: OutboundPurpose | null = null;\n @Output() readonly closed = new EventEmitter<void>();\n @Output() readonly saved = new EventEmitter<OutboundPurpose>();\n\n @ViewChild('templateInput') templateInput?: ElementRef<HTMLTextAreaElement>;\n\n protected readonly fieldOptions = REQUIRED_FIELD_OPTIONS;\n protected readonly saving = signal(false);\n protected readonly error = signal<string | null>(null);\n\n protected label = '';\n protected description = '';\n protected sampleOpening = '';\n protected openingTemplate = '';\n protected agentContextHint = '';\n protected requiredFields = new Set<OutboundRequiredField>();\n protected allowsCustomScript = false;\n protected sortOrder = 1;\n protected isActive = true;\n protected placeholders: OutboundPurposePlaceholder[] = DEFAULT_PLACEHOLDERS;\n\n protected get isEdit(): boolean {\n return !!this.purpose;\n }\n\n protected get previewText(): string {\n return renderOpeningPreview(this.sampleOpening, this.openingTemplate, this.placeholders);\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes['open']?.currentValue || changes['purpose']) {\n this.resetForm();\n }\n }\n\n protected close(): void {\n this.closed.emit();\n }\n\n protected toggleRequired(field: OutboundRequiredField): void {\n const next = new Set(this.requiredFields);\n if (next.has(field)) next.delete(field);\n else next.add(field);\n this.requiredFields = next;\n }\n\n protected isRequiredSelected(field: OutboundRequiredField): boolean {\n return this.requiredFields.has(field);\n }\n\n protected insertPlaceholder(token: string): void {\n const el = this.templateInput?.nativeElement;\n if (!el) {\n this.openingTemplate += token;\n return;\n }\n const start = el.selectionStart ?? this.openingTemplate.length;\n const end = el.selectionEnd ?? start;\n this.openingTemplate =\n this.openingTemplate.slice(0, start) + token + this.openingTemplate.slice(end);\n const pos = start + token.length;\n requestAnimationFrame(() => {\n el.focus();\n el.setSelectionRange(pos, pos);\n });\n }\n\n protected submit(): void {\n this.error.set(null);\n const trimmedLabel = this.label.trim();\n const trimmedTemplate = this.openingTemplate.trim();\n if (!trimmedLabel) {\n this.error.set('Label is required.');\n return;\n }\n if (!trimmedTemplate) {\n this.error.set('Opening template is required.');\n return;\n }\n if (this.sampleOpening.length > 500) {\n this.error.set('Sample opening must be 500 characters or fewer.');\n return;\n }\n\n this.saving.set(true);\n const fields = [...this.requiredFields];\n\n if (this.isEdit && this.purpose) {\n const body: UpdateOutboundPurposeRequest = {\n label: trimmedLabel,\n description: this.description.trim(),\n sampleOpening: this.sampleOpening.trim(),\n openingTemplate: trimmedTemplate,\n agentContextHint: this.agentContextHint.trim() || null,\n requiredFields: fields,\n allowsCustomScript: this.allowsCustomScript,\n sortOrder: this.sortOrder,\n isActive: this.isActive,\n };\n this.api.updateOutboundPurpose(this.purpose.purposeId, body).subscribe({\n next: (updated) => {\n this.saving.set(false);\n this.saved.emit(updated);\n this.close();\n },\n error: () => {\n this.saving.set(false);\n this.error.set('Failed to save purpose template.');\n },\n });\n return;\n }\n\n const body: CreateOutboundPurposeRequest = {\n label: trimmedLabel,\n description: this.description.trim(),\n sampleOpening: this.sampleOpening.trim(),\n openingTemplate: trimmedTemplate,\n agentContextHint: this.agentContextHint.trim() || null,\n requiredFields: fields,\n allowsCustomScript: this.allowsCustomScript,\n sortOrder: this.sortOrder,\n };\n this.api.createOutboundPurpose(body).subscribe({\n next: (created) => {\n this.saving.set(false);\n this.saved.emit(created);\n this.close();\n },\n error: () => {\n this.saving.set(false);\n this.error.set('Failed to create purpose template.');\n },\n });\n }\n\n private resetForm(): void {\n this.error.set(null);\n this.saving.set(false);\n if (this.purpose) {\n this.label = this.purpose.label;\n this.description = this.purpose.description;\n this.sampleOpening = this.purpose.sampleOpening;\n this.openingTemplate = this.purpose.openingTemplate;\n this.agentContextHint = this.purpose.agentContextHint ?? '';\n this.requiredFields = new Set(this.purpose.requiredFields);\n this.allowsCustomScript = this.purpose.allowsCustomScript;\n this.sortOrder = this.purpose.sortOrder;\n this.isActive = this.purpose.isActive;\n this.placeholders = this.purpose.placeholders?.length\n ? [...this.purpose.placeholders]\n : [...DEFAULT_PLACEHOLDERS];\n } else {\n this.label = '';\n this.description = '';\n this.sampleOpening = '';\n this.openingTemplate = 'Hi {{patientName}}, this is {{practiceName}}.';\n this.agentContextHint = '';\n this.requiredFields = new Set();\n this.allowsCustomScript = false;\n this.sortOrder = 1;\n this.isActive = true;\n this.placeholders = [...DEFAULT_PLACEHOLDERS];\n }\n }\n}\n","@if (open) {\n <app-modal\n [title]=\"isEdit ? 'Edit outbound purpose' : 'New outbound purpose'\"\n subtitle=\"Configure dialer fields and AI opening script\"\n maxWidth=\"720px\"\n (closed)=\"close()\"\n >\n <form class=\"flex flex-col gap-4\" (ngSubmit)=\"submit()\" novalidate autocomplete=\"off\">\n <div class=\"grid grid-cols-2 gap-3\">\n <label class=\"col-span-full flex flex-col gap-2\">\n <span class=\"eds-label\">Label <span class=\"text-[#dc2626]\">*</span></span>\n <input type=\"text\" class=\"purpose-form__input rounded-lg border px-3 py-2 font-[inherit]\" [(ngModel)]=\"label\" name=\"label\" required autocomplete=\"off\" />\n </label>\n\n <label class=\"col-span-full flex flex-col gap-2\">\n <span class=\"eds-label\">Description</span>\n <input type=\"text\" class=\"purpose-form__input rounded-lg border px-3 py-2 font-[inherit]\" [(ngModel)]=\"description\" name=\"description\" autocomplete=\"off\" />\n </label>\n\n <label class=\"col-span-full flex flex-col gap-2\">\n <span class=\"eds-label\">Sample opening (plain preview, max 500)</span>\n <textarea\n class=\"purpose-form__textarea min-h-[72px] resize-y rounded-lg border px-3 py-2 font-[inherit]\"\n rows=\"3\"\n maxlength=\"500\"\n [(ngModel)]=\"sampleOpening\"\n name=\"sampleOpening\" autocomplete=\"off\"></textarea>\n <span class=\"purpose-form__hint text-xs\">{{ sampleOpening.length }}/500</span>\n </label>\n\n <div class=\"col-span-full flex flex-col gap-2\">\n <span class=\"eds-label\">Opening template <span class=\"text-[#dc2626]\">*</span></span>\n <div class=\"mb-2 flex flex-wrap gap-2\">\n @for (chip of placeholders; track chip.token) {\n <button type=\"button\" class=\"purpose-form__chip cursor-pointer rounded-full border px-3 py-1 text-xs\" (click)=\"insertPlaceholder(chip.token)\">\n {{ chip.label }}\n </button>\n }\n </div>\n <textarea\n #templateInput\n class=\"purpose-form__textarea min-h-[72px] resize-y rounded-lg border px-3 py-2 font-[inherit]\"\n rows=\"4\"\n [(ngModel)]=\"openingTemplate\"\n name=\"openingTemplate\"\n required autocomplete=\"off\"></textarea>\n </div>\n\n <label class=\"col-span-full flex flex-col gap-2\">\n <span class=\"eds-label\">Agent context hint</span>\n <textarea\n class=\"purpose-form__textarea min-h-[72px] resize-y rounded-lg border px-3 py-2 font-[inherit]\"\n rows=\"2\"\n [(ngModel)]=\"agentContextHint\"\n name=\"agentContextHint\"\n placeholder=\"Optional guidance for the AI after the opening\" autocomplete=\"off\"></textarea>\n </label>\n\n <fieldset class=\"col-span-full flex flex-col gap-2\">\n <legend class=\"eds-label\">Required fields</legend>\n <div class=\"grid grid-cols-2 gap-2\">\n @for (opt of fieldOptions; track opt.value) {\n <label class=\"flex items-center gap-2 text-[13px]\">\n <input\n type=\"checkbox\"\n [checked]=\"isRequiredSelected(opt.value)\"\n (change)=\"toggleRequired(opt.value)\" autocomplete=\"off\" />\n {{ opt.label }}\n </label>\n }\n </div>\n </fieldset>\n\n <label class=\"col-span-full flex items-center gap-2 text-[13px]\">\n <input type=\"checkbox\" [(ngModel)]=\"allowsCustomScript\" name=\"allowsCustomScript\" autocomplete=\"off\" />\n Allows custom script (dialer shows free-text script field)\n </label>\n\n <label class=\"flex flex-col gap-2\">\n <span class=\"eds-label\">Sort order</span>\n <input type=\"number\" class=\"purpose-form__input rounded-lg border px-3 py-2 font-[inherit]\" [(ngModel)]=\"sortOrder\" name=\"sortOrder\" min=\"0\" autocomplete=\"off\" />\n </label>\n\n @if (isEdit) {\n <label class=\"flex items-center gap-2 text-[13px]\">\n <input type=\"checkbox\" [(ngModel)]=\"isActive\" name=\"isActive\" autocomplete=\"off\" />\n Active\n </label>\n }\n </div>\n\n <section class=\"purpose-form__preview eds-card rounded-lg p-3 shadow-sm\">\n <h3 class=\"eds-label\">Live preview</h3>\n <p class=\"purpose-form__preview-text mt-2 whitespace-pre-wrap text-sm leading-normal\">{{ previewText }}</p>\n </section>\n\n @if (error()) {\n <p class=\"m-0 text-[13px] text-[#b91c1c]\" role=\"alert\">{{ error() }}</p>\n }\n\n <footer class=\"flex justify-end gap-2\">\n <eds-button variant=\"secondary\" type=\"button\" (click)=\"close()\" [disabled]=\"saving()\">\n Cancel\n </eds-button>\n <eds-button variant=\"primary\" type=\"submit\" [disabled]=\"saving()\">\n {{ saving() ? 'Saving…' : isEdit ? 'Save changes' : 'Create purpose' }}\n </eds-button>\n </footer>\n </form>\n </app-modal>\n}\n","import { ChangeDetectionStrategy, Component, inject, OnInit, signal } from '@angular/core';\nimport { RouterLink } from '@angular/router';\n\nimport { OutboundPurpose } from '../../models/outbound-purpose.types';\nimport { AiReceptionistApiService } from '../../services/ai-receptionist-api.service';\nimport { formatRequiredFields } from '../../utils/outbound-purpose.util';\nimport { OutboundPurposeFormModalComponent } from '../../components/outbound-purpose-form-modal/outbound-purpose-form-modal.component';\nimport { EdsBadgeComponent } from '../../ui/eds-badge.component';\nimport { EdsButtonComponent } from '../../ui/eds-button.component';\nimport { EdsIconComponent } from '../../ui/eds-icon.component';\n\n@Component({\n selector: 'eds-outbound-purposes-page',\n imports: [\n RouterLink,\n EdsBadgeComponent,\n EdsButtonComponent,\n EdsIconComponent,\n OutboundPurposeFormModalComponent,\n ],\n templateUrl: './outbound-purposes-page.component.html',\n styleUrl: './outbound-purposes-page.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class OutboundPurposesPageComponent implements OnInit {\n private readonly api = inject(AiReceptionistApiService);\n\n protected readonly purposes = signal<OutboundPurpose[]>([]);\n protected readonly loading = signal(true);\n protected readonly error = signal<string | null>(null);\n protected readonly modalOpen = signal(false);\n protected readonly editing = signal<OutboundPurpose | null>(null);\n\n protected formatRequiredFields = formatRequiredFields;\n\n ngOnInit(): void {\n this.load();\n }\n\n protected load(): void {\n this.loading.set(true);\n this.error.set(null);\n this.api.getOutboundPurposes(true).subscribe({\n next: ({ purposes }) => {\n this.purposes.set(purposes);\n this.loading.set(false);\n },\n error: () => {\n this.loading.set(false);\n this.error.set('Failed to load outbound purposes.');\n },\n });\n }\n\n protected openCreate(): void {\n this.editing.set(null);\n this.modalOpen.set(true);\n }\n\n protected openEdit(purpose: OutboundPurpose): void {\n this.editing.set(purpose);\n this.modalOpen.set(true);\n }\n\n protected closeModal(): void {\n this.modalOpen.set(false);\n this.editing.set(null);\n }\n\n protected onSaved(): void {\n this.load();\n }\n\n protected toggleActive(purpose: OutboundPurpose, active: boolean): void {\n this.api.updateOutboundPurpose(purpose.purposeId, { isActive: active }).subscribe({\n next: (updated) => {\n this.purposes.update((list) =>\n list.map((p) => (p.purposeId === updated.purposeId ? updated : p)),\n );\n },\n error: () => this.load(),\n });\n }\n\n protected deletePurpose(purpose: OutboundPurpose): void {\n if (purpose.isSystem) {\n this.toggleActive(purpose, false);\n return;\n }\n if (!confirm(`Delete \"${purpose.label}\"? This cannot be undone.`)) return;\n this.api.deleteOutboundPurpose(purpose.purposeId).subscribe({\n next: () => this.load(),\n error: () => this.error.set('Failed to delete purpose.'),\n });\n }\n\n protected actionLabel(purpose: OutboundPurpose): string {\n return purpose.isSystem ? 'Deactivate' : 'Delete';\n }\n}\n","<div class=\"eds-page outbound-purposes-page\">\n <header class=\"mb-5 flex items-start justify-between gap-4\">\n <div>\n <a routerLink=\"../settings\" class=\"outbound-purposes-page__back eds-body-sm mb-2 inline-flex items-center gap-1 no-underline\">\n <eds-icon name=\"arrow_back\" [size]=\"16\" /> Settings\n </a>\n <h1 class=\"eds-h1\">Outbound Call Purposes</h1>\n <p class=\"eds-body-sm\">Templates that drive outbound dialer fields and AI opening scripts</p>\n </div>\n <eds-button variant=\"primary\" (click)=\"openCreate()\">\n <eds-icon name=\"add\" [size]=\"18\" /> New purpose\n </eds-button>\n </header>\n\n @if (loading()) {\n <p class=\"eds-body-sm\">Loading purposes…</p>\n } @else if (error()) {\n <p class=\"eds-body-sm text-red-700\" role=\"alert\">{{ error() }}</p>\n } @else {\n <article class=\"eds-card overflow-x-auto p-4 shadow-sm\">\n <table class=\"eds-table\">\n <thead>\n <tr>\n <th>Label</th>\n <th>Description</th>\n <th>Required fields</th>\n <th>System</th>\n <th>Active</th>\n <th>Sort</th>\n <th>Actions</th>\n </tr>\n </thead>\n <tbody>\n @for (p of purposes(); track p.purposeId) {\n <tr>\n <td class=\"eds-body-sm-bold\">{{ p.label }}</td>\n <td class=\"eds-body-sm\">{{ p.description || '—' }}</td>\n <td class=\"eds-body-sm\">{{ formatRequiredFields(p.requiredFields) }}</td>\n <td>\n @if (p.isSystem) {\n <eds-badge tone=\"brand\">System</eds-badge>\n } @else {\n <span class=\"eds-body-sm\">—</span>\n }\n </td>\n <td>\n <label>\n <input\n type=\"checkbox\"\n class=\"h-4 w-4\"\n [checked]=\"p.isActive\"\n (change)=\"toggleActive(p, $any($event.target).checked)\" autocomplete=\"off\" />\n </label>\n </td>\n <td class=\"eds-mono-sm\">{{ p.sortOrder }}</td>\n <td class=\"flex gap-3 whitespace-nowrap\">\n <button type=\"button\" class=\"outbound-purposes-page__link cursor-pointer border-none bg-transparent p-0\" (click)=\"openEdit(p)\">\n Edit\n </button>\n <button type=\"button\" class=\"outbound-purposes-page__link cursor-pointer border-none bg-transparent p-0\" (click)=\"deletePurpose(p)\">\n {{ actionLabel(p) }}\n </button>\n </td>\n </tr>\n } @empty {\n <tr>\n <td colspan=\"7\" class=\"eds-body-sm\">No outbound purposes configured.</td>\n </tr>\n }\n </tbody>\n </table>\n </article>\n }\n\n <eds-outbound-purpose-form-modal\n [open]=\"modalOpen()\"\n [purpose]=\"editing()\"\n (closed)=\"closeModal()\"\n (saved)=\"onSaved()\"\n />\n</div>\n"],"names":[],"mappings":"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"}
|