@edvak99/voice-receptionist-widget 1.1.2 → 1.1.4
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-activities-page.component-DT9UKvQO.mjs +307 -0
- package/fesm2022/edvak99-voice-receptionist-widget-activities-page.component-DT9UKvQO.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-CMhknpGf.mjs → edvak99-voice-receptionist-widget-ai-receptionist-api.service-48cifVPF.mjs} +1351 -579
- package/fesm2022/edvak99-voice-receptionist-widget-ai-receptionist-api.service-48cifVPF.mjs.map +1 -0
- package/fesm2022/edvak99-voice-receptionist-widget-analytics-page.component-C5inEHJw.mjs +278 -0
- package/fesm2022/edvak99-voice-receptionist-widget-analytics-page.component-C5inEHJw.mjs.map +1 -0
- package/fesm2022/edvak99-voice-receptionist-widget-call-history-detail-page.component-sYhM20CE.mjs +418 -0
- package/fesm2022/edvak99-voice-receptionist-widget-call-history-detail-page.component-sYhM20CE.mjs.map +1 -0
- package/fesm2022/edvak99-voice-receptionist-widget-call-history-page.component-DpwajEOE.mjs +194 -0
- package/fesm2022/edvak99-voice-receptionist-widget-call-history-page.component-DpwajEOE.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-call-recording-player.component-AN6GcSDq.mjs → edvak99-voice-receptionist-widget-call-recording-player.component-CgkRcFOl.mjs} +5 -4
- package/fesm2022/{edvak99-voice-receptionist-widget-call-recording-player.component-AN6GcSDq.mjs.map → edvak99-voice-receptionist-widget-call-recording-player.component-CgkRcFOl.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-call-review.service-Cy_Bf7AO.mjs → edvak99-voice-receptionist-widget-call-review.service-CIMcjGKX.mjs} +2 -2
- package/fesm2022/{edvak99-voice-receptionist-widget-call-review.service-Cy_Bf7AO.mjs.map → edvak99-voice-receptionist-widget-call-review.service-CIMcjGKX.mjs.map} +1 -1
- package/fesm2022/edvak99-voice-receptionist-widget-call-review.util-Deh3jPgo.mjs +21 -0
- package/fesm2022/edvak99-voice-receptionist-widget-call-review.util-Deh3jPgo.mjs.map +1 -0
- package/fesm2022/edvak99-voice-receptionist-widget-dashboard-page.component-CxbO0eDS.mjs +440 -0
- package/fesm2022/edvak99-voice-receptionist-widget-dashboard-page.component-CxbO0eDS.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-eds-elapsed.pipe-ouRlPpwT.mjs → edvak99-voice-receptionist-widget-dashboard-socket.service-BX91r74O.mjs} +5 -21
- package/fesm2022/edvak99-voice-receptionist-widget-dashboard-socket.service-BX91r74O.mjs.map +1 -0
- package/fesm2022/edvak99-voice-receptionist-widget-eds-avatar.component-CWRiJGfv.mjs +38 -0
- package/fesm2022/edvak99-voice-receptionist-widget-eds-avatar.component-CWRiJGfv.mjs.map +1 -0
- package/fesm2022/edvak99-voice-receptionist-widget-eds-button.component-Bg5T5BN8.mjs +27 -0
- package/fesm2022/edvak99-voice-receptionist-widget-eds-button.component-Bg5T5BN8.mjs.map +1 -0
- package/fesm2022/edvak99-voice-receptionist-widget-eds-elapsed.pipe-BFCiJOT3.mjs +22 -0
- package/fesm2022/edvak99-voice-receptionist-widget-eds-elapsed.pipe-BFCiJOT3.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-live-calls-list.service-CDtFRW8w.mjs → edvak99-voice-receptionist-widget-eds-pulse-dot.component-BPY6xN7C.mjs} +15 -5
- package/fesm2022/edvak99-voice-receptionist-widget-eds-pulse-dot.component-BPY6xN7C.mjs.map +1 -0
- package/fesm2022/edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-BsBQIS_f.mjs +203 -0
- package/fesm2022/edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-BsBQIS_f.mjs.map +1 -0
- package/fesm2022/edvak99-voice-receptionist-widget-live-calls-page.component-CaSDMxpV.mjs +81 -0
- package/fesm2022/edvak99-voice-receptionist-widget-live-calls-page.component-CaSDMxpV.mjs.map +1 -0
- package/fesm2022/edvak99-voice-receptionist-widget-live-monitor-page.component-Cy3ND-c-.mjs +1070 -0
- package/fesm2022/edvak99-voice-receptionist-widget-live-monitor-page.component-Cy3ND-c-.mjs.map +1 -0
- package/fesm2022/edvak99-voice-receptionist-widget-modal.component-COfi7biN.mjs +48 -0
- package/fesm2022/edvak99-voice-receptionist-widget-modal.component-COfi7biN.mjs.map +1 -0
- package/fesm2022/edvak99-voice-receptionist-widget-outbound-purpose.util-Bdh4QfFe.mjs +127 -0
- package/fesm2022/edvak99-voice-receptionist-widget-outbound-purpose.util-Bdh4QfFe.mjs.map +1 -0
- package/fesm2022/edvak99-voice-receptionist-widget-outbound-purposes-page.component-fHVzpiVk.mjs +268 -0
- package/fesm2022/edvak99-voice-receptionist-widget-outbound-purposes-page.component-fHVzpiVk.mjs.map +1 -0
- package/fesm2022/edvak99-voice-receptionist-widget-settings-page.component-Bok64X2q.mjs +968 -0
- package/fesm2022/edvak99-voice-receptionist-widget-settings-page.component-Bok64X2q.mjs.map +1 -0
- package/fesm2022/edvak99-voice-receptionist-widget-tasks-page.component-Bb9lPcYi.mjs +317 -0
- package/fesm2022/edvak99-voice-receptionist-widget-tasks-page.component-Bb9lPcYi.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-wizard-page.component-CJLa5pia.mjs → edvak99-voice-receptionist-widget-wizard-page.component-BZVlWLWh.mjs} +6 -4
- package/fesm2022/{edvak99-voice-receptionist-widget-wizard-page.component-CJLa5pia.mjs.map → edvak99-voice-receptionist-widget-wizard-page.component-BZVlWLWh.mjs.map} +1 -1
- package/fesm2022/edvak99-voice-receptionist-widget.mjs +1 -1
- package/lib/components/call-conversation-panel/call-conversation-panel.component.d.ts +9 -6
- package/lib/components/call-tasks-panel/call-tasks-panel.component.d.ts +8 -8
- package/lib/components/knowledge-test-modal/knowledge-test-modal.component.d.ts +28 -0
- package/lib/components/live-transcript-panel/live-transcript-panel.component.d.ts +7 -4
- package/lib/components/outbound-dial-modal/outbound-dial-modal.component.d.ts +26 -0
- package/lib/layout/eds-module-nav.component.d.ts +0 -3
- package/lib/mocks/agent-activity.seed.d.ts +2 -0
- package/lib/models/agent-activity.types.d.ts +54 -0
- package/lib/models/ai-receptionist.types.d.ts +26 -0
- package/lib/models/api-dto.types.d.ts +18 -0
- package/lib/models/live-transcript.types.d.ts +2 -1
- package/lib/models/outbound-patient.types.d.ts +23 -0
- package/lib/models/outbound-purpose.types.d.ts +2 -0
- package/lib/models/pagination.d.ts +11 -0
- package/lib/models/staff-media.types.d.ts +36 -0
- package/lib/pages/activities-page/activities-page.component.d.ts +57 -0
- package/lib/pages/analytics-page/analytics-page.component.d.ts +38 -14
- package/lib/pages/call-history-detail-page/call-history-detail-page.component.d.ts +2 -3
- package/lib/pages/call-history-page/call-history-page.component.d.ts +16 -9
- package/lib/pages/dashboard-page/dashboard-page.component.d.ts +12 -8
- package/lib/pages/live-calls-page/live-calls-page.component.d.ts +14 -24
- package/lib/pages/live-monitor-page/live-monitor-page.component.d.ts +34 -1
- package/lib/pages/settings-page/settings-fields.config.d.ts +16 -0
- package/lib/pages/settings-page/settings-page.component.d.ts +48 -14
- package/lib/pages/tasks-page/tasks-page.component.d.ts +6 -0
- package/lib/services/ai-receptionist-api.mock.d.ts +44 -9
- package/lib/services/ai-receptionist-api.service.d.ts +65 -10
- package/lib/services/live-transcript.service.d.ts +1 -0
- package/lib/services/staff-media.service.d.ts +52 -0
- package/lib/ui/eds-avatar.component.d.ts +5 -2
- package/lib/ui/eds-button.component.d.ts +1 -1
- package/lib/utils/call-history-display.util.d.ts +21 -0
- package/lib/utils/outbound-purpose.util.d.ts +19 -0
- package/lib/utils/transcript-timing.util.d.ts +1 -1
- package/lib/utils/welcome-message.util.d.ts +1 -1
- package/package.json +2 -1
- package/styles/_index.scss +5 -40
- package/styles/chat-ui.scss +18 -18
- package/styles/eds.scss +188 -119
- package/fesm2022/edvak99-voice-receptionist-widget-analytics-page.component-CW5OKmik.mjs +0 -113
- package/fesm2022/edvak99-voice-receptionist-widget-analytics-page.component-CW5OKmik.mjs.map +0 -1
- 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-detail-page.component-CTwfUHUf.mjs +0 -316
- package/fesm2022/edvak99-voice-receptionist-widget-call-history-detail-page.component-CTwfUHUf.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-call-history-page.component-Cj4wxd4e.mjs +0 -138
- package/fesm2022/edvak99-voice-receptionist-widget-call-history-page.component-Cj4wxd4e.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-call-review.util-DQLIw7xb.mjs +0 -70
- package/fesm2022/edvak99-voice-receptionist-widget-call-review.util-DQLIw7xb.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-dashboard-page.component-DzdIt2A7.mjs +0 -248
- package/fesm2022/edvak99-voice-receptionist-widget-dashboard-page.component-DzdIt2A7.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-eds-avatar.component-PCnIWeOA.mjs +0 -27
- package/fesm2022/edvak99-voice-receptionist-widget-eds-avatar.component-PCnIWeOA.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-eds-elapsed.pipe-ouRlPpwT.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 +0 -575
- package/fesm2022/edvak99-voice-receptionist-widget-knowledge-hub.page-cZqBuull.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-live-calls-list.service-CDtFRW8w.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-live-calls-page.component-DrYzXJQW.mjs +0 -115
- package/fesm2022/edvak99-voice-receptionist-widget-live-calls-page.component-DrYzXJQW.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-live-monitor-page.component-D7dlk0y2.mjs +0 -574
- package/fesm2022/edvak99-voice-receptionist-widget-live-monitor-page.component-D7dlk0y2.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-outbound-purpose.util-BQECIuJu.mjs +0 -54
- package/fesm2022/edvak99-voice-receptionist-widget-outbound-purpose.util-BQECIuJu.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-outbound-purposes-page.component-CJ8NEjcj.mjs +0 -265
- package/fesm2022/edvak99-voice-receptionist-widget-outbound-purposes-page.component-CJ8NEjcj.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-settings-page.component-Bo3XNK3b.mjs +0 -509
- package/fesm2022/edvak99-voice-receptionist-widget-settings-page.component-Bo3XNK3b.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-task.util-DdtI0CR3.mjs +0 -52
- package/fesm2022/edvak99-voice-receptionist-widget-task.util-DdtI0CR3.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-tasks-page.component-CBwl15NP.mjs +0 -237
- package/fesm2022/edvak99-voice-receptionist-widget-tasks-page.component-CBwl15NP.mjs.map +0 -1
- package/lib/knowledge/components/faq-empty-state/faq-empty-state.component.d.ts +0 -22
- package/lib/knowledge/components/faq-form/faq-form.component.d.ts +0 -27
- package/lib/knowledge/components/faq-search-tester/faq-search-tester.component.d.ts +0 -17
- package/lib/knowledge/mocks/practice-faq.seed.d.ts +0 -2
- package/lib/knowledge/models/practice-faq.model.d.ts +0 -47
- package/lib/knowledge/pages/knowledge-hub.page.d.ts +0 -47
- package/lib/knowledge/services/practice-faq-api.mock.d.ts +0 -16
- package/lib/knowledge/services/practice-faq-api.service.d.ts +0 -22
- package/lib/knowledge/utils/faq.util.d.ts +0 -3
- package/lib/layout/eds-topbar.component.d.ts +0 -29
- package/lib/pages/audit-page/audit-page.component.d.ts +0 -14
- package/lib/ui/eds-waveform.component.d.ts +0 -8
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, signal, computed, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
|
-
import { ActivatedRoute, Router } from '@angular/router';
|
|
4
|
-
import { DatePipe } from '@angular/common';
|
|
5
|
-
import * as i1 from '@angular/forms';
|
|
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-CMhknpGf.mjs';
|
|
8
|
-
import { C as CallReviewService } from './edvak99-voice-receptionist-widget-call-review.service-Cy_Bf7AO.mjs';
|
|
9
|
-
import { m as matchesReviewFilter, i as isNeedsReview, r as reviewLabel, a as reviewBadgeTone, o as outcomeBadgeTone, f as formatOutcomeLabel } from './edvak99-voice-receptionist-widget-call-review.util-DQLIw7xb.mjs';
|
|
10
|
-
import { E as EdsAvatarComponent } from './edvak99-voice-receptionist-widget-eds-avatar.component-PCnIWeOA.mjs';
|
|
11
|
-
|
|
12
|
-
class CallHistoryPageComponent {
|
|
13
|
-
constructor() {
|
|
14
|
-
this.api = inject(AiReceptionistApiService);
|
|
15
|
-
this.reviewService = inject(CallReviewService);
|
|
16
|
-
this.toast = inject(ToastService);
|
|
17
|
-
this.route = inject(ActivatedRoute);
|
|
18
|
-
this.router = inject(Router);
|
|
19
|
-
this.allRows = signal([]);
|
|
20
|
-
this.loading = signal(true);
|
|
21
|
-
this.reviewingId = signal(null);
|
|
22
|
-
this.search = signal('');
|
|
23
|
-
this.direction = signal('');
|
|
24
|
-
this.outcome = signal('');
|
|
25
|
-
this.location = signal('');
|
|
26
|
-
this.reviewTab = signal('all');
|
|
27
|
-
this.reviewTabs = [
|
|
28
|
-
{ id: 'all', label: 'All' },
|
|
29
|
-
{ id: 'needs', label: 'Needs review' },
|
|
30
|
-
{ id: 'reviewed', label: 'Reviewed' },
|
|
31
|
-
];
|
|
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
|
-
this.reviewLabel = reviewLabel;
|
|
38
|
-
this.reviewTone = reviewBadgeTone;
|
|
39
|
-
this.isNeedsReview = isNeedsReview;
|
|
40
|
-
this.outcomeTone = outcomeBadgeTone;
|
|
41
|
-
this.outcomeLabel = formatOutcomeLabel;
|
|
42
|
-
}
|
|
43
|
-
ngOnInit() {
|
|
44
|
-
const reviewParam = this.route.snapshot.queryParamMap.get('review');
|
|
45
|
-
if (reviewParam === 'needs' || reviewParam === 'reviewed') {
|
|
46
|
-
this.reviewTab.set(reviewParam);
|
|
47
|
-
}
|
|
48
|
-
this.load();
|
|
49
|
-
}
|
|
50
|
-
load() {
|
|
51
|
-
this.loading.set(true);
|
|
52
|
-
this.api
|
|
53
|
-
.getHistory({
|
|
54
|
-
q: this.search() || undefined,
|
|
55
|
-
dir: this.direction() || undefined,
|
|
56
|
-
outcome: this.outcome() || undefined,
|
|
57
|
-
location: this.location() || undefined,
|
|
58
|
-
})
|
|
59
|
-
.subscribe(({ data }) => {
|
|
60
|
-
this.allRows.set(data);
|
|
61
|
-
this.loading.set(false);
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
applyFilters() {
|
|
65
|
-
this.load();
|
|
66
|
-
}
|
|
67
|
-
setReviewTab(tab) {
|
|
68
|
-
this.reviewTab.set(tab);
|
|
69
|
-
void this.router.navigate([], {
|
|
70
|
-
relativeTo: this.route,
|
|
71
|
-
queryParams: tab === 'all' ? { review: null } : { review: tab },
|
|
72
|
-
queryParamsHandling: 'merge',
|
|
73
|
-
replaceUrl: true,
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
tabBadgeCount(tab) {
|
|
77
|
-
if (tab !== 'needs')
|
|
78
|
-
return null;
|
|
79
|
-
const count = this.needsReviewCount();
|
|
80
|
-
return count > 0 ? count : null;
|
|
81
|
-
}
|
|
82
|
-
markReviewed(row, event) {
|
|
83
|
-
event.preventDefault();
|
|
84
|
-
event.stopPropagation();
|
|
85
|
-
if (!isNeedsReview(row.review) || this.reviewingId())
|
|
86
|
-
return;
|
|
87
|
-
this.reviewingId.set(row.id);
|
|
88
|
-
this.allRows.update((list) => list.map((r) => (r.id === row.id ? { ...r, review: 'reviewed' } : r)));
|
|
89
|
-
this.reviewService.markReviewed(row.id).subscribe({
|
|
90
|
-
next: () => {
|
|
91
|
-
this.reviewingId.set(null);
|
|
92
|
-
this.toast.show('Call marked as reviewed', 'success');
|
|
93
|
-
},
|
|
94
|
-
error: () => {
|
|
95
|
-
this.reviewingId.set(null);
|
|
96
|
-
this.allRows.update((list) => list.map((r) => (r.id === row.id ? { ...r, review: 'needs' } : r)));
|
|
97
|
-
this.toast.show('Failed to mark call as reviewed', 'error');
|
|
98
|
-
},
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
formatDuration(sec) {
|
|
102
|
-
const m = Math.floor(sec / 60);
|
|
103
|
-
const s = sec % 60;
|
|
104
|
-
return `${m}:${s.toString().padStart(2, '0')}`;
|
|
105
|
-
}
|
|
106
|
-
openCallDetail(id) {
|
|
107
|
-
void this.router.navigate(['../history', id], { relativeTo: this.route });
|
|
108
|
-
}
|
|
109
|
-
exportCsv() {
|
|
110
|
-
const header = 'ID,Name,Phone,Direction,Outcome,Reason,Duration,Location,Review\n';
|
|
111
|
-
const body = this.rows()
|
|
112
|
-
.map((r) => `${r.id},${r.name},${r.phone},${r.direction},${r.outcome},${r.reason},${r.duration},${r.location},${reviewLabel(r.review)}`)
|
|
113
|
-
.join('\n');
|
|
114
|
-
const blob = new Blob([header + body], { type: 'text/csv' });
|
|
115
|
-
const url = URL.createObjectURL(blob);
|
|
116
|
-
const a = document.createElement('a');
|
|
117
|
-
a.href = url;
|
|
118
|
-
a.download = 'call-history.csv';
|
|
119
|
-
a.click();
|
|
120
|
-
URL.revokeObjectURL(url);
|
|
121
|
-
}
|
|
122
|
-
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 }); }
|
|
124
|
-
}
|
|
125
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: CallHistoryPageComponent, decorators: [{
|
|
126
|
-
type: Component,
|
|
127
|
-
args: [{ selector: 'eds-call-history-page', imports: [
|
|
128
|
-
DatePipe,
|
|
129
|
-
FormsModule,
|
|
130
|
-
EdsAvatarComponent,
|
|
131
|
-
EdsBadgeComponent,
|
|
132
|
-
EdsButtonComponent,
|
|
133
|
-
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"] }]
|
|
135
|
-
}] });
|
|
136
|
-
|
|
137
|
-
export { CallHistoryPageComponent };
|
|
138
|
-
//# sourceMappingURL=edvak99-voice-receptionist-widget-call-history-page.component-Cj4wxd4e.mjs.map
|
package/fesm2022/edvak99-voice-receptionist-widget-call-history-page.component-Cj4wxd4e.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"edvak99-voice-receptionist-widget-call-history-page.component-Cj4wxd4e.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, computed, inject, OnInit, signal } from '@angular/core';\n\nimport { ActivatedRoute, Router } from '@angular/router';\n\nimport { DatePipe } from '@angular/common';\n\nimport { FormsModule } from '@angular/forms';\n\n\n\nimport { HistoryCall } from '../../models/ai-receptionist.types';\n\nimport { AiReceptionistApiService } from '../../services/ai-receptionist-api.service';\n\nimport { CallReviewService } from '../../services/call-review.service';\n\nimport { formatOutcomeLabel, outcomeBadgeTone } from '../../utils/call-outcome.util';\n\nimport {\n\n isNeedsReview,\n\n matchesReviewFilter,\n\n reviewBadgeTone,\n\n reviewLabel,\n\n ReviewFilterTab,\n\n} from '../../utils/call-review.util';\n\nimport { EdsAvatarComponent } from '../../ui/eds-avatar.component';\n\nimport { EdsBadgeComponent } from '../../ui/eds-badge.component';\n\nimport { EdsButtonComponent } from '../../ui/eds-button.component';\n\nimport { EdsIconComponent } from '../../ui/eds-icon.component';\n\nimport { ToastService } from '../../shared/toast.service';\n\n\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})\n\nexport class CallHistoryPageComponent implements OnInit {\n\n private readonly api = inject(AiReceptionistApiService);\n\n private readonly reviewService = inject(CallReviewService);\n\n private readonly toast = inject(ToastService);\n\n private readonly route = inject(ActivatedRoute);\n\n private readonly router = inject(Router);\n\n\n\n protected readonly allRows = signal<HistoryCall[]>([]);\n\n protected readonly loading = signal(true);\n\n protected readonly reviewingId = signal<string | null>(null);\n\n protected readonly search = signal('');\n\n protected readonly direction = signal('');\n\n protected readonly outcome = signal('');\n\n protected readonly location = signal('');\n\n protected readonly reviewTab = signal<ReviewFilterTab>('all');\n\n\n\n protected readonly reviewTabs: { id: ReviewFilterTab; label: string }[] = [\n\n { id: 'all', label: 'All' },\n\n { id: 'needs', label: 'Needs review' },\n\n { id: 'reviewed', label: 'Reviewed' },\n\n ];\n\n\n\n protected readonly rows = computed(() => {\n\n const tab = this.reviewTab();\n\n return this.allRows().filter((row) => matchesReviewFilter(row.review, tab));\n\n });\n\n\n\n protected readonly needsReviewCount = computed(\n\n () => this.allRows().filter((r) => isNeedsReview(r.review)).length,\n\n );\n\n\n\n protected reviewLabel = reviewLabel;\n\n protected reviewTone = reviewBadgeTone;\n\n protected isNeedsReview = isNeedsReview;\n\n protected outcomeTone = outcomeBadgeTone;\n\n protected outcomeLabel = formatOutcomeLabel;\n\n\n\n ngOnInit(): void {\n\n const reviewParam = this.route.snapshot.queryParamMap.get('review');\n\n if (reviewParam === 'needs' || reviewParam === 'reviewed') {\n\n this.reviewTab.set(reviewParam);\n\n }\n\n this.load();\n\n }\n\n\n\n protected load(): void {\n\n this.loading.set(true);\n\n this.api\n\n .getHistory({\n\n q: this.search() || undefined,\n\n dir: this.direction() || undefined,\n\n outcome: this.outcome() || undefined,\n\n location: this.location() || undefined,\n\n })\n\n .subscribe(({ data }) => {\n\n this.allRows.set(data);\n\n this.loading.set(false);\n\n });\n\n }\n\n\n\n protected applyFilters(): void {\n\n this.load();\n\n }\n\n\n\n protected setReviewTab(tab: ReviewFilterTab): void {\n\n this.reviewTab.set(tab);\n\n void this.router.navigate([], {\n\n relativeTo: this.route,\n\n queryParams: tab === 'all' ? { review: null } : { review: tab },\n\n queryParamsHandling: 'merge',\n\n replaceUrl: true,\n\n });\n\n }\n\n\n\n protected tabBadgeCount(tab: ReviewFilterTab): number | null {\n\n if (tab !== 'needs') return null;\n\n const count = this.needsReviewCount();\n\n return count > 0 ? count : null;\n\n }\n\n\n\n protected markReviewed(row: HistoryCall, event: Event): void {\n event.preventDefault();\n event.stopPropagation();\n\n if (!isNeedsReview(row.review) || this.reviewingId()) return;\n\n\n\n this.reviewingId.set(row.id);\n\n this.allRows.update((list) =>\n\n list.map((r) => (r.id === row.id ? { ...r, review: 'reviewed' as const } : r)),\n\n );\n\n\n\n this.reviewService.markReviewed(row.id).subscribe({\n\n next: () => {\n\n this.reviewingId.set(null);\n\n this.toast.show('Call marked as reviewed', 'success');\n\n },\n\n error: () => {\n\n this.reviewingId.set(null);\n\n this.allRows.update((list) =>\n\n list.map((r) => (r.id === row.id ? { ...r, review: 'needs' as const } : r)),\n\n );\n\n this.toast.show('Failed to mark call as reviewed', 'error');\n\n },\n\n });\n\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\n const header = 'ID,Name,Phone,Direction,Outcome,Reason,Duration,Location,Review\\n';\n\n const body = this.rows()\n\n .map(\n\n (r) =>\n\n `${r.id},${r.name},${r.phone},${r.direction},${r.outcome},${r.reason},${r.duration},${r.location},${reviewLabel(r.review)}`,\n\n )\n\n .join('\\n');\n\n const blob = new Blob([header + body], { type: 'text/csv' });\n\n const url = URL.createObjectURL(blob);\n\n const a = document.createElement('a');\n\n a.href = url;\n\n a.download = 'call-history.csv';\n\n a.click();\n\n URL.revokeObjectURL(url);\n\n }\n\n}\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</div>\n\n\n"],"names":[],"mappings":"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"}
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
/** Known history outcomes from GET /calls/history (HistoryCallDto.outcome). */
|
|
2
|
-
const HISTORY_OUTCOMES = [
|
|
3
|
-
'completed',
|
|
4
|
-
'failed',
|
|
5
|
-
'transferred',
|
|
6
|
-
'escalated',
|
|
7
|
-
];
|
|
8
|
-
function normalizeHistoryOutcome(outcome) {
|
|
9
|
-
const key = outcome.trim().toLowerCase();
|
|
10
|
-
if (HISTORY_OUTCOMES.includes(key)) {
|
|
11
|
-
return key;
|
|
12
|
-
}
|
|
13
|
-
return 'custom';
|
|
14
|
-
}
|
|
15
|
-
/** Badge tone for history table / detail — separate from lifecycle or live UI status. */
|
|
16
|
-
function outcomeBadgeTone(outcome) {
|
|
17
|
-
switch (normalizeHistoryOutcome(outcome)) {
|
|
18
|
-
case 'completed':
|
|
19
|
-
return 'pos';
|
|
20
|
-
case 'failed':
|
|
21
|
-
return 'neg';
|
|
22
|
-
case 'transferred':
|
|
23
|
-
return 'violet';
|
|
24
|
-
case 'escalated':
|
|
25
|
-
return 'neg';
|
|
26
|
-
default: {
|
|
27
|
-
const key = outcome.trim().toLowerCase();
|
|
28
|
-
if (key.includes('transfer'))
|
|
29
|
-
return 'violet';
|
|
30
|
-
if (key.includes('fail') || key.includes('escalat') || key.includes('abandon'))
|
|
31
|
-
return 'neg';
|
|
32
|
-
if (key.includes('voicemail'))
|
|
33
|
-
return 'gray';
|
|
34
|
-
if (key.includes('complete') || key.includes('book') || key.includes('task'))
|
|
35
|
-
return 'pos';
|
|
36
|
-
return 'brand';
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
function formatOutcomeLabel(outcome) {
|
|
41
|
-
const trimmed = outcome.trim();
|
|
42
|
-
if (!trimmed)
|
|
43
|
-
return 'Unknown';
|
|
44
|
-
const known = normalizeHistoryOutcome(trimmed);
|
|
45
|
-
if (known === 'custom')
|
|
46
|
-
return trimmed;
|
|
47
|
-
return known.charAt(0).toUpperCase() + known.slice(1);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function reviewLabel(status) {
|
|
51
|
-
return status === 'reviewed' ? 'Reviewed' : 'Pending review';
|
|
52
|
-
}
|
|
53
|
-
function reviewBadgeTone(status) {
|
|
54
|
-
return status === 'reviewed' ? 'pos' : 'notice';
|
|
55
|
-
}
|
|
56
|
-
function isNeedsReview(status) {
|
|
57
|
-
return status === 'needs';
|
|
58
|
-
}
|
|
59
|
-
/** Normalize legacy or API values to CallReviewStatus. */
|
|
60
|
-
function normalizeReviewStatus(value) {
|
|
61
|
-
return value === 'reviewed' ? 'reviewed' : 'needs';
|
|
62
|
-
}
|
|
63
|
-
function matchesReviewFilter(status, tab) {
|
|
64
|
-
if (tab === 'all')
|
|
65
|
-
return true;
|
|
66
|
-
return status === tab;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export { reviewBadgeTone as a, formatOutcomeLabel as f, isNeedsReview as i, matchesReviewFilter as m, outcomeBadgeTone as o, reviewLabel as r };
|
|
70
|
-
//# sourceMappingURL=edvak99-voice-receptionist-widget-call-review.util-DQLIw7xb.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"edvak99-voice-receptionist-widget-call-review.util-DQLIw7xb.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;;;;"}
|