@edvak99/voice-receptionist-widget 1.1.2 → 1.1.3
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 +3 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-analytics-page.component-CW5OKmik.mjs → edvak99-voice-receptionist-widget-analytics-page.component-Dsujn5az.mjs} +4 -4
- package/fesm2022/{edvak99-voice-receptionist-widget-analytics-page.component-CW5OKmik.mjs.map → edvak99-voice-receptionist-widget-analytics-page.component-Dsujn5az.mjs.map} +1 -1
- package/fesm2022/edvak99-voice-receptionist-widget-audit-page.component-xoLlHj8K.mjs +67 -0
- package/fesm2022/edvak99-voice-receptionist-widget-audit-page.component-xoLlHj8K.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-call-history-detail-page.component-CTwfUHUf.mjs → edvak99-voice-receptionist-widget-call-history-detail-page.component-2K9W77As.mjs} +11 -11
- package/fesm2022/{edvak99-voice-receptionist-widget-call-history-detail-page.component-CTwfUHUf.mjs.map → edvak99-voice-receptionist-widget-call-history-detail-page.component-2K9W77As.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-call-history-page.component-Cj4wxd4e.mjs → edvak99-voice-receptionist-widget-call-history-page.component-B5AnEjoh.mjs} +62 -26
- package/fesm2022/edvak99-voice-receptionist-widget-call-history-page.component-B5AnEjoh.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-call-recording-player.component-AN6GcSDq.mjs → edvak99-voice-receptionist-widget-call-recording-player.component-B8_qp7Fe.mjs} +4 -4
- package/fesm2022/{edvak99-voice-receptionist-widget-call-recording-player.component-AN6GcSDq.mjs.map → edvak99-voice-receptionist-widget-call-recording-player.component-B8_qp7Fe.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-call-review.service-Cy_Bf7AO.mjs → edvak99-voice-receptionist-widget-call-review.service-Cj2XTeK4.mjs} +2 -2
- package/fesm2022/{edvak99-voice-receptionist-widget-call-review.service-Cy_Bf7AO.mjs.map → edvak99-voice-receptionist-widget-call-review.service-Cj2XTeK4.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-call-review.util-DQLIw7xb.mjs → edvak99-voice-receptionist-widget-call-review.util-BgsBCKgZ.mjs} +2 -2
- package/fesm2022/{edvak99-voice-receptionist-widget-call-review.util-DQLIw7xb.mjs.map → edvak99-voice-receptionist-widget-call-review.util-BgsBCKgZ.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-dashboard-page.component-DzdIt2A7.mjs → edvak99-voice-receptionist-widget-dashboard-page.component-BNdnbAVM.mjs} +10 -10
- package/fesm2022/{edvak99-voice-receptionist-widget-dashboard-page.component-DzdIt2A7.mjs.map → edvak99-voice-receptionist-widget-dashboard-page.component-BNdnbAVM.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-eds-avatar.component-PCnIWeOA.mjs → edvak99-voice-receptionist-widget-eds-avatar.component-CbphhP6o.mjs} +3 -3
- package/fesm2022/{edvak99-voice-receptionist-widget-eds-avatar.component-PCnIWeOA.mjs.map → edvak99-voice-receptionist-widget-eds-avatar.component-CbphhP6o.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-eds-elapsed.pipe-ouRlPpwT.mjs → edvak99-voice-receptionist-widget-eds-elapsed.pipe-BgLsnq6A.mjs} +2 -2
- package/fesm2022/{edvak99-voice-receptionist-widget-eds-elapsed.pipe-ouRlPpwT.mjs.map → edvak99-voice-receptionist-widget-eds-elapsed.pipe-BgLsnq6A.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-CMhknpGf.mjs → edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-Dn0GrZ6_.mjs} +106 -48
- package/fesm2022/edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-Dn0GrZ6_.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-knowledge-hub.page-cZqBuull.mjs → edvak99-voice-receptionist-widget-knowledge-hub.page-BngGx_Lc.mjs} +70 -36
- package/fesm2022/edvak99-voice-receptionist-widget-knowledge-hub.page-BngGx_Lc.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-live-calls-list.service-CDtFRW8w.mjs → edvak99-voice-receptionist-widget-live-calls-list.service-0kGWO6sh.mjs} +3 -3
- package/fesm2022/{edvak99-voice-receptionist-widget-live-calls-list.service-CDtFRW8w.mjs.map → edvak99-voice-receptionist-widget-live-calls-list.service-0kGWO6sh.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-live-calls-page.component-DrYzXJQW.mjs → edvak99-voice-receptionist-widget-live-calls-page.component-DfLmK89M.mjs} +7 -7
- package/fesm2022/{edvak99-voice-receptionist-widget-live-calls-page.component-DrYzXJQW.mjs.map → edvak99-voice-receptionist-widget-live-calls-page.component-DfLmK89M.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-live-monitor-page.component-D7dlk0y2.mjs → edvak99-voice-receptionist-widget-live-monitor-page.component-DNpLFqBw.mjs} +11 -11
- package/fesm2022/{edvak99-voice-receptionist-widget-live-monitor-page.component-D7dlk0y2.mjs.map → edvak99-voice-receptionist-widget-live-monitor-page.component-DNpLFqBw.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-outbound-purposes-page.component-CJ8NEjcj.mjs → edvak99-voice-receptionist-widget-outbound-purposes-page.component-CYSZ832p.mjs} +6 -6
- package/fesm2022/{edvak99-voice-receptionist-widget-outbound-purposes-page.component-CJ8NEjcj.mjs.map → edvak99-voice-receptionist-widget-outbound-purposes-page.component-CYSZ832p.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-settings-page.component-Bo3XNK3b.mjs → edvak99-voice-receptionist-widget-settings-page.component-B9nv6wtB.mjs} +4 -4
- package/fesm2022/{edvak99-voice-receptionist-widget-settings-page.component-Bo3XNK3b.mjs.map → edvak99-voice-receptionist-widget-settings-page.component-B9nv6wtB.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-tasks-page.component-CBwl15NP.mjs → edvak99-voice-receptionist-widget-tasks-page.component-DXxjMVUv.mjs} +40 -11
- package/fesm2022/edvak99-voice-receptionist-widget-tasks-page.component-DXxjMVUv.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-wizard-page.component-CJLa5pia.mjs → edvak99-voice-receptionist-widget-wizard-page.component-C1Z6yC0q.mjs} +4 -4
- package/fesm2022/{edvak99-voice-receptionist-widget-wizard-page.component-CJLa5pia.mjs.map → edvak99-voice-receptionist-widget-wizard-page.component-C1Z6yC0q.mjs.map} +1 -1
- package/fesm2022/edvak99-voice-receptionist-widget.mjs +1 -1
- package/lib/knowledge/models/practice-faq.model.d.ts +3 -0
- package/lib/knowledge/pages/knowledge-hub.page.d.ts +8 -1
- package/lib/knowledge/services/practice-faq-api.service.d.ts +6 -2
- package/lib/models/ai-receptionist.types.d.ts +1 -0
- package/lib/models/pagination.d.ts +11 -0
- package/lib/pages/audit-page/audit-page.component.d.ts +7 -0
- package/lib/pages/call-history-page/call-history-page.component.d.ts +7 -3
- package/lib/pages/tasks-page/tasks-page.component.d.ts +6 -0
- package/lib/services/ai-receptionist-api.mock.d.ts +10 -9
- package/lib/services/ai-receptionist-api.service.d.ts +9 -9
- package/package.json +1 -1
- package/styles/_index.scss +5 -40
- package/styles/chat-ui.scss +18 -18
- package/styles/eds.scss +135 -95
- package/fesm2022/edvak99-voice-receptionist-widget-audit-page.component-DL1GfQyF.mjs +0 -35
- package/fesm2022/edvak99-voice-receptionist-widget-audit-page.component-DL1GfQyF.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-call-history-page.component-Cj4wxd4e.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-CMhknpGf.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-knowledge-hub.page-cZqBuull.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-tasks-page.component-CBwl15NP.mjs.map +0 -1
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, signal,
|
|
2
|
+
import { inject, signal, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
3
|
import { ActivatedRoute, Router } from '@angular/router';
|
|
4
4
|
import { DatePipe } from '@angular/common';
|
|
5
5
|
import * as i1 from '@angular/forms';
|
|
6
6
|
import { FormsModule } from '@angular/forms';
|
|
7
|
-
import { A as AiReceptionistApiService, T as ToastService, a as EdsBadgeComponent, E as EdsButtonComponent, b as EdsIconComponent } from './edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-
|
|
8
|
-
import { C as CallReviewService } from './edvak99-voice-receptionist-widget-call-review.service-
|
|
9
|
-
import {
|
|
10
|
-
import { E as EdsAvatarComponent } from './edvak99-voice-receptionist-widget-eds-avatar.component-
|
|
7
|
+
import { A as AiReceptionistApiService, T as ToastService, D as DEFAULT_PAGE_SIZE, f as totalPages, a as EdsBadgeComponent, E as EdsButtonComponent, b as EdsIconComponent } from './edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-Dn0GrZ6_.mjs';
|
|
8
|
+
import { C as CallReviewService } from './edvak99-voice-receptionist-widget-call-review.service-Cj2XTeK4.mjs';
|
|
9
|
+
import { r as reviewLabel, a as reviewBadgeTone, i as isNeedsReview, o as outcomeBadgeTone, f as formatOutcomeLabel } from './edvak99-voice-receptionist-widget-call-review.util-BgsBCKgZ.mjs';
|
|
10
|
+
import { E as EdsAvatarComponent } from './edvak99-voice-receptionist-widget-eds-avatar.component-CbphhP6o.mjs';
|
|
11
11
|
|
|
12
12
|
class CallHistoryPageComponent {
|
|
13
13
|
constructor() {
|
|
@@ -16,7 +16,10 @@ class CallHistoryPageComponent {
|
|
|
16
16
|
this.toast = inject(ToastService);
|
|
17
17
|
this.route = inject(ActivatedRoute);
|
|
18
18
|
this.router = inject(Router);
|
|
19
|
-
this.
|
|
19
|
+
this.pageSize = DEFAULT_PAGE_SIZE;
|
|
20
|
+
this.rows = signal([]);
|
|
21
|
+
this.total = signal(0);
|
|
22
|
+
this.page = signal(1);
|
|
20
23
|
this.loading = signal(true);
|
|
21
24
|
this.reviewingId = signal(null);
|
|
22
25
|
this.search = signal('');
|
|
@@ -29,11 +32,6 @@ class CallHistoryPageComponent {
|
|
|
29
32
|
{ id: 'needs', label: 'Needs review' },
|
|
30
33
|
{ id: 'reviewed', label: 'Reviewed' },
|
|
31
34
|
];
|
|
32
|
-
this.rows = computed(() => {
|
|
33
|
-
const tab = this.reviewTab();
|
|
34
|
-
return this.allRows().filter((row) => matchesReviewFilter(row.review, tab));
|
|
35
|
-
});
|
|
36
|
-
this.needsReviewCount = computed(() => this.allRows().filter((r) => isNeedsReview(r.review)).length);
|
|
37
35
|
this.reviewLabel = reviewLabel;
|
|
38
36
|
this.reviewTone = reviewBadgeTone;
|
|
39
37
|
this.isNeedsReview = isNeedsReview;
|
|
@@ -49,51 +47,80 @@ class CallHistoryPageComponent {
|
|
|
49
47
|
}
|
|
50
48
|
load() {
|
|
51
49
|
this.loading.set(true);
|
|
50
|
+
const tab = this.reviewTab();
|
|
52
51
|
this.api
|
|
53
52
|
.getHistory({
|
|
54
53
|
q: this.search() || undefined,
|
|
55
54
|
dir: this.direction() || undefined,
|
|
56
55
|
outcome: this.outcome() || undefined,
|
|
57
56
|
location: this.location() || undefined,
|
|
57
|
+
review: tab === 'all' ? undefined : tab,
|
|
58
|
+
page: this.page(),
|
|
59
|
+
limit: DEFAULT_PAGE_SIZE,
|
|
58
60
|
})
|
|
59
|
-
.subscribe(
|
|
60
|
-
|
|
61
|
-
|
|
61
|
+
.subscribe({
|
|
62
|
+
next: ({ items, total, page }) => {
|
|
63
|
+
this.rows.set(items);
|
|
64
|
+
this.total.set(total);
|
|
65
|
+
this.page.set(page);
|
|
66
|
+
this.loading.set(false);
|
|
67
|
+
},
|
|
68
|
+
error: () => this.loading.set(false),
|
|
62
69
|
});
|
|
63
70
|
}
|
|
64
71
|
applyFilters() {
|
|
72
|
+
this.page.set(1);
|
|
65
73
|
this.load();
|
|
66
74
|
}
|
|
67
75
|
setReviewTab(tab) {
|
|
68
76
|
this.reviewTab.set(tab);
|
|
77
|
+
this.page.set(1);
|
|
69
78
|
void this.router.navigate([], {
|
|
70
79
|
relativeTo: this.route,
|
|
71
80
|
queryParams: tab === 'all' ? { review: null } : { review: tab },
|
|
72
81
|
queryParamsHandling: 'merge',
|
|
73
82
|
replaceUrl: true,
|
|
74
83
|
});
|
|
84
|
+
this.load();
|
|
75
85
|
}
|
|
76
86
|
tabBadgeCount(tab) {
|
|
77
|
-
if (tab !== 'needs')
|
|
87
|
+
if (tab !== 'needs' || this.reviewTab() !== 'needs')
|
|
78
88
|
return null;
|
|
79
|
-
const count = this.
|
|
89
|
+
const count = this.total();
|
|
80
90
|
return count > 0 ? count : null;
|
|
81
91
|
}
|
|
92
|
+
totalPages() {
|
|
93
|
+
return totalPages(this.total(), DEFAULT_PAGE_SIZE);
|
|
94
|
+
}
|
|
95
|
+
prevPage() {
|
|
96
|
+
if (this.page() <= 1)
|
|
97
|
+
return;
|
|
98
|
+
this.page.update((p) => p - 1);
|
|
99
|
+
this.load();
|
|
100
|
+
}
|
|
101
|
+
nextPage() {
|
|
102
|
+
if (this.page() >= this.totalPages())
|
|
103
|
+
return;
|
|
104
|
+
this.page.update((p) => p + 1);
|
|
105
|
+
this.load();
|
|
106
|
+
}
|
|
82
107
|
markReviewed(row, event) {
|
|
83
108
|
event.preventDefault();
|
|
84
109
|
event.stopPropagation();
|
|
85
110
|
if (!isNeedsReview(row.review) || this.reviewingId())
|
|
86
111
|
return;
|
|
87
112
|
this.reviewingId.set(row.id);
|
|
88
|
-
this.
|
|
113
|
+
this.rows.update((list) => list.map((r) => (r.id === row.id ? { ...r, review: 'reviewed' } : r)));
|
|
89
114
|
this.reviewService.markReviewed(row.id).subscribe({
|
|
90
115
|
next: () => {
|
|
91
116
|
this.reviewingId.set(null);
|
|
92
117
|
this.toast.show('Call marked as reviewed', 'success');
|
|
118
|
+
if (this.reviewTab() === 'needs')
|
|
119
|
+
this.load();
|
|
93
120
|
},
|
|
94
121
|
error: () => {
|
|
95
122
|
this.reviewingId.set(null);
|
|
96
|
-
this.
|
|
123
|
+
this.rows.update((list) => list.map((r) => (r.id === row.id ? { ...r, review: 'needs' } : r)));
|
|
97
124
|
this.toast.show('Failed to mark call as reviewed', 'error');
|
|
98
125
|
},
|
|
99
126
|
});
|
|
@@ -107,20 +134,29 @@ class CallHistoryPageComponent {
|
|
|
107
134
|
void this.router.navigate(['../history', id], { relativeTo: this.route });
|
|
108
135
|
}
|
|
109
136
|
exportCsv() {
|
|
110
|
-
const header = '
|
|
111
|
-
const
|
|
112
|
-
|
|
137
|
+
const header = ['id', 'name', 'phone', 'direction', 'outcome', 'duration', 'started'];
|
|
138
|
+
const csvRows = this.rows().map((r) => [
|
|
139
|
+
r.id,
|
|
140
|
+
r.name,
|
|
141
|
+
r.phone,
|
|
142
|
+
r.direction,
|
|
143
|
+
r.outcome,
|
|
144
|
+
String(r.duration),
|
|
145
|
+
String(r.started),
|
|
146
|
+
]);
|
|
147
|
+
const csv = [header, ...csvRows]
|
|
148
|
+
.map((row) => row.map((cell) => `"${String(cell).replace(/"/g, '""')}"`).join(','))
|
|
113
149
|
.join('\n');
|
|
114
|
-
const blob = new Blob([
|
|
150
|
+
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8' });
|
|
115
151
|
const url = URL.createObjectURL(blob);
|
|
116
152
|
const a = document.createElement('a');
|
|
117
153
|
a.href = url;
|
|
118
|
-
a.download =
|
|
154
|
+
a.download = `call-history-page-${this.page()}.csv`;
|
|
119
155
|
a.click();
|
|
120
156
|
URL.revokeObjectURL(url);
|
|
121
157
|
}
|
|
122
158
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: CallHistoryPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
123
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: CallHistoryPageComponent, isStandalone: true, selector: "eds-call-history-page", ngImport: i0, template: "<div class=\"eds-page call-history-page\">\n\n <header class=\"call-history-page__header\">\n\n <div>\n\n <h1 class=\"eds-h1\">Call history</h1>\n\n <p class=\"eds-body-sm\">Search and review completed conversations</p>\n\n </div>\n\n <eds-button variant=\"secondary\" (click)=\"exportCsv()\">\n\n <eds-icon name=\"download\" [size]=\"18\" /> Export CSV\n\n </eds-button>\n\n </header>\n\n\n\n <nav class=\"call-history-page__review-tabs\" aria-label=\"Review status\">\n\n @for (t of reviewTabs; track t.id) {\n\n <button\n\n type=\"button\"\n\n class=\"call-history-page__review-tab\"\n\n [class.call-history-page__review-tab--active]=\"reviewTab() === t.id\"\n\n (click)=\"setReviewTab(t.id)\"\n\n >\n\n {{ t.label }}\n\n @if (tabBadgeCount(t.id); as count) {\n\n <span class=\"call-history-page__tab-badge\">{{ count }}</span>\n\n }\n\n </button>\n\n }\n\n </nav>\n\n\n\n <div class=\"eds-card call-history-page__filters\">\n\n <input\n\n type=\"search\"\n\n class=\"call-history-page__search\"\n\n placeholder=\"Search name, phone, reason\u2026\"\n\n [ngModel]=\"search()\"\n\n (ngModelChange)=\"search.set($event)\"\n\n (keyup.enter)=\"applyFilters()\"\n\n />\n\n <select class=\"call-history-page__select\" [ngModel]=\"direction()\" (ngModelChange)=\"direction.set($event)\">\n\n <option value=\"\">All directions</option>\n\n <option value=\"inbound\">Inbound</option>\n\n <option value=\"outbound\">Outbound</option>\n\n </select>\n\n <input\n\n type=\"text\"\n\n class=\"call-history-page__select\"\n\n placeholder=\"Outcome\"\n\n [ngModel]=\"outcome()\"\n\n (ngModelChange)=\"outcome.set($event)\"\n\n />\n\n <input\n\n type=\"text\"\n\n class=\"call-history-page__select\"\n\n placeholder=\"Location\"\n\n [ngModel]=\"location()\"\n\n (ngModelChange)=\"location.set($event)\"\n\n />\n\n <eds-button variant=\"primary\" (click)=\"applyFilters()\">Apply</eds-button>\n\n </div>\n\n\n\n @if (loading()) {\n\n <p class=\"eds-body-sm\">Loading history\u2026</p>\n\n } @else {\n\n <div class=\"eds-card call-history-page__table-wrap\">\n\n <table class=\"eds-table\">\n\n <thead>\n\n <tr>\n\n <th>Caller</th>\n\n <th>Direction</th>\n\n <th>Reason</th>\n\n <th>Status</th>\n\n <th>Duration</th>\n\n <th>Date & time</th>\n\n <th>Review</th>\n\n <th></th>\n\n </tr>\n\n </thead>\n\n <tbody>\n\n @for (row of rows(); track row.id) {\n\n <tr\n class=\"call-history-page__row\"\n [class.call-history-page__row--needs-review]=\"isNeedsReview(row.review)\"\n tabindex=\"0\"\n role=\"link\"\n [attr.aria-label]=\"'View call details for ' + row.name\"\n (click)=\"openCallDetail(row.id)\"\n (keyup.enter)=\"openCallDetail(row.id)\"\n >\n <td>\n <div class=\"call-history-page__caller\">\n <eds-avatar [initials]=\"row.initials\" />\n <span>{{ row.name }}</span>\n </div>\n </td>\n\n <td>{{ row.direction }}</td>\n\n <td>{{ row.reason }}</td>\n\n <td>\n\n <eds-badge [tone]=\"outcomeTone(row.outcome)\">\n\n {{ outcomeLabel(row.outcome) }}\n\n </eds-badge>\n\n </td>\n\n <td class=\"eds-mono-sm\">{{ row.durationLabel ?? formatDuration(row.duration) }}</td>\n\n <td class=\"eds-mono-sm\">\n {{ row.started ? (row.started | date: 'medium') : (row.whenLabel ?? '\u2014') }}\n </td>\n\n <td>\n\n <eds-badge [tone]=\"reviewTone(row.review)\">\n\n {{ reviewLabel(row.review) }}\n\n </eds-badge>\n\n </td>\n\n <td class=\"call-history-page__actions\">\n\n @if (isNeedsReview(row.review)) {\n\n <button\n\n type=\"button\"\n\n class=\"call-history-page__mark-btn\"\n\n title=\"Mark as reviewed\"\n\n [disabled]=\"reviewingId() === row.id\"\n\n (click)=\"markReviewed(row, $event)\"\n\n >\n\n <eds-icon name=\"check_circle\" [size]=\"18\" />\n\n </button>\n\n }\n\n </td>\n\n </tr>\n\n } @empty {\n\n <tr>\n\n <td colspan=\"8\" class=\"eds-body-sm\">No calls match this filter.</td>\n\n </tr>\n\n }\n\n </tbody>\n\n </table>\n\n </div>\n\n }\n\n</div>\n\n\n", styles: [".call-history-page__header{display:flex;align-items:flex-start;justify-content:space-between;margin-bottom:20px}.call-history-page__review-tabs{display:flex;gap:4px;margin-bottom:12px;padding:4px;width:fit-content;background:var(--surface-l1);border-radius:var(--eds-radius-md)}.call-history-page__review-tab{border:none;background:transparent;padding:8px 14px;border-radius:var(--eds-radius-sm);font-size:13px;font-weight:500;cursor:pointer;color:var(--text-secondary);display:inline-flex;align-items:center;gap:6px}.call-history-page__review-tab--active{background:var(--surface-l0);color:var(--text-primary);box-shadow:0 1px 2px #0000000f}.call-history-page__tab-badge{min-width:18px;padding:0 6px;border-radius:999px;background:#f59e0b;color:#fff;font-size:11px;font-weight:700;line-height:18px;text-align:center}.call-history-page__row{cursor:pointer}.call-history-page__row:hover{background:var(--surface-l1)}.call-history-page__row:focus-visible{outline:2px solid var(--brand-500, #0d9488);outline-offset:-2px}.call-history-page__row--needs-review{border-left:3px solid #f59e0b}.call-history-page__actions{width:40px;text-align:center}.call-history-page__mark-btn{border:none;background:transparent;color:var(--green-600, #16a34a);cursor:pointer;padding:4px;border-radius:6px}.call-history-page__mark-btn:hover:not(:disabled){background:#16a34a1a}.call-history-page__mark-btn:disabled{opacity:.5;cursor:wait}.call-history-page__filters{display:flex;flex-wrap:wrap;gap:10px;padding:14px;margin-bottom:16px;align-items:center}.call-history-page__search{flex:1;min-width:200px;padding:8px 12px;border:1px solid var(--border-default);border-radius:var(--eds-radius-md);font-size:14px}.call-history-page__select{padding:8px 12px;border:1px solid var(--border-default);border-radius:var(--eds-radius-md);font-size:13px;background:var(--surface-l0)}.call-history-page__table-wrap{overflow-x:auto;padding:0}.call-history-page__caller{display:flex;align-items:center;gap:8px;font-weight:500}\n"], dependencies: [{ kind: "pipe", type: DatePipe, name: "date" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: EdsAvatarComponent, selector: "eds-avatar", inputs: ["initials", "tone", "gradient"] }, { kind: "component", type: EdsBadgeComponent, selector: "eds-badge", inputs: ["tone"] }, { kind: "component", type: EdsButtonComponent, selector: "eds-button", inputs: ["variant", "type", "disabled"] }, { kind: "component", type: EdsIconComponent, selector: "eds-icon", inputs: ["name", "size", "fill", "weight"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
159
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: CallHistoryPageComponent, isStandalone: true, selector: "eds-call-history-page", ngImport: i0, template: "<div class=\"eds-page call-history-page\">\n\n <header class=\"call-history-page__header\">\n\n <div>\n\n <h1 class=\"eds-h1\">Call history</h1>\n\n <p class=\"eds-body-sm\">Search and review completed conversations</p>\n\n </div>\n\n <eds-button variant=\"secondary\" (click)=\"exportCsv()\">\n\n <eds-icon name=\"download\" [size]=\"18\" /> Export CSV\n\n </eds-button>\n\n </header>\n\n\n\n <nav class=\"call-history-page__review-tabs\" aria-label=\"Review status\">\n\n @for (t of reviewTabs; track t.id) {\n\n <button\n\n type=\"button\"\n\n class=\"call-history-page__review-tab\"\n\n [class.call-history-page__review-tab--active]=\"reviewTab() === t.id\"\n\n (click)=\"setReviewTab(t.id)\"\n\n >\n\n {{ t.label }}\n\n @if (tabBadgeCount(t.id); as count) {\n\n <span class=\"call-history-page__tab-badge\">{{ count }}</span>\n\n }\n\n </button>\n\n }\n\n </nav>\n\n\n\n <div class=\"eds-card call-history-page__filters\">\n\n <input\n\n type=\"search\"\n\n class=\"call-history-page__search\"\n\n placeholder=\"Search name, phone, reason\u2026\"\n\n [ngModel]=\"search()\"\n\n (ngModelChange)=\"search.set($event)\"\n\n (keyup.enter)=\"applyFilters()\"\n\n />\n\n <select class=\"call-history-page__select\" [ngModel]=\"direction()\" (ngModelChange)=\"direction.set($event)\">\n\n <option value=\"\">All directions</option>\n\n <option value=\"inbound\">Inbound</option>\n\n <option value=\"outbound\">Outbound</option>\n\n </select>\n\n <input\n\n type=\"text\"\n\n class=\"call-history-page__select\"\n\n placeholder=\"Outcome\"\n\n [ngModel]=\"outcome()\"\n\n (ngModelChange)=\"outcome.set($event)\"\n\n />\n\n <input\n\n type=\"text\"\n\n class=\"call-history-page__select\"\n\n placeholder=\"Location\"\n\n [ngModel]=\"location()\"\n\n (ngModelChange)=\"location.set($event)\"\n\n />\n\n <eds-button variant=\"primary\" (click)=\"applyFilters()\">Apply</eds-button>\n\n </div>\n\n\n\n @if (loading()) {\n\n <p class=\"eds-body-sm\">Loading history\u2026</p>\n\n } @else {\n\n <div class=\"eds-card call-history-page__table-wrap\">\n\n <table class=\"eds-table\">\n\n <thead>\n\n <tr>\n\n <th>Caller</th>\n\n <th>Direction</th>\n\n <th>Reason</th>\n\n <th>Status</th>\n\n <th>Duration</th>\n\n <th>Date & time</th>\n\n <th>Review</th>\n\n <th></th>\n\n </tr>\n\n </thead>\n\n <tbody>\n\n @for (row of rows(); track row.id) {\n\n <tr\n class=\"call-history-page__row\"\n [class.call-history-page__row--needs-review]=\"isNeedsReview(row.review)\"\n tabindex=\"0\"\n role=\"link\"\n [attr.aria-label]=\"'View call details for ' + row.name\"\n (click)=\"openCallDetail(row.id)\"\n (keyup.enter)=\"openCallDetail(row.id)\"\n >\n <td>\n <div class=\"call-history-page__caller\">\n <eds-avatar [initials]=\"row.initials\" />\n <span>{{ row.name }}</span>\n </div>\n </td>\n\n <td>{{ row.direction }}</td>\n\n <td>{{ row.reason }}</td>\n\n <td>\n\n <eds-badge [tone]=\"outcomeTone(row.outcome)\">\n\n {{ outcomeLabel(row.outcome) }}\n\n </eds-badge>\n\n </td>\n\n <td class=\"eds-mono-sm\">{{ row.durationLabel ?? formatDuration(row.duration) }}</td>\n\n <td class=\"eds-mono-sm\">\n {{ row.started ? (row.started | date: 'medium') : (row.whenLabel ?? '\u2014') }}\n </td>\n\n <td>\n\n <eds-badge [tone]=\"reviewTone(row.review)\">\n\n {{ reviewLabel(row.review) }}\n\n </eds-badge>\n\n </td>\n\n <td class=\"call-history-page__actions\">\n\n @if (isNeedsReview(row.review)) {\n\n <button\n\n type=\"button\"\n\n class=\"call-history-page__mark-btn\"\n\n title=\"Mark as reviewed\"\n\n [disabled]=\"reviewingId() === row.id\"\n\n (click)=\"markReviewed(row, $event)\"\n\n >\n\n <eds-icon name=\"check_circle\" [size]=\"18\" />\n\n </button>\n\n }\n\n </td>\n\n </tr>\n\n } @empty {\n\n <tr>\n\n <td colspan=\"8\" class=\"eds-body-sm\">No calls match this filter.</td>\n\n </tr>\n\n }\n\n </tbody>\n\n </table>\n\n </div>\n\n }\n\n\n <footer class=\"call-history-page__pager\">\n <span class=\"eds-body-sm\">\n Page {{ page() }} of {{ totalPages() }} \u00B7 {{ total() }} total\n </span>\n <div class=\"call-history-page__pager-actions\">\n <eds-button variant=\"secondary\" [disabled]=\"page() <= 1\" (click)=\"prevPage()\">Previous</eds-button>\n <eds-button variant=\"secondary\" [disabled]=\"page() >= totalPages()\" (click)=\"nextPage()\">Next</eds-button>\n </div>\n </footer>\n\n</div>\n\n\n", styles: [".call-history-page__header{display:flex;align-items:flex-start;justify-content:space-between;margin-bottom:20px}.call-history-page__review-tabs{display:flex;gap:4px;margin-bottom:12px;padding:4px;width:fit-content;background:var(--eds-surface-l1);border-radius:var(--eds-radius-md)}.call-history-page__review-tab{border:none;background:transparent;padding:8px 14px;border-radius:var(--eds-radius-sm);font-size:13px;font-weight:500;cursor:pointer;color:var(--eds-text-secondary);display:inline-flex;align-items:center;gap:6px}.call-history-page__review-tab--active{background:var(--eds-surface-l0);color:var(--eds-text-primary);box-shadow:0 1px 2px #0000000f}.call-history-page__tab-badge{min-width:18px;padding:0 6px;border-radius:999px;background:#f59e0b;color:#fff;font-size:11px;font-weight:700;line-height:18px;text-align:center}.call-history-page__row{cursor:pointer}.call-history-page__row:hover{background:var(--eds-surface-l1)}.call-history-page__row:focus-visible{outline:2px solid var(--eds-brand-500, #0d9488);outline-offset:-2px}.call-history-page__row--needs-review{border-left:3px solid #f59e0b}.call-history-page__actions{width:40px;text-align:center}.call-history-page__mark-btn{border:none;background:transparent;color:var(--eds-green-600, #16a34a);cursor:pointer;padding:4px;border-radius:6px}.call-history-page__mark-btn:hover:not(:disabled){background:#16a34a1a}.call-history-page__mark-btn:disabled{opacity:.5;cursor:wait}.call-history-page__filters{display:flex;flex-wrap:wrap;gap:10px;padding:14px;margin-bottom:16px;align-items:center}.call-history-page__search{flex:1;min-width:200px;padding:8px 12px;border:1px solid var(--eds-border-default);border-radius:var(--eds-radius-md);font-size:14px}.call-history-page__select{padding:8px 12px;border:1px solid var(--eds-border-default);border-radius:var(--eds-radius-md);font-size:13px;background:var(--eds-surface-l0)}.call-history-page__table-wrap{overflow-x:auto;padding:0}.call-history-page__caller{display:flex;align-items:center;gap:8px;font-weight:500}.call-history-page__pager{display:flex;align-items:center;justify-content:space-between;margin-top:16px;padding-top:12px;border-top:1px solid var(--eds-border-subtle, #e4e4e7)}.call-history-page__pager-actions{display:flex;gap:8px}\n"], dependencies: [{ kind: "pipe", type: DatePipe, name: "date" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: EdsAvatarComponent, selector: "eds-avatar", inputs: ["initials", "tone", "gradient"] }, { kind: "component", type: EdsBadgeComponent, selector: "eds-badge", inputs: ["tone"] }, { kind: "component", type: EdsButtonComponent, selector: "eds-button", inputs: ["variant", "type", "disabled"] }, { kind: "component", type: EdsIconComponent, selector: "eds-icon", inputs: ["name", "size", "fill", "weight"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
124
160
|
}
|
|
125
161
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: CallHistoryPageComponent, decorators: [{
|
|
126
162
|
type: Component,
|
|
@@ -131,8 +167,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
131
167
|
EdsBadgeComponent,
|
|
132
168
|
EdsButtonComponent,
|
|
133
169
|
EdsIconComponent,
|
|
134
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"eds-page call-history-page\">\n\n <header class=\"call-history-page__header\">\n\n <div>\n\n <h1 class=\"eds-h1\">Call history</h1>\n\n <p class=\"eds-body-sm\">Search and review completed conversations</p>\n\n </div>\n\n <eds-button variant=\"secondary\" (click)=\"exportCsv()\">\n\n <eds-icon name=\"download\" [size]=\"18\" /> Export CSV\n\n </eds-button>\n\n </header>\n\n\n\n <nav class=\"call-history-page__review-tabs\" aria-label=\"Review status\">\n\n @for (t of reviewTabs; track t.id) {\n\n <button\n\n type=\"button\"\n\n class=\"call-history-page__review-tab\"\n\n [class.call-history-page__review-tab--active]=\"reviewTab() === t.id\"\n\n (click)=\"setReviewTab(t.id)\"\n\n >\n\n {{ t.label }}\n\n @if (tabBadgeCount(t.id); as count) {\n\n <span class=\"call-history-page__tab-badge\">{{ count }}</span>\n\n }\n\n </button>\n\n }\n\n </nav>\n\n\n\n <div class=\"eds-card call-history-page__filters\">\n\n <input\n\n type=\"search\"\n\n class=\"call-history-page__search\"\n\n placeholder=\"Search name, phone, reason\u2026\"\n\n [ngModel]=\"search()\"\n\n (ngModelChange)=\"search.set($event)\"\n\n (keyup.enter)=\"applyFilters()\"\n\n />\n\n <select class=\"call-history-page__select\" [ngModel]=\"direction()\" (ngModelChange)=\"direction.set($event)\">\n\n <option value=\"\">All directions</option>\n\n <option value=\"inbound\">Inbound</option>\n\n <option value=\"outbound\">Outbound</option>\n\n </select>\n\n <input\n\n type=\"text\"\n\n class=\"call-history-page__select\"\n\n placeholder=\"Outcome\"\n\n [ngModel]=\"outcome()\"\n\n (ngModelChange)=\"outcome.set($event)\"\n\n />\n\n <input\n\n type=\"text\"\n\n class=\"call-history-page__select\"\n\n placeholder=\"Location\"\n\n [ngModel]=\"location()\"\n\n (ngModelChange)=\"location.set($event)\"\n\n />\n\n <eds-button variant=\"primary\" (click)=\"applyFilters()\">Apply</eds-button>\n\n </div>\n\n\n\n @if (loading()) {\n\n <p class=\"eds-body-sm\">Loading history\u2026</p>\n\n } @else {\n\n <div class=\"eds-card call-history-page__table-wrap\">\n\n <table class=\"eds-table\">\n\n <thead>\n\n <tr>\n\n <th>Caller</th>\n\n <th>Direction</th>\n\n <th>Reason</th>\n\n <th>Status</th>\n\n <th>Duration</th>\n\n <th>Date & time</th>\n\n <th>Review</th>\n\n <th></th>\n\n </tr>\n\n </thead>\n\n <tbody>\n\n @for (row of rows(); track row.id) {\n\n <tr\n class=\"call-history-page__row\"\n [class.call-history-page__row--needs-review]=\"isNeedsReview(row.review)\"\n tabindex=\"0\"\n role=\"link\"\n [attr.aria-label]=\"'View call details for ' + row.name\"\n (click)=\"openCallDetail(row.id)\"\n (keyup.enter)=\"openCallDetail(row.id)\"\n >\n <td>\n <div class=\"call-history-page__caller\">\n <eds-avatar [initials]=\"row.initials\" />\n <span>{{ row.name }}</span>\n </div>\n </td>\n\n <td>{{ row.direction }}</td>\n\n <td>{{ row.reason }}</td>\n\n <td>\n\n <eds-badge [tone]=\"outcomeTone(row.outcome)\">\n\n {{ outcomeLabel(row.outcome) }}\n\n </eds-badge>\n\n </td>\n\n <td class=\"eds-mono-sm\">{{ row.durationLabel ?? formatDuration(row.duration) }}</td>\n\n <td class=\"eds-mono-sm\">\n {{ row.started ? (row.started | date: 'medium') : (row.whenLabel ?? '\u2014') }}\n </td>\n\n <td>\n\n <eds-badge [tone]=\"reviewTone(row.review)\">\n\n {{ reviewLabel(row.review) }}\n\n </eds-badge>\n\n </td>\n\n <td class=\"call-history-page__actions\">\n\n @if (isNeedsReview(row.review)) {\n\n <button\n\n type=\"button\"\n\n class=\"call-history-page__mark-btn\"\n\n title=\"Mark as reviewed\"\n\n [disabled]=\"reviewingId() === row.id\"\n\n (click)=\"markReviewed(row, $event)\"\n\n >\n\n <eds-icon name=\"check_circle\" [size]=\"18\" />\n\n </button>\n\n }\n\n </td>\n\n </tr>\n\n } @empty {\n\n <tr>\n\n <td colspan=\"8\" class=\"eds-body-sm\">No calls match this filter.</td>\n\n </tr>\n\n }\n\n </tbody>\n\n </table>\n\n </div>\n\n }\n\n</div>\n\n\n", styles: [".call-history-page__header{display:flex;align-items:flex-start;justify-content:space-between;margin-bottom:20px}.call-history-page__review-tabs{display:flex;gap:4px;margin-bottom:12px;padding:4px;width:fit-content;background:var(--surface-l1);border-radius:var(--eds-radius-md)}.call-history-page__review-tab{border:none;background:transparent;padding:8px 14px;border-radius:var(--eds-radius-sm);font-size:13px;font-weight:500;cursor:pointer;color:var(--text-secondary);display:inline-flex;align-items:center;gap:6px}.call-history-page__review-tab--active{background:var(--surface-l0);color:var(--text-primary);box-shadow:0 1px 2px #0000000f}.call-history-page__tab-badge{min-width:18px;padding:0 6px;border-radius:999px;background:#f59e0b;color:#fff;font-size:11px;font-weight:700;line-height:18px;text-align:center}.call-history-page__row{cursor:pointer}.call-history-page__row:hover{background:var(--surface-l1)}.call-history-page__row:focus-visible{outline:2px solid var(--brand-500, #0d9488);outline-offset:-2px}.call-history-page__row--needs-review{border-left:3px solid #f59e0b}.call-history-page__actions{width:40px;text-align:center}.call-history-page__mark-btn{border:none;background:transparent;color:var(--green-600, #16a34a);cursor:pointer;padding:4px;border-radius:6px}.call-history-page__mark-btn:hover:not(:disabled){background:#16a34a1a}.call-history-page__mark-btn:disabled{opacity:.5;cursor:wait}.call-history-page__filters{display:flex;flex-wrap:wrap;gap:10px;padding:14px;margin-bottom:16px;align-items:center}.call-history-page__search{flex:1;min-width:200px;padding:8px 12px;border:1px solid var(--border-default);border-radius:var(--eds-radius-md);font-size:14px}.call-history-page__select{padding:8px 12px;border:1px solid var(--border-default);border-radius:var(--eds-radius-md);font-size:13px;background:var(--surface-l0)}.call-history-page__table-wrap{overflow-x:auto;padding:0}.call-history-page__caller{display:flex;align-items:center;gap:8px;font-weight:500}\n"] }]
|
|
170
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"eds-page call-history-page\">\n\n <header class=\"call-history-page__header\">\n\n <div>\n\n <h1 class=\"eds-h1\">Call history</h1>\n\n <p class=\"eds-body-sm\">Search and review completed conversations</p>\n\n </div>\n\n <eds-button variant=\"secondary\" (click)=\"exportCsv()\">\n\n <eds-icon name=\"download\" [size]=\"18\" /> Export CSV\n\n </eds-button>\n\n </header>\n\n\n\n <nav class=\"call-history-page__review-tabs\" aria-label=\"Review status\">\n\n @for (t of reviewTabs; track t.id) {\n\n <button\n\n type=\"button\"\n\n class=\"call-history-page__review-tab\"\n\n [class.call-history-page__review-tab--active]=\"reviewTab() === t.id\"\n\n (click)=\"setReviewTab(t.id)\"\n\n >\n\n {{ t.label }}\n\n @if (tabBadgeCount(t.id); as count) {\n\n <span class=\"call-history-page__tab-badge\">{{ count }}</span>\n\n }\n\n </button>\n\n }\n\n </nav>\n\n\n\n <div class=\"eds-card call-history-page__filters\">\n\n <input\n\n type=\"search\"\n\n class=\"call-history-page__search\"\n\n placeholder=\"Search name, phone, reason\u2026\"\n\n [ngModel]=\"search()\"\n\n (ngModelChange)=\"search.set($event)\"\n\n (keyup.enter)=\"applyFilters()\"\n\n />\n\n <select class=\"call-history-page__select\" [ngModel]=\"direction()\" (ngModelChange)=\"direction.set($event)\">\n\n <option value=\"\">All directions</option>\n\n <option value=\"inbound\">Inbound</option>\n\n <option value=\"outbound\">Outbound</option>\n\n </select>\n\n <input\n\n type=\"text\"\n\n class=\"call-history-page__select\"\n\n placeholder=\"Outcome\"\n\n [ngModel]=\"outcome()\"\n\n (ngModelChange)=\"outcome.set($event)\"\n\n />\n\n <input\n\n type=\"text\"\n\n class=\"call-history-page__select\"\n\n placeholder=\"Location\"\n\n [ngModel]=\"location()\"\n\n (ngModelChange)=\"location.set($event)\"\n\n />\n\n <eds-button variant=\"primary\" (click)=\"applyFilters()\">Apply</eds-button>\n\n </div>\n\n\n\n @if (loading()) {\n\n <p class=\"eds-body-sm\">Loading history\u2026</p>\n\n } @else {\n\n <div class=\"eds-card call-history-page__table-wrap\">\n\n <table class=\"eds-table\">\n\n <thead>\n\n <tr>\n\n <th>Caller</th>\n\n <th>Direction</th>\n\n <th>Reason</th>\n\n <th>Status</th>\n\n <th>Duration</th>\n\n <th>Date & time</th>\n\n <th>Review</th>\n\n <th></th>\n\n </tr>\n\n </thead>\n\n <tbody>\n\n @for (row of rows(); track row.id) {\n\n <tr\n class=\"call-history-page__row\"\n [class.call-history-page__row--needs-review]=\"isNeedsReview(row.review)\"\n tabindex=\"0\"\n role=\"link\"\n [attr.aria-label]=\"'View call details for ' + row.name\"\n (click)=\"openCallDetail(row.id)\"\n (keyup.enter)=\"openCallDetail(row.id)\"\n >\n <td>\n <div class=\"call-history-page__caller\">\n <eds-avatar [initials]=\"row.initials\" />\n <span>{{ row.name }}</span>\n </div>\n </td>\n\n <td>{{ row.direction }}</td>\n\n <td>{{ row.reason }}</td>\n\n <td>\n\n <eds-badge [tone]=\"outcomeTone(row.outcome)\">\n\n {{ outcomeLabel(row.outcome) }}\n\n </eds-badge>\n\n </td>\n\n <td class=\"eds-mono-sm\">{{ row.durationLabel ?? formatDuration(row.duration) }}</td>\n\n <td class=\"eds-mono-sm\">\n {{ row.started ? (row.started | date: 'medium') : (row.whenLabel ?? '\u2014') }}\n </td>\n\n <td>\n\n <eds-badge [tone]=\"reviewTone(row.review)\">\n\n {{ reviewLabel(row.review) }}\n\n </eds-badge>\n\n </td>\n\n <td class=\"call-history-page__actions\">\n\n @if (isNeedsReview(row.review)) {\n\n <button\n\n type=\"button\"\n\n class=\"call-history-page__mark-btn\"\n\n title=\"Mark as reviewed\"\n\n [disabled]=\"reviewingId() === row.id\"\n\n (click)=\"markReviewed(row, $event)\"\n\n >\n\n <eds-icon name=\"check_circle\" [size]=\"18\" />\n\n </button>\n\n }\n\n </td>\n\n </tr>\n\n } @empty {\n\n <tr>\n\n <td colspan=\"8\" class=\"eds-body-sm\">No calls match this filter.</td>\n\n </tr>\n\n }\n\n </tbody>\n\n </table>\n\n </div>\n\n }\n\n\n <footer class=\"call-history-page__pager\">\n <span class=\"eds-body-sm\">\n Page {{ page() }} of {{ totalPages() }} \u00B7 {{ total() }} total\n </span>\n <div class=\"call-history-page__pager-actions\">\n <eds-button variant=\"secondary\" [disabled]=\"page() <= 1\" (click)=\"prevPage()\">Previous</eds-button>\n <eds-button variant=\"secondary\" [disabled]=\"page() >= totalPages()\" (click)=\"nextPage()\">Next</eds-button>\n </div>\n </footer>\n\n</div>\n\n\n", styles: [".call-history-page__header{display:flex;align-items:flex-start;justify-content:space-between;margin-bottom:20px}.call-history-page__review-tabs{display:flex;gap:4px;margin-bottom:12px;padding:4px;width:fit-content;background:var(--eds-surface-l1);border-radius:var(--eds-radius-md)}.call-history-page__review-tab{border:none;background:transparent;padding:8px 14px;border-radius:var(--eds-radius-sm);font-size:13px;font-weight:500;cursor:pointer;color:var(--eds-text-secondary);display:inline-flex;align-items:center;gap:6px}.call-history-page__review-tab--active{background:var(--eds-surface-l0);color:var(--eds-text-primary);box-shadow:0 1px 2px #0000000f}.call-history-page__tab-badge{min-width:18px;padding:0 6px;border-radius:999px;background:#f59e0b;color:#fff;font-size:11px;font-weight:700;line-height:18px;text-align:center}.call-history-page__row{cursor:pointer}.call-history-page__row:hover{background:var(--eds-surface-l1)}.call-history-page__row:focus-visible{outline:2px solid var(--eds-brand-500, #0d9488);outline-offset:-2px}.call-history-page__row--needs-review{border-left:3px solid #f59e0b}.call-history-page__actions{width:40px;text-align:center}.call-history-page__mark-btn{border:none;background:transparent;color:var(--eds-green-600, #16a34a);cursor:pointer;padding:4px;border-radius:6px}.call-history-page__mark-btn:hover:not(:disabled){background:#16a34a1a}.call-history-page__mark-btn:disabled{opacity:.5;cursor:wait}.call-history-page__filters{display:flex;flex-wrap:wrap;gap:10px;padding:14px;margin-bottom:16px;align-items:center}.call-history-page__search{flex:1;min-width:200px;padding:8px 12px;border:1px solid var(--eds-border-default);border-radius:var(--eds-radius-md);font-size:14px}.call-history-page__select{padding:8px 12px;border:1px solid var(--eds-border-default);border-radius:var(--eds-radius-md);font-size:13px;background:var(--eds-surface-l0)}.call-history-page__table-wrap{overflow-x:auto;padding:0}.call-history-page__caller{display:flex;align-items:center;gap:8px;font-weight:500}.call-history-page__pager{display:flex;align-items:center;justify-content:space-between;margin-top:16px;padding-top:12px;border-top:1px solid var(--eds-border-subtle, #e4e4e7)}.call-history-page__pager-actions{display:flex;gap:8px}\n"] }]
|
|
135
171
|
}] });
|
|
136
172
|
|
|
137
173
|
export { CallHistoryPageComponent };
|
|
138
|
-
//# sourceMappingURL=edvak99-voice-receptionist-widget-call-history-page.component-
|
|
174
|
+
//# sourceMappingURL=edvak99-voice-receptionist-widget-call-history-page.component-B5AnEjoh.mjs.map
|
package/fesm2022/edvak99-voice-receptionist-widget-call-history-page.component-B5AnEjoh.mjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edvak99-voice-receptionist-widget-call-history-page.component-B5AnEjoh.mjs","sources":["../../../projects/voice-receptionist-widget/src/lib/pages/call-history-page/call-history-page.component.ts","../../../projects/voice-receptionist-widget/src/lib/pages/call-history-page/call-history-page.component.html"],"sourcesContent":["import { ChangeDetectionStrategy, Component, inject, OnInit, signal } from '@angular/core';\nimport { ActivatedRoute, Router } from '@angular/router';\nimport { DatePipe } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\n\nimport { HistoryCall } from '../../models/ai-receptionist.types';\nimport { DEFAULT_PAGE_SIZE, totalPages as calcTotalPages } from '../../models/pagination';\nimport { AiReceptionistApiService } from '../../services/ai-receptionist-api.service';\nimport { CallReviewService } from '../../services/call-review.service';\nimport { formatOutcomeLabel, outcomeBadgeTone } from '../../utils/call-outcome.util';\nimport {\n isNeedsReview,\n reviewBadgeTone,\n reviewLabel,\n ReviewFilterTab,\n} from '../../utils/call-review.util';\nimport { EdsAvatarComponent } from '../../ui/eds-avatar.component';\nimport { EdsBadgeComponent } from '../../ui/eds-badge.component';\nimport { EdsButtonComponent } from '../../ui/eds-button.component';\nimport { EdsIconComponent } from '../../ui/eds-icon.component';\nimport { ToastService } from '../../shared/toast.service';\n\n@Component({\n selector: 'eds-call-history-page',\n imports: [\n DatePipe,\n FormsModule,\n EdsAvatarComponent,\n EdsBadgeComponent,\n EdsButtonComponent,\n EdsIconComponent,\n ],\n templateUrl: './call-history-page.component.html',\n styleUrl: './call-history-page.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class CallHistoryPageComponent implements OnInit {\n private readonly api = inject(AiReceptionistApiService);\n private readonly reviewService = inject(CallReviewService);\n private readonly toast = inject(ToastService);\n private readonly route = inject(ActivatedRoute);\n private readonly router = inject(Router);\n\n protected readonly pageSize = DEFAULT_PAGE_SIZE;\n protected readonly rows = signal<HistoryCall[]>([]);\n protected readonly total = signal(0);\n protected readonly page = signal(1);\n protected readonly loading = signal(true);\n protected readonly reviewingId = signal<string | null>(null);\n protected readonly search = signal('');\n protected readonly direction = signal('');\n protected readonly outcome = signal('');\n protected readonly location = signal('');\n protected readonly reviewTab = signal<ReviewFilterTab>('all');\n\n protected readonly reviewTabs: { id: ReviewFilterTab; label: string }[] = [\n { id: 'all', label: 'All' },\n { id: 'needs', label: 'Needs review' },\n { id: 'reviewed', label: 'Reviewed' },\n ];\n\n protected reviewLabel = reviewLabel;\n protected reviewTone = reviewBadgeTone;\n protected isNeedsReview = isNeedsReview;\n protected outcomeTone = outcomeBadgeTone;\n protected outcomeLabel = formatOutcomeLabel;\n\n ngOnInit(): void {\n const reviewParam = this.route.snapshot.queryParamMap.get('review');\n if (reviewParam === 'needs' || reviewParam === 'reviewed') {\n this.reviewTab.set(reviewParam);\n }\n this.load();\n }\n\n protected load(): void {\n this.loading.set(true);\n const tab = this.reviewTab();\n this.api\n .getHistory({\n q: this.search() || undefined,\n dir: this.direction() || undefined,\n outcome: this.outcome() || undefined,\n location: this.location() || undefined,\n review: tab === 'all' ? undefined : tab,\n page: this.page(),\n limit: DEFAULT_PAGE_SIZE,\n })\n .subscribe({\n next: ({ items, total, page }) => {\n this.rows.set(items);\n this.total.set(total);\n this.page.set(page);\n this.loading.set(false);\n },\n error: () => this.loading.set(false),\n });\n }\n\n protected applyFilters(): void {\n this.page.set(1);\n this.load();\n }\n\n protected setReviewTab(tab: ReviewFilterTab): void {\n this.reviewTab.set(tab);\n this.page.set(1);\n void this.router.navigate([], {\n relativeTo: this.route,\n queryParams: tab === 'all' ? { review: null } : { review: tab },\n queryParamsHandling: 'merge',\n replaceUrl: true,\n });\n this.load();\n }\n\n protected tabBadgeCount(tab: ReviewFilterTab): number | null {\n if (tab !== 'needs' || this.reviewTab() !== 'needs') return null;\n const count = this.total();\n return count > 0 ? count : null;\n }\n\n protected totalPages(): number {\n return calcTotalPages(this.total(), DEFAULT_PAGE_SIZE);\n }\n\n protected prevPage(): void {\n if (this.page() <= 1) return;\n this.page.update((p) => p - 1);\n this.load();\n }\n\n protected nextPage(): void {\n if (this.page() >= this.totalPages()) return;\n this.page.update((p) => p + 1);\n this.load();\n }\n\n protected markReviewed(row: HistoryCall, event: Event): void {\n event.preventDefault();\n event.stopPropagation();\n if (!isNeedsReview(row.review) || this.reviewingId()) return;\n\n this.reviewingId.set(row.id);\n this.rows.update((list) =>\n list.map((r) => (r.id === row.id ? { ...r, review: 'reviewed' as const } : r)),\n );\n\n this.reviewService.markReviewed(row.id).subscribe({\n next: () => {\n this.reviewingId.set(null);\n this.toast.show('Call marked as reviewed', 'success');\n if (this.reviewTab() === 'needs') this.load();\n },\n error: () => {\n this.reviewingId.set(null);\n this.rows.update((list) =>\n list.map((r) => (r.id === row.id ? { ...r, review: 'needs' as const } : r)),\n );\n this.toast.show('Failed to mark call as reviewed', 'error');\n },\n });\n }\n\n protected formatDuration(sec: number): string {\n const m = Math.floor(sec / 60);\n const s = sec % 60;\n return `${m}:${s.toString().padStart(2, '0')}`;\n }\n\n protected openCallDetail(id: string): void {\n void this.router.navigate(['../history', id], { relativeTo: this.route });\n }\n\n protected exportCsv(): void {\n const header = ['id', 'name', 'phone', 'direction', 'outcome', 'duration', 'started'];\n const csvRows = this.rows().map((r) => [\n r.id,\n r.name,\n r.phone,\n r.direction,\n r.outcome,\n String(r.duration),\n String(r.started),\n ]);\n const csv = [header, ...csvRows]\n .map((row) => row.map((cell) => `\"${String(cell).replace(/\"/g, '\"\"')}\"`).join(','))\n .join('\\n');\n const blob = new Blob([csv], { type: 'text/csv;charset=utf-8' });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = `call-history-page-${this.page()}.csv`;\n a.click();\n URL.revokeObjectURL(url);\n }\n}\n","<div class=\"eds-page call-history-page\">\n\n <header class=\"call-history-page__header\">\n\n <div>\n\n <h1 class=\"eds-h1\">Call history</h1>\n\n <p class=\"eds-body-sm\">Search and review completed conversations</p>\n\n </div>\n\n <eds-button variant=\"secondary\" (click)=\"exportCsv()\">\n\n <eds-icon name=\"download\" [size]=\"18\" /> Export CSV\n\n </eds-button>\n\n </header>\n\n\n\n <nav class=\"call-history-page__review-tabs\" aria-label=\"Review status\">\n\n @for (t of reviewTabs; track t.id) {\n\n <button\n\n type=\"button\"\n\n class=\"call-history-page__review-tab\"\n\n [class.call-history-page__review-tab--active]=\"reviewTab() === t.id\"\n\n (click)=\"setReviewTab(t.id)\"\n\n >\n\n {{ t.label }}\n\n @if (tabBadgeCount(t.id); as count) {\n\n <span class=\"call-history-page__tab-badge\">{{ count }}</span>\n\n }\n\n </button>\n\n }\n\n </nav>\n\n\n\n <div class=\"eds-card call-history-page__filters\">\n\n <input\n\n type=\"search\"\n\n class=\"call-history-page__search\"\n\n placeholder=\"Search name, phone, reason…\"\n\n [ngModel]=\"search()\"\n\n (ngModelChange)=\"search.set($event)\"\n\n (keyup.enter)=\"applyFilters()\"\n\n />\n\n <select class=\"call-history-page__select\" [ngModel]=\"direction()\" (ngModelChange)=\"direction.set($event)\">\n\n <option value=\"\">All directions</option>\n\n <option value=\"inbound\">Inbound</option>\n\n <option value=\"outbound\">Outbound</option>\n\n </select>\n\n <input\n\n type=\"text\"\n\n class=\"call-history-page__select\"\n\n placeholder=\"Outcome\"\n\n [ngModel]=\"outcome()\"\n\n (ngModelChange)=\"outcome.set($event)\"\n\n />\n\n <input\n\n type=\"text\"\n\n class=\"call-history-page__select\"\n\n placeholder=\"Location\"\n\n [ngModel]=\"location()\"\n\n (ngModelChange)=\"location.set($event)\"\n\n />\n\n <eds-button variant=\"primary\" (click)=\"applyFilters()\">Apply</eds-button>\n\n </div>\n\n\n\n @if (loading()) {\n\n <p class=\"eds-body-sm\">Loading history…</p>\n\n } @else {\n\n <div class=\"eds-card call-history-page__table-wrap\">\n\n <table class=\"eds-table\">\n\n <thead>\n\n <tr>\n\n <th>Caller</th>\n\n <th>Direction</th>\n\n <th>Reason</th>\n\n <th>Status</th>\n\n <th>Duration</th>\n\n <th>Date & time</th>\n\n <th>Review</th>\n\n <th></th>\n\n </tr>\n\n </thead>\n\n <tbody>\n\n @for (row of rows(); track row.id) {\n\n <tr\n class=\"call-history-page__row\"\n [class.call-history-page__row--needs-review]=\"isNeedsReview(row.review)\"\n tabindex=\"0\"\n role=\"link\"\n [attr.aria-label]=\"'View call details for ' + row.name\"\n (click)=\"openCallDetail(row.id)\"\n (keyup.enter)=\"openCallDetail(row.id)\"\n >\n <td>\n <div class=\"call-history-page__caller\">\n <eds-avatar [initials]=\"row.initials\" />\n <span>{{ row.name }}</span>\n </div>\n </td>\n\n <td>{{ row.direction }}</td>\n\n <td>{{ row.reason }}</td>\n\n <td>\n\n <eds-badge [tone]=\"outcomeTone(row.outcome)\">\n\n {{ outcomeLabel(row.outcome) }}\n\n </eds-badge>\n\n </td>\n\n <td class=\"eds-mono-sm\">{{ row.durationLabel ?? formatDuration(row.duration) }}</td>\n\n <td class=\"eds-mono-sm\">\n {{ row.started ? (row.started | date: 'medium') : (row.whenLabel ?? '—') }}\n </td>\n\n <td>\n\n <eds-badge [tone]=\"reviewTone(row.review)\">\n\n {{ reviewLabel(row.review) }}\n\n </eds-badge>\n\n </td>\n\n <td class=\"call-history-page__actions\">\n\n @if (isNeedsReview(row.review)) {\n\n <button\n\n type=\"button\"\n\n class=\"call-history-page__mark-btn\"\n\n title=\"Mark as reviewed\"\n\n [disabled]=\"reviewingId() === row.id\"\n\n (click)=\"markReviewed(row, $event)\"\n\n >\n\n <eds-icon name=\"check_circle\" [size]=\"18\" />\n\n </button>\n\n }\n\n </td>\n\n </tr>\n\n } @empty {\n\n <tr>\n\n <td colspan=\"8\" class=\"eds-body-sm\">No calls match this filter.</td>\n\n </tr>\n\n }\n\n </tbody>\n\n </table>\n\n </div>\n\n }\n\n\n <footer class=\"call-history-page__pager\">\n <span class=\"eds-body-sm\">\n Page {{ page() }} of {{ totalPages() }} · {{ total() }} total\n </span>\n <div class=\"call-history-page__pager-actions\">\n <eds-button variant=\"secondary\" [disabled]=\"page() <= 1\" (click)=\"prevPage()\">Previous</eds-button>\n <eds-button variant=\"secondary\" [disabled]=\"page() >= totalPages()\" (click)=\"nextPage()\">Next</eds-button>\n </div>\n </footer>\n\n</div>\n\n\n"],"names":["calcTotalPages"],"mappings":";;;;;;;;;;;MAoCa,wBAAwB,CAAA;AAdrC,IAAA,WAAA,GAAA;AAemB,QAAA,IAAA,CAAA,GAAG,GAAG,MAAM,CAAC,wBAAwB,CAAC;AACtC,QAAA,IAAA,CAAA,aAAa,GAAG,MAAM,CAAC,iBAAiB,CAAC;AACzC,QAAA,IAAA,CAAA,KAAK,GAAG,MAAM,CAAC,YAAY,CAAC;AAC5B,QAAA,IAAA,CAAA,KAAK,GAAG,MAAM,CAAC,cAAc,CAAC;AAC9B,QAAA,IAAA,CAAA,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;QAErB,IAAA,CAAA,QAAQ,GAAG,iBAAiB;AAC5B,QAAA,IAAA,CAAA,IAAI,GAAG,MAAM,CAAgB,EAAE,CAAC;AAChC,QAAA,IAAA,CAAA,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC;AACjB,QAAA,IAAA,CAAA,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC;AAChB,QAAA,IAAA,CAAA,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC;AACtB,QAAA,IAAA,CAAA,WAAW,GAAG,MAAM,CAAgB,IAAI,CAAC;AACzC,QAAA,IAAA,CAAA,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;AACnB,QAAA,IAAA,CAAA,SAAS,GAAG,MAAM,CAAC,EAAE,CAAC;AACtB,QAAA,IAAA,CAAA,OAAO,GAAG,MAAM,CAAC,EAAE,CAAC;AACpB,QAAA,IAAA,CAAA,QAAQ,GAAG,MAAM,CAAC,EAAE,CAAC;AACrB,QAAA,IAAA,CAAA,SAAS,GAAG,MAAM,CAAkB,KAAK,CAAC;AAE1C,QAAA,IAAA,CAAA,UAAU,GAA6C;AACxE,YAAA,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE;AAC3B,YAAA,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE;AACtC,YAAA,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE;SACtC;QAES,IAAA,CAAA,WAAW,GAAG,WAAW;QACzB,IAAA,CAAA,UAAU,GAAG,eAAe;QAC5B,IAAA,CAAA,aAAa,GAAG,aAAa;QAC7B,IAAA,CAAA,WAAW,GAAG,gBAAgB;QAC9B,IAAA,CAAA,YAAY,GAAG,kBAAkB;AAmI5C,IAAA;IAjIC,QAAQ,GAAA;AACN,QAAA,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC;QACnE,IAAI,WAAW,KAAK,OAAO,IAAI,WAAW,KAAK,UAAU,EAAE;AACzD,YAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC;QACjC;QACA,IAAI,CAAC,IAAI,EAAE;IACb;IAEU,IAAI,GAAA;AACZ,QAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;AACtB,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,EAAE;AAC5B,QAAA,IAAI,CAAC;AACF,aAAA,UAAU,CAAC;AACV,YAAA,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,SAAS;AAC7B,YAAA,GAAG,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,SAAS;AAClC,YAAA,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,SAAS;AACpC,YAAA,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,SAAS;YACtC,MAAM,EAAE,GAAG,KAAK,KAAK,GAAG,SAAS,GAAG,GAAG;AACvC,YAAA,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE;AACjB,YAAA,KAAK,EAAE,iBAAiB;SACzB;AACA,aAAA,SAAS,CAAC;YACT,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,KAAI;AAC/B,gBAAA,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;AACpB,gBAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC;AACrB,gBAAA,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;AACnB,gBAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;YACzB,CAAC;YACD,KAAK,EAAE,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;AACrC,SAAA,CAAC;IACN;IAEU,YAAY,GAAA;AACpB,QAAA,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QAChB,IAAI,CAAC,IAAI,EAAE;IACb;AAEU,IAAA,YAAY,CAAC,GAAoB,EAAA;AACzC,QAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC;AACvB,QAAA,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAChB,QAAA,KAAK,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,EAAE;YAC5B,UAAU,EAAE,IAAI,CAAC,KAAK;AACtB,YAAA,WAAW,EAAE,GAAG,KAAK,KAAK,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE;AAC/D,YAAA,mBAAmB,EAAE,OAAO;AAC5B,YAAA,UAAU,EAAE,IAAI;AACjB,SAAA,CAAC;QACF,IAAI,CAAC,IAAI,EAAE;IACb;AAEU,IAAA,aAAa,CAAC,GAAoB,EAAA;QAC1C,IAAI,GAAG,KAAK,OAAO,IAAI,IAAI,CAAC,SAAS,EAAE,KAAK,OAAO;AAAE,YAAA,OAAO,IAAI;AAChE,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,EAAE;QAC1B,OAAO,KAAK,GAAG,CAAC,GAAG,KAAK,GAAG,IAAI;IACjC;IAEU,UAAU,GAAA;QAClB,OAAOA,UAAc,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,iBAAiB,CAAC;IACxD;IAEU,QAAQ,GAAA;AAChB,QAAA,IAAI,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC;YAAE;AACtB,QAAA,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC9B,IAAI,CAAC,IAAI,EAAE;IACb;IAEU,QAAQ,GAAA;QAChB,IAAI,IAAI,CAAC,IAAI,EAAE,IAAI,IAAI,CAAC,UAAU,EAAE;YAAE;AACtC,QAAA,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC9B,IAAI,CAAC,IAAI,EAAE;IACb;IAEU,YAAY,CAAC,GAAgB,EAAE,KAAY,EAAA;QACnD,KAAK,CAAC,cAAc,EAAE;QACtB,KAAK,CAAC,eAAe,EAAE;QACvB,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,WAAW,EAAE;YAAE;QAEtD,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;QAC5B,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,KACpB,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,UAAmB,EAAE,GAAG,CAAC,CAAC,CAAC,CAC/E;QAED,IAAI,CAAC,aAAa,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC;YAChD,IAAI,EAAE,MAAK;AACT,gBAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;gBAC1B,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,yBAAyB,EAAE,SAAS,CAAC;AACrD,gBAAA,IAAI,IAAI,CAAC,SAAS,EAAE,KAAK,OAAO;oBAAE,IAAI,CAAC,IAAI,EAAE;YAC/C,CAAC;YACD,KAAK,EAAE,MAAK;AACV,gBAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;gBAC1B,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,KACpB,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,OAAgB,EAAE,GAAG,CAAC,CAAC,CAAC,CAC5E;gBACD,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,iCAAiC,EAAE,OAAO,CAAC;YAC7D,CAAC;AACF,SAAA,CAAC;IACJ;AAEU,IAAA,cAAc,CAAC,GAAW,EAAA;QAClC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,EAAE,CAAC;AAC9B,QAAA,MAAM,CAAC,GAAG,GAAG,GAAG,EAAE;AAClB,QAAA,OAAO,CAAA,EAAG,CAAC,CAAA,CAAA,EAAI,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;IAChD;AAEU,IAAA,cAAc,CAAC,EAAU,EAAA;QACjC,KAAK,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,EAAE,EAAE,UAAU,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;IAC3E;IAEU,SAAS,GAAA;AACjB,QAAA,MAAM,MAAM,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,CAAC;AACrF,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK;AACrC,YAAA,CAAC,CAAC,EAAE;AACJ,YAAA,CAAC,CAAC,IAAI;AACN,YAAA,CAAC,CAAC,KAAK;AACP,YAAA,CAAC,CAAC,SAAS;AACX,YAAA,CAAC,CAAC,OAAO;AACT,YAAA,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC;AAClB,YAAA,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;AAClB,SAAA,CAAC;AACF,QAAA,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,GAAG,OAAO;AAC5B,aAAA,GAAG,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,CAAA,CAAA,EAAI,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA,CAAA,CAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;aACjF,IAAI,CAAC,IAAI,CAAC;AACb,QAAA,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,EAAE,wBAAwB,EAAE,CAAC;QAChE,MAAM,GAAG,GAAG,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC;QACrC,MAAM,CAAC,GAAG,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC;AACrC,QAAA,CAAC,CAAC,IAAI,GAAG,GAAG;QACZ,CAAC,CAAC,QAAQ,GAAG,CAAA,kBAAA,EAAqB,IAAI,CAAC,IAAI,EAAE,CAAA,IAAA,CAAM;QACnD,CAAC,CAAC,KAAK,EAAE;AACT,QAAA,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC;IAC1B;+GA/JW,wBAAwB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;AAAxB,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,wBAAwB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,uBAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,ECpCrC,u0KAoQA,EAAA,MAAA,EAAA,CAAA,wtEAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,ED3OI,QAAQ,EAAA,IAAA,EAAA,MAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EACR,WAAW,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,cAAA,EAAA,QAAA,EAAA,QAAA,EAAA,MAAA,EAAA,CAAA,SAAA,EAAA,OAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,uBAAA,EAAA,QAAA,EAAA,QAAA,EAAA,MAAA,EAAA,CAAA,SAAA,EAAA,OAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,oBAAA,EAAA,QAAA,EAAA,8MAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,0BAAA,EAAA,QAAA,EAAA,6GAAA,EAAA,MAAA,EAAA,CAAA,aAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,eAAA,EAAA,QAAA,EAAA,2CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,OAAA,EAAA,QAAA,EAAA,qDAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,UAAA,EAAA,SAAA,EAAA,gBAAA,CAAA,EAAA,OAAA,EAAA,CAAA,eAAA,CAAA,EAAA,QAAA,EAAA,CAAA,SAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACX,kBAAkB,EAAA,QAAA,EAAA,YAAA,EAAA,MAAA,EAAA,CAAA,UAAA,EAAA,MAAA,EAAA,UAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAClB,iBAAiB,EAAA,QAAA,EAAA,WAAA,EAAA,MAAA,EAAA,CAAA,MAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACjB,kBAAkB,gGAClB,gBAAgB,EAAA,QAAA,EAAA,UAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,QAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA,CAAA;;4FAMP,wBAAwB,EAAA,UAAA,EAAA,CAAA;kBAdpC,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,uBAAuB,EAAA,OAAA,EACxB;wBACP,QAAQ;wBACR,WAAW;wBACX,kBAAkB;wBAClB,iBAAiB;wBACjB,kBAAkB;wBAClB,gBAAgB;qBACjB,EAAA,eAAA,EAGgB,uBAAuB,CAAC,MAAM,EAAA,QAAA,EAAA,u0KAAA,EAAA,MAAA,EAAA,CAAA,wtEAAA,CAAA,EAAA;;;;;"}
|
|
@@ -2,7 +2,7 @@ import * as i0 from '@angular/core';
|
|
|
2
2
|
import { input, output, viewChild, inject, DestroyRef, signal, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
3
|
import { toObservable, takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
4
4
|
import { distinctUntilChanged, tap, switchMap, EMPTY, map, catchError } from 'rxjs';
|
|
5
|
-
import { A as AiReceptionistApiService, b as EdsIconComponent } from './edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-
|
|
5
|
+
import { A as AiReceptionistApiService, b as EdsIconComponent } from './edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-Dn0GrZ6_.mjs';
|
|
6
6
|
|
|
7
7
|
class CallRecordingPlayerComponent {
|
|
8
8
|
constructor() {
|
|
@@ -99,12 +99,12 @@ class CallRecordingPlayerComponent {
|
|
|
99
99
|
this.message.set(null);
|
|
100
100
|
}
|
|
101
101
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: CallRecordingPlayerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
102
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: CallRecordingPlayerComponent, isStandalone: true, selector: "eds-call-recording-player", inputs: { callId: { classPropertyName: "callId", publicName: "callId", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { currentTimeChange: "currentTimeChange", durationChange: "durationChange" }, viewQueries: [{ propertyName: "audioRef", first: true, predicate: ["audioEl"], descendants: true, isSignal: true }], ngImport: i0, template: "<section class=\"call-recording-player\" aria-labelledby=\"call-recording-title\">\n <header class=\"call-recording-player__header\">\n <eds-icon name=\"graphic_eq\" [size]=\"20\" />\n <h3 id=\"call-recording-title\" class=\"eds-h3\">Call recording</h3>\n @if (durationSeconds(); as dur) {\n <span class=\"eds-mono-sm call-recording-player__duration\">{{ formatDuration(dur) }}</span>\n }\n </header>\n\n @switch (phase()) {\n @case ('loading') {\n <p class=\"call-recording-player__status eds-body-sm\">Loading recording\u2026</p>\n }\n @case ('ready') {\n @if (blobUrl(); as src) {\n <audio\n #audioEl\n class=\"call-recording-player__audio\"\n controls\n [src]=\"src\"\n (error)=\"onAudioError()\"\n (timeupdate)=\"onTimeUpdate($event)\"\n (loadedmetadata)=\"onLoadedMetadata($event)\"\n >\n Your browser does not support audio playback.\n </audio>\n }\n }\n @case ('pending') {\n <p class=\"call-recording-player__status eds-body-sm\">\n {{ message() ?? 'Recording is still processing\u2026' }}\n </p>\n }\n @case ('unavailable') {\n <p class=\"call-recording-player__status eds-body-sm call-recording-player__status--muted\">\n {{ message() ?? 'No recording available for this call.' }}\n </p>\n }\n @case ('failed') {\n <p class=\"call-recording-player__status eds-body-sm call-recording-player__status--error\">\n {{ message() ?? 'Recording could not be retrieved.' }}\n </p>\n }\n @case ('error') {\n <p class=\"call-recording-player__status eds-body-sm call-recording-player__status--error\">\n {{ message() ?? 'Playback error.' }}\n </p>\n }\n }\n</section>\n", styles: [".call-recording-player{display:flex;flex-direction:column;gap:12px;padding:16px;border-radius:var(--eds-radius-md);background:var(--surface-l1);border:1px solid var(--border-default)}.call-recording-player__header{display:flex;align-items:center;gap:8px}.call-recording-player__header .eds-h3{margin:0;flex:1}.call-recording-player__duration{color:var(--text-secondary)}.call-recording-player__status{margin:0;color:var(--text-secondary)}.call-recording-player__status--muted{color:var(--text-secondary)}.call-recording-player__status--error{color:var(--red-500, #dc2626)}.call-recording-player__audio{width:100%;height:40px}\n"], dependencies: [{ kind: "component", type: EdsIconComponent, selector: "eds-icon", inputs: ["name", "size", "fill", "weight"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
102
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: CallRecordingPlayerComponent, isStandalone: true, selector: "eds-call-recording-player", inputs: { callId: { classPropertyName: "callId", publicName: "callId", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { currentTimeChange: "currentTimeChange", durationChange: "durationChange" }, viewQueries: [{ propertyName: "audioRef", first: true, predicate: ["audioEl"], descendants: true, isSignal: true }], ngImport: i0, template: "<section class=\"call-recording-player\" aria-labelledby=\"call-recording-title\">\n <header class=\"call-recording-player__header\">\n <eds-icon name=\"graphic_eq\" [size]=\"20\" />\n <h3 id=\"call-recording-title\" class=\"eds-h3\">Call recording</h3>\n @if (durationSeconds(); as dur) {\n <span class=\"eds-mono-sm call-recording-player__duration\">{{ formatDuration(dur) }}</span>\n }\n </header>\n\n @switch (phase()) {\n @case ('loading') {\n <p class=\"call-recording-player__status eds-body-sm\">Loading recording\u2026</p>\n }\n @case ('ready') {\n @if (blobUrl(); as src) {\n <audio\n #audioEl\n class=\"call-recording-player__audio\"\n controls\n [src]=\"src\"\n (error)=\"onAudioError()\"\n (timeupdate)=\"onTimeUpdate($event)\"\n (loadedmetadata)=\"onLoadedMetadata($event)\"\n >\n Your browser does not support audio playback.\n </audio>\n }\n }\n @case ('pending') {\n <p class=\"call-recording-player__status eds-body-sm\">\n {{ message() ?? 'Recording is still processing\u2026' }}\n </p>\n }\n @case ('unavailable') {\n <p class=\"call-recording-player__status eds-body-sm call-recording-player__status--muted\">\n {{ message() ?? 'No recording available for this call.' }}\n </p>\n }\n @case ('failed') {\n <p class=\"call-recording-player__status eds-body-sm call-recording-player__status--error\">\n {{ message() ?? 'Recording could not be retrieved.' }}\n </p>\n }\n @case ('error') {\n <p class=\"call-recording-player__status eds-body-sm call-recording-player__status--error\">\n {{ message() ?? 'Playback error.' }}\n </p>\n }\n }\n</section>\n", styles: [".call-recording-player{display:flex;flex-direction:column;gap:12px;padding:16px;border-radius:var(--eds-radius-md);background:var(--eds-surface-l1);border:1px solid var(--eds-border-default)}.call-recording-player__header{display:flex;align-items:center;gap:8px}.call-recording-player__header .eds-h3{margin:0;flex:1}.call-recording-player__duration{color:var(--eds-text-secondary)}.call-recording-player__status{margin:0;color:var(--eds-text-secondary)}.call-recording-player__status--muted{color:var(--eds-text-secondary)}.call-recording-player__status--error{color:var(--eds-red-500, #dc2626)}.call-recording-player__audio{width:100%;height:40px}\n"], dependencies: [{ kind: "component", type: EdsIconComponent, selector: "eds-icon", inputs: ["name", "size", "fill", "weight"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
103
103
|
}
|
|
104
104
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: CallRecordingPlayerComponent, decorators: [{
|
|
105
105
|
type: Component,
|
|
106
|
-
args: [{ selector: 'eds-call-recording-player', imports: [EdsIconComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<section class=\"call-recording-player\" aria-labelledby=\"call-recording-title\">\n <header class=\"call-recording-player__header\">\n <eds-icon name=\"graphic_eq\" [size]=\"20\" />\n <h3 id=\"call-recording-title\" class=\"eds-h3\">Call recording</h3>\n @if (durationSeconds(); as dur) {\n <span class=\"eds-mono-sm call-recording-player__duration\">{{ formatDuration(dur) }}</span>\n }\n </header>\n\n @switch (phase()) {\n @case ('loading') {\n <p class=\"call-recording-player__status eds-body-sm\">Loading recording\u2026</p>\n }\n @case ('ready') {\n @if (blobUrl(); as src) {\n <audio\n #audioEl\n class=\"call-recording-player__audio\"\n controls\n [src]=\"src\"\n (error)=\"onAudioError()\"\n (timeupdate)=\"onTimeUpdate($event)\"\n (loadedmetadata)=\"onLoadedMetadata($event)\"\n >\n Your browser does not support audio playback.\n </audio>\n }\n }\n @case ('pending') {\n <p class=\"call-recording-player__status eds-body-sm\">\n {{ message() ?? 'Recording is still processing\u2026' }}\n </p>\n }\n @case ('unavailable') {\n <p class=\"call-recording-player__status eds-body-sm call-recording-player__status--muted\">\n {{ message() ?? 'No recording available for this call.' }}\n </p>\n }\n @case ('failed') {\n <p class=\"call-recording-player__status eds-body-sm call-recording-player__status--error\">\n {{ message() ?? 'Recording could not be retrieved.' }}\n </p>\n }\n @case ('error') {\n <p class=\"call-recording-player__status eds-body-sm call-recording-player__status--error\">\n {{ message() ?? 'Playback error.' }}\n </p>\n }\n }\n</section>\n", styles: [".call-recording-player{display:flex;flex-direction:column;gap:12px;padding:16px;border-radius:var(--eds-radius-md);background:var(--surface-l1);border:1px solid var(--border-default)}.call-recording-player__header{display:flex;align-items:center;gap:8px}.call-recording-player__header .eds-h3{margin:0;flex:1}.call-recording-player__duration{color:var(--text-secondary)}.call-recording-player__status{margin:0;color:var(--text-secondary)}.call-recording-player__status--muted{color:var(--text-secondary)}.call-recording-player__status--error{color:var(--red-500, #dc2626)}.call-recording-player__audio{width:100%;height:40px}\n"] }]
|
|
106
|
+
args: [{ selector: 'eds-call-recording-player', imports: [EdsIconComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<section class=\"call-recording-player\" aria-labelledby=\"call-recording-title\">\n <header class=\"call-recording-player__header\">\n <eds-icon name=\"graphic_eq\" [size]=\"20\" />\n <h3 id=\"call-recording-title\" class=\"eds-h3\">Call recording</h3>\n @if (durationSeconds(); as dur) {\n <span class=\"eds-mono-sm call-recording-player__duration\">{{ formatDuration(dur) }}</span>\n }\n </header>\n\n @switch (phase()) {\n @case ('loading') {\n <p class=\"call-recording-player__status eds-body-sm\">Loading recording\u2026</p>\n }\n @case ('ready') {\n @if (blobUrl(); as src) {\n <audio\n #audioEl\n class=\"call-recording-player__audio\"\n controls\n [src]=\"src\"\n (error)=\"onAudioError()\"\n (timeupdate)=\"onTimeUpdate($event)\"\n (loadedmetadata)=\"onLoadedMetadata($event)\"\n >\n Your browser does not support audio playback.\n </audio>\n }\n }\n @case ('pending') {\n <p class=\"call-recording-player__status eds-body-sm\">\n {{ message() ?? 'Recording is still processing\u2026' }}\n </p>\n }\n @case ('unavailable') {\n <p class=\"call-recording-player__status eds-body-sm call-recording-player__status--muted\">\n {{ message() ?? 'No recording available for this call.' }}\n </p>\n }\n @case ('failed') {\n <p class=\"call-recording-player__status eds-body-sm call-recording-player__status--error\">\n {{ message() ?? 'Recording could not be retrieved.' }}\n </p>\n }\n @case ('error') {\n <p class=\"call-recording-player__status eds-body-sm call-recording-player__status--error\">\n {{ message() ?? 'Playback error.' }}\n </p>\n }\n }\n</section>\n", styles: [".call-recording-player{display:flex;flex-direction:column;gap:12px;padding:16px;border-radius:var(--eds-radius-md);background:var(--eds-surface-l1);border:1px solid var(--eds-border-default)}.call-recording-player__header{display:flex;align-items:center;gap:8px}.call-recording-player__header .eds-h3{margin:0;flex:1}.call-recording-player__duration{color:var(--eds-text-secondary)}.call-recording-player__status{margin:0;color:var(--eds-text-secondary)}.call-recording-player__status--muted{color:var(--eds-text-secondary)}.call-recording-player__status--error{color:var(--eds-red-500, #dc2626)}.call-recording-player__audio{width:100%;height:40px}\n"] }]
|
|
107
107
|
}], ctorParameters: () => [] });
|
|
108
108
|
|
|
109
109
|
export { CallRecordingPlayerComponent as C };
|
|
110
|
-
//# sourceMappingURL=edvak99-voice-receptionist-widget-call-recording-player.component-
|
|
110
|
+
//# sourceMappingURL=edvak99-voice-receptionist-widget-call-recording-player.component-B8_qp7Fe.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"edvak99-voice-receptionist-widget-call-recording-player.component-AN6GcSDq.mjs","sources":["../../../projects/voice-receptionist-widget/src/lib/components/call-recording-player/call-recording-player.component.ts","../../../projects/voice-receptionist-widget/src/lib/components/call-recording-player/call-recording-player.component.html"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n ElementRef,\n inject,\n input,\n output,\n signal,\n viewChild,\n} from '@angular/core';\nimport { takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop';\nimport { catchError, distinctUntilChanged, EMPTY, map, switchMap, tap } from 'rxjs';\n\nimport { CallRecordingStatus } from '../../models/ai-receptionist.types';\nimport { AiReceptionistApiService } from '../../services/ai-receptionist-api.service';\nimport { EdsIconComponent } from '../../ui/eds-icon.component';\n\ntype PlayerPhase = 'loading' | CallRecordingStatus | 'error';\n\n@Component({\n selector: 'eds-call-recording-player',\n imports: [EdsIconComponent],\n templateUrl: './call-recording-player.component.html',\n styleUrl: './call-recording-player.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class CallRecordingPlayerComponent {\n readonly callId = input.required<string>();\n readonly currentTimeChange = output<number>();\n readonly durationChange = output<number>();\n\n private readonly audioRef = viewChild<ElementRef<HTMLAudioElement>>('audioEl');\n\n private readonly api = inject(AiReceptionistApiService);\n private readonly destroyRef = inject(DestroyRef);\n\n protected readonly phase = signal<PlayerPhase>('loading');\n protected readonly blobUrl = signal<string | null>(null);\n protected readonly durationSeconds = signal<number | null>(null);\n protected readonly message = signal<string | null>(null);\n\n /** Tracked outside signals so cleanup never reads blobUrl (avoids effect/subscription loops). */\n private objectUrl: string | null = null;\n\n constructor() {\n toObservable(this.callId)\n .pipe(\n distinctUntilChanged(),\n tap(() => this.revokeObjectUrl()),\n switchMap((id) => {\n if (!id) {\n this.resetUi();\n return EMPTY;\n }\n this.phase.set('loading');\n this.message.set(null);\n return this.api.getCallRecording(id).pipe(\n switchMap((meta) => {\n if (meta.status !== 'ready' || !meta.url) {\n this.phase.set(meta.status);\n this.message.set(meta.message ?? null);\n this.durationSeconds.set(meta.durationSeconds ?? null);\n return EMPTY;\n }\n this.durationSeconds.set(meta.durationSeconds ?? null);\n return this.api.getCallRecordingBlob(meta.url).pipe(\n map((blob) => blob),\n catchError(() => {\n this.phase.set('error');\n this.message.set('Could not load recording audio.');\n return EMPTY;\n }),\n );\n }),\n catchError(() => {\n this.phase.set('unavailable');\n this.message.set('Could not load recording metadata.');\n return EMPTY;\n }),\n );\n }),\n takeUntilDestroyed(),\n )\n .subscribe((blob) => {\n this.revokeObjectUrl();\n this.objectUrl = URL.createObjectURL(blob);\n this.blobUrl.set(this.objectUrl);\n this.phase.set('ready');\n this.message.set(null);\n const dur = this.durationSeconds();\n if (dur != null && dur > 0) {\n this.durationChange.emit(dur);\n }\n });\n\n this.destroyRef.onDestroy(() => this.revokeObjectUrl());\n }\n\n protected formatDuration(seconds: number): string {\n const m = Math.floor(seconds / 60);\n const s = seconds % 60;\n return `${m}:${s.toString().padStart(2, '0')}`;\n }\n\n protected onAudioError(): void {\n this.phase.set('error');\n this.message.set('Playback error — try reloading the page.');\n }\n\n protected onTimeUpdate(event: Event): void {\n const el = event.target as HTMLAudioElement;\n this.currentTimeChange.emit(el.currentTime);\n }\n\n protected onLoadedMetadata(event: Event): void {\n const el = event.target as HTMLAudioElement;\n if (Number.isFinite(el.duration) && el.duration > 0) {\n this.durationChange.emit(el.duration);\n }\n }\n\n /** Seek playback — used by synced transcript lines. */\n seekTo(seconds: number): void {\n const el = this.audioRef()?.nativeElement;\n if (!el) return;\n el.currentTime = Math.max(0, seconds);\n void el.play().catch(() => undefined);\n this.currentTimeChange.emit(el.currentTime);\n }\n\n private revokeObjectUrl(): void {\n if (this.objectUrl) {\n URL.revokeObjectURL(this.objectUrl);\n this.objectUrl = null;\n }\n this.blobUrl.set(null);\n }\n\n private resetUi(): void {\n this.phase.set('loading');\n this.durationSeconds.set(null);\n this.message.set(null);\n }\n}\n","<section class=\"call-recording-player\" aria-labelledby=\"call-recording-title\">\n <header class=\"call-recording-player__header\">\n <eds-icon name=\"graphic_eq\" [size]=\"20\" />\n <h3 id=\"call-recording-title\" class=\"eds-h3\">Call recording</h3>\n @if (durationSeconds(); as dur) {\n <span class=\"eds-mono-sm call-recording-player__duration\">{{ formatDuration(dur) }}</span>\n }\n </header>\n\n @switch (phase()) {\n @case ('loading') {\n <p class=\"call-recording-player__status eds-body-sm\">Loading recording…</p>\n }\n @case ('ready') {\n @if (blobUrl(); as src) {\n <audio\n #audioEl\n class=\"call-recording-player__audio\"\n controls\n [src]=\"src\"\n (error)=\"onAudioError()\"\n (timeupdate)=\"onTimeUpdate($event)\"\n (loadedmetadata)=\"onLoadedMetadata($event)\"\n >\n Your browser does not support audio playback.\n </audio>\n }\n }\n @case ('pending') {\n <p class=\"call-recording-player__status eds-body-sm\">\n {{ message() ?? 'Recording is still processing…' }}\n </p>\n }\n @case ('unavailable') {\n <p class=\"call-recording-player__status eds-body-sm call-recording-player__status--muted\">\n {{ message() ?? 'No recording available for this call.' }}\n </p>\n }\n @case ('failed') {\n <p class=\"call-recording-player__status eds-body-sm call-recording-player__status--error\">\n {{ message() ?? 'Recording could not be retrieved.' }}\n </p>\n }\n @case ('error') {\n <p class=\"call-recording-player__status eds-body-sm call-recording-player__status--error\">\n {{ message() ?? 'Playback error.' }}\n </p>\n }\n }\n</section>\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"edvak99-voice-receptionist-widget-call-recording-player.component-B8_qp7Fe.mjs","sources":["../../../projects/voice-receptionist-widget/src/lib/components/call-recording-player/call-recording-player.component.ts","../../../projects/voice-receptionist-widget/src/lib/components/call-recording-player/call-recording-player.component.html"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n ElementRef,\n inject,\n input,\n output,\n signal,\n viewChild,\n} from '@angular/core';\nimport { takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop';\nimport { catchError, distinctUntilChanged, EMPTY, map, switchMap, tap } from 'rxjs';\n\nimport { CallRecordingStatus } from '../../models/ai-receptionist.types';\nimport { AiReceptionistApiService } from '../../services/ai-receptionist-api.service';\nimport { EdsIconComponent } from '../../ui/eds-icon.component';\n\ntype PlayerPhase = 'loading' | CallRecordingStatus | 'error';\n\n@Component({\n selector: 'eds-call-recording-player',\n imports: [EdsIconComponent],\n templateUrl: './call-recording-player.component.html',\n styleUrl: './call-recording-player.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class CallRecordingPlayerComponent {\n readonly callId = input.required<string>();\n readonly currentTimeChange = output<number>();\n readonly durationChange = output<number>();\n\n private readonly audioRef = viewChild<ElementRef<HTMLAudioElement>>('audioEl');\n\n private readonly api = inject(AiReceptionistApiService);\n private readonly destroyRef = inject(DestroyRef);\n\n protected readonly phase = signal<PlayerPhase>('loading');\n protected readonly blobUrl = signal<string | null>(null);\n protected readonly durationSeconds = signal<number | null>(null);\n protected readonly message = signal<string | null>(null);\n\n /** Tracked outside signals so cleanup never reads blobUrl (avoids effect/subscription loops). */\n private objectUrl: string | null = null;\n\n constructor() {\n toObservable(this.callId)\n .pipe(\n distinctUntilChanged(),\n tap(() => this.revokeObjectUrl()),\n switchMap((id) => {\n if (!id) {\n this.resetUi();\n return EMPTY;\n }\n this.phase.set('loading');\n this.message.set(null);\n return this.api.getCallRecording(id).pipe(\n switchMap((meta) => {\n if (meta.status !== 'ready' || !meta.url) {\n this.phase.set(meta.status);\n this.message.set(meta.message ?? null);\n this.durationSeconds.set(meta.durationSeconds ?? null);\n return EMPTY;\n }\n this.durationSeconds.set(meta.durationSeconds ?? null);\n return this.api.getCallRecordingBlob(meta.url).pipe(\n map((blob) => blob),\n catchError(() => {\n this.phase.set('error');\n this.message.set('Could not load recording audio.');\n return EMPTY;\n }),\n );\n }),\n catchError(() => {\n this.phase.set('unavailable');\n this.message.set('Could not load recording metadata.');\n return EMPTY;\n }),\n );\n }),\n takeUntilDestroyed(),\n )\n .subscribe((blob) => {\n this.revokeObjectUrl();\n this.objectUrl = URL.createObjectURL(blob);\n this.blobUrl.set(this.objectUrl);\n this.phase.set('ready');\n this.message.set(null);\n const dur = this.durationSeconds();\n if (dur != null && dur > 0) {\n this.durationChange.emit(dur);\n }\n });\n\n this.destroyRef.onDestroy(() => this.revokeObjectUrl());\n }\n\n protected formatDuration(seconds: number): string {\n const m = Math.floor(seconds / 60);\n const s = seconds % 60;\n return `${m}:${s.toString().padStart(2, '0')}`;\n }\n\n protected onAudioError(): void {\n this.phase.set('error');\n this.message.set('Playback error — try reloading the page.');\n }\n\n protected onTimeUpdate(event: Event): void {\n const el = event.target as HTMLAudioElement;\n this.currentTimeChange.emit(el.currentTime);\n }\n\n protected onLoadedMetadata(event: Event): void {\n const el = event.target as HTMLAudioElement;\n if (Number.isFinite(el.duration) && el.duration > 0) {\n this.durationChange.emit(el.duration);\n }\n }\n\n /** Seek playback — used by synced transcript lines. */\n seekTo(seconds: number): void {\n const el = this.audioRef()?.nativeElement;\n if (!el) return;\n el.currentTime = Math.max(0, seconds);\n void el.play().catch(() => undefined);\n this.currentTimeChange.emit(el.currentTime);\n }\n\n private revokeObjectUrl(): void {\n if (this.objectUrl) {\n URL.revokeObjectURL(this.objectUrl);\n this.objectUrl = null;\n }\n this.blobUrl.set(null);\n }\n\n private resetUi(): void {\n this.phase.set('loading');\n this.durationSeconds.set(null);\n this.message.set(null);\n }\n}\n","<section class=\"call-recording-player\" aria-labelledby=\"call-recording-title\">\n <header class=\"call-recording-player__header\">\n <eds-icon name=\"graphic_eq\" [size]=\"20\" />\n <h3 id=\"call-recording-title\" class=\"eds-h3\">Call recording</h3>\n @if (durationSeconds(); as dur) {\n <span class=\"eds-mono-sm call-recording-player__duration\">{{ formatDuration(dur) }}</span>\n }\n </header>\n\n @switch (phase()) {\n @case ('loading') {\n <p class=\"call-recording-player__status eds-body-sm\">Loading recording…</p>\n }\n @case ('ready') {\n @if (blobUrl(); as src) {\n <audio\n #audioEl\n class=\"call-recording-player__audio\"\n controls\n [src]=\"src\"\n (error)=\"onAudioError()\"\n (timeupdate)=\"onTimeUpdate($event)\"\n (loadedmetadata)=\"onLoadedMetadata($event)\"\n >\n Your browser does not support audio playback.\n </audio>\n }\n }\n @case ('pending') {\n <p class=\"call-recording-player__status eds-body-sm\">\n {{ message() ?? 'Recording is still processing…' }}\n </p>\n }\n @case ('unavailable') {\n <p class=\"call-recording-player__status eds-body-sm call-recording-player__status--muted\">\n {{ message() ?? 'No recording available for this call.' }}\n </p>\n }\n @case ('failed') {\n <p class=\"call-recording-player__status eds-body-sm call-recording-player__status--error\">\n {{ message() ?? 'Recording could not be retrieved.' }}\n </p>\n }\n @case ('error') {\n <p class=\"call-recording-player__status eds-body-sm call-recording-player__status--error\">\n {{ message() ?? 'Playback error.' }}\n </p>\n }\n }\n</section>\n"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { inject, signal, Injectable } from '@angular/core';
|
|
3
3
|
import { tap, map } from 'rxjs';
|
|
4
|
-
import { A as AiReceptionistApiService } from './edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-
|
|
4
|
+
import { A as AiReceptionistApiService } from './edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-Dn0GrZ6_.mjs';
|
|
5
5
|
|
|
6
6
|
class CallReviewService {
|
|
7
7
|
constructor() {
|
|
@@ -26,4 +26,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
26
26
|
}] });
|
|
27
27
|
|
|
28
28
|
export { CallReviewService as C };
|
|
29
|
-
//# sourceMappingURL=edvak99-voice-receptionist-widget-call-review.service-
|
|
29
|
+
//# sourceMappingURL=edvak99-voice-receptionist-widget-call-review.service-Cj2XTeK4.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"edvak99-voice-receptionist-widget-call-review.service-
|
|
1
|
+
{"version":3,"file":"edvak99-voice-receptionist-widget-call-review.service-Cj2XTeK4.mjs","sources":["../../../projects/voice-receptionist-widget/src/lib/services/call-review.service.ts"],"sourcesContent":["import { Injectable, inject, signal } from '@angular/core';\nimport { Observable, map, tap } from 'rxjs';\n\nimport { CallReviewStatus } from '../utils/call-review.util';\nimport { AiReceptionistApiService } from './ai-receptionist-api.service';\n\n@Injectable({ providedIn: 'root' })\nexport class CallReviewService {\n private readonly api = inject(AiReceptionistApiService);\n\n /** Cached from dashboard summary; decremented optimistically on review. */\n readonly needsReviewCount = signal<number | null>(null);\n\n setNeedsReviewCount(count: number): void {\n this.needsReviewCount.set(count);\n }\n\n markReviewed(callId: string): Observable<CallReviewStatus> {\n return this.api.postReview(callId).pipe(\n tap(() => {\n this.needsReviewCount.update((c) => (c != null && c > 0 ? c - 1 : c));\n }),\n map(() => 'reviewed'),\n );\n }\n}\n"],"names":[],"mappings":";;;;;MAOa,iBAAiB,CAAA;AAD9B,IAAA,WAAA,GAAA;AAEmB,QAAA,IAAA,CAAA,GAAG,GAAG,MAAM,CAAC,wBAAwB,CAAC;;AAG9C,QAAA,IAAA,CAAA,gBAAgB,GAAG,MAAM,CAAgB,IAAI,CAAC;AAcxD,IAAA;AAZC,IAAA,mBAAmB,CAAC,KAAa,EAAA;AAC/B,QAAA,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC;IAClC;AAEA,IAAA,YAAY,CAAC,MAAc,EAAA;AACzB,QAAA,OAAO,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,IAAI,CACrC,GAAG,CAAC,MAAK;AACP,YAAA,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;QACvE,CAAC,CAAC,EACF,GAAG,CAAC,MAAM,UAAU,CAAC,CACtB;IACH;+GAjBW,iBAAiB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA,CAAA;AAAjB,IAAA,SAAA,IAAA,CAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,iBAAiB,cADJ,MAAM,EAAA,CAAA,CAAA;;4FACnB,iBAAiB,EAAA,UAAA,EAAA,CAAA;kBAD7B,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;;;"}
|
|
@@ -66,5 +66,5 @@ function matchesReviewFilter(status, tab) {
|
|
|
66
66
|
return status === tab;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
export { reviewBadgeTone as a, formatOutcomeLabel as f, isNeedsReview as i,
|
|
70
|
-
//# sourceMappingURL=edvak99-voice-receptionist-widget-call-review.util-
|
|
69
|
+
export { reviewBadgeTone as a, formatOutcomeLabel as f, isNeedsReview as i, outcomeBadgeTone as o, reviewLabel as r };
|
|
70
|
+
//# sourceMappingURL=edvak99-voice-receptionist-widget-call-review.util-BgsBCKgZ.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"edvak99-voice-receptionist-widget-call-review.util-
|
|
1
|
+
{"version":3,"file":"edvak99-voice-receptionist-widget-call-review.util-BgsBCKgZ.mjs","sources":["../../../projects/voice-receptionist-widget/src/lib/utils/call-outcome.util.ts","../../../projects/voice-receptionist-widget/src/lib/utils/call-review.util.ts"],"sourcesContent":["import { BadgeTone } from '../ui/eds-badge.component';\n\n/** Known history outcomes from GET /calls/history (HistoryCallDto.outcome). */\nexport const HISTORY_OUTCOMES = [\n 'completed',\n 'failed',\n 'transferred',\n 'escalated',\n] as const;\n\nexport type HistoryOutcome = (typeof HISTORY_OUTCOMES)[number] | 'custom';\n\nexport function normalizeHistoryOutcome(outcome: string): HistoryOutcome {\n const key = outcome.trim().toLowerCase();\n if ((HISTORY_OUTCOMES as readonly string[]).includes(key)) {\n return key as HistoryOutcome;\n }\n return 'custom';\n}\n\n/** Badge tone for history table / detail — separate from lifecycle or live UI status. */\nexport function outcomeBadgeTone(outcome: string): BadgeTone {\n switch (normalizeHistoryOutcome(outcome)) {\n case 'completed':\n return 'pos';\n case 'failed':\n return 'neg';\n case 'transferred':\n return 'violet';\n case 'escalated':\n return 'neg';\n default: {\n const key = outcome.trim().toLowerCase();\n if (key.includes('transfer')) return 'violet';\n if (key.includes('fail') || key.includes('escalat') || key.includes('abandon')) return 'neg';\n if (key.includes('voicemail')) return 'gray';\n if (key.includes('complete') || key.includes('book') || key.includes('task')) return 'pos';\n return 'brand';\n }\n }\n}\n\nexport function formatOutcomeLabel(outcome: string): string {\n const trimmed = outcome.trim();\n if (!trimmed) return 'Unknown';\n const known = normalizeHistoryOutcome(trimmed);\n if (known === 'custom') return trimmed;\n return known.charAt(0).toUpperCase() + known.slice(1);\n}\n","export type CallReviewStatus = 'needs' | 'reviewed';\n\nexport function reviewLabel(status: CallReviewStatus): string {\n return status === 'reviewed' ? 'Reviewed' : 'Pending review';\n}\n\nexport function reviewBadgeTone(status: CallReviewStatus): 'pos' | 'notice' {\n return status === 'reviewed' ? 'pos' : 'notice';\n}\n\nexport function isNeedsReview(status: CallReviewStatus): boolean {\n return status === 'needs';\n}\n\n/** Normalize legacy or API values to CallReviewStatus. */\nexport function normalizeReviewStatus(value: string | undefined | null): CallReviewStatus {\n return value === 'reviewed' ? 'reviewed' : 'needs';\n}\n\nexport type ReviewFilterTab = 'all' | 'needs' | 'reviewed';\n\nexport function matchesReviewFilter(\n status: CallReviewStatus,\n tab: ReviewFilterTab,\n): boolean {\n if (tab === 'all') return true;\n return status === tab;\n}\n"],"names":[],"mappings":"AAEA;AACO,MAAM,gBAAgB,GAAG;IAC9B,WAAW;IACX,QAAQ;IACR,aAAa;IACb,WAAW;CACH;AAIJ,SAAU,uBAAuB,CAAC,OAAe,EAAA;IACrD,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE;AACxC,IAAA,IAAK,gBAAsC,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;AACzD,QAAA,OAAO,GAAqB;IAC9B;AACA,IAAA,OAAO,QAAQ;AACjB;AAEA;AACM,SAAU,gBAAgB,CAAC,OAAe,EAAA;AAC9C,IAAA,QAAQ,uBAAuB,CAAC,OAAO,CAAC;AACtC,QAAA,KAAK,WAAW;AACd,YAAA,OAAO,KAAK;AACd,QAAA,KAAK,QAAQ;AACX,YAAA,OAAO,KAAK;AACd,QAAA,KAAK,aAAa;AAChB,YAAA,OAAO,QAAQ;AACjB,QAAA,KAAK,WAAW;AACd,YAAA,OAAO,KAAK;QACd,SAAS;YACP,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE;AACxC,YAAA,IAAI,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC;AAAE,gBAAA,OAAO,QAAQ;AAC7C,YAAA,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC;AAAE,gBAAA,OAAO,KAAK;AAC5F,YAAA,IAAI,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC;AAAE,gBAAA,OAAO,MAAM;AAC5C,YAAA,IAAI,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC;AAAE,gBAAA,OAAO,KAAK;AAC1F,YAAA,OAAO,OAAO;QAChB;;AAEJ;AAEM,SAAU,kBAAkB,CAAC,OAAe,EAAA;AAChD,IAAA,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE;AAC9B,IAAA,IAAI,CAAC,OAAO;AAAE,QAAA,OAAO,SAAS;AAC9B,IAAA,MAAM,KAAK,GAAG,uBAAuB,CAAC,OAAO,CAAC;IAC9C,IAAI,KAAK,KAAK,QAAQ;AAAE,QAAA,OAAO,OAAO;AACtC,IAAA,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;AACvD;;AC9CM,SAAU,WAAW,CAAC,MAAwB,EAAA;IAClD,OAAO,MAAM,KAAK,UAAU,GAAG,UAAU,GAAG,gBAAgB;AAC9D;AAEM,SAAU,eAAe,CAAC,MAAwB,EAAA;IACtD,OAAO,MAAM,KAAK,UAAU,GAAG,KAAK,GAAG,QAAQ;AACjD;AAEM,SAAU,aAAa,CAAC,MAAwB,EAAA;IACpD,OAAO,MAAM,KAAK,OAAO;AAC3B;AAEA;AACM,SAAU,qBAAqB,CAAC,KAAgC,EAAA;IACpE,OAAO,KAAK,KAAK,UAAU,GAAG,UAAU,GAAG,OAAO;AACpD;AAIM,SAAU,mBAAmB,CACjC,MAAwB,EACxB,GAAoB,EAAA;IAEpB,IAAI,GAAG,KAAK,KAAK;AAAE,QAAA,OAAO,IAAI;IAC9B,OAAO,MAAM,KAAK,GAAG;AACvB;;;;"}
|