@edvak99/voice-receptionist-widget 1.1.19 → 1.1.21

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.
Files changed (52) hide show
  1. package/fesm2022/edvak99-voice-receptionist-widget-activities-page.component-CpXa1J9-.mjs +510 -0
  2. package/fesm2022/edvak99-voice-receptionist-widget-activities-page.component-CpXa1J9-.mjs.map +1 -0
  3. package/fesm2022/edvak99-voice-receptionist-widget-analytics-page.component-CmImX5FN.mjs +435 -0
  4. package/fesm2022/edvak99-voice-receptionist-widget-analytics-page.component-CmImX5FN.mjs.map +1 -0
  5. package/fesm2022/edvak99-voice-receptionist-widget-audit-page.component-DTAB2WTX.mjs +78 -0
  6. package/fesm2022/edvak99-voice-receptionist-widget-audit-page.component-DTAB2WTX.mjs.map +1 -0
  7. package/fesm2022/{edvak99-voice-receptionist-widget-call-history-detail-page.component-DShtvrbw.mjs → edvak99-voice-receptionist-widget-call-history-detail-page.component-BT4clUO-.mjs} +4 -4
  8. package/fesm2022/{edvak99-voice-receptionist-widget-call-history-detail-page.component-DShtvrbw.mjs.map → edvak99-voice-receptionist-widget-call-history-detail-page.component-BT4clUO-.mjs.map} +1 -1
  9. package/fesm2022/edvak99-voice-receptionist-widget-call-history-page.component-BACON4uq.mjs +247 -0
  10. package/fesm2022/edvak99-voice-receptionist-widget-call-history-page.component-BACON4uq.mjs.map +1 -0
  11. package/fesm2022/{edvak99-voice-receptionist-widget-call-recording-player.component-CSKZTNFs.mjs → edvak99-voice-receptionist-widget-call-recording-player.component-4fL-zUWy.mjs} +2 -2
  12. package/fesm2022/{edvak99-voice-receptionist-widget-call-recording-player.component-CSKZTNFs.mjs.map → edvak99-voice-receptionist-widget-call-recording-player.component-4fL-zUWy.mjs.map} +1 -1
  13. package/fesm2022/{edvak99-voice-receptionist-widget-call-review.service-C5BQdHNZ.mjs → edvak99-voice-receptionist-widget-call-review.service-BhbCmB1S.mjs} +2 -2
  14. package/fesm2022/{edvak99-voice-receptionist-widget-call-review.service-C5BQdHNZ.mjs.map → edvak99-voice-receptionist-widget-call-review.service-BhbCmB1S.mjs.map} +1 -1
  15. package/fesm2022/{edvak99-voice-receptionist-widget-dashboard-page.component-CE2Zh0eJ.mjs → edvak99-voice-receptionist-widget-dashboard-page.component-CxNYLBbg.mjs} +2 -2
  16. package/fesm2022/{edvak99-voice-receptionist-widget-dashboard-page.component-CE2Zh0eJ.mjs.map → edvak99-voice-receptionist-widget-dashboard-page.component-CxNYLBbg.mjs.map} +1 -1
  17. package/fesm2022/{edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-Cbn5DmQI.mjs → edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-DDS7VdnD.mjs} +153 -28
  18. package/fesm2022/edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-DDS7VdnD.mjs.map +1 -0
  19. package/fesm2022/{edvak99-voice-receptionist-widget-live-calls-page.component-OYQuPU33.mjs → edvak99-voice-receptionist-widget-live-calls-page.component-4LtgT4lS.mjs} +2 -2
  20. package/fesm2022/{edvak99-voice-receptionist-widget-live-calls-page.component-OYQuPU33.mjs.map → edvak99-voice-receptionist-widget-live-calls-page.component-4LtgT4lS.mjs.map} +1 -1
  21. package/fesm2022/{edvak99-voice-receptionist-widget-live-monitor-page.component-jHHs_DbW.mjs → edvak99-voice-receptionist-widget-live-monitor-page.component-B1lKfw-j.mjs} +8 -8
  22. package/fesm2022/edvak99-voice-receptionist-widget-live-monitor-page.component-B1lKfw-j.mjs.map +1 -0
  23. package/fesm2022/{edvak99-voice-receptionist-widget-outbound-purposes-page.component-C8wLTIF0.mjs → edvak99-voice-receptionist-widget-outbound-purposes-page.component-BkIHblSu.mjs} +4 -4
  24. package/fesm2022/edvak99-voice-receptionist-widget-outbound-purposes-page.component-BkIHblSu.mjs.map +1 -0
  25. package/fesm2022/{edvak99-voice-receptionist-widget-task-detail-drawer.component-CDaYKu5_.mjs → edvak99-voice-receptionist-widget-task-detail-drawer.component-aDTKTV79.mjs} +2 -2
  26. package/fesm2022/{edvak99-voice-receptionist-widget-task-detail-drawer.component-CDaYKu5_.mjs.map → edvak99-voice-receptionist-widget-task-detail-drawer.component-aDTKTV79.mjs.map} +1 -1
  27. package/fesm2022/edvak99-voice-receptionist-widget-tasks-page.component-Dj1nWx6V.mjs +150 -0
  28. package/fesm2022/edvak99-voice-receptionist-widget-tasks-page.component-Dj1nWx6V.mjs.map +1 -0
  29. package/fesm2022/{edvak99-voice-receptionist-widget-wizard-page.component-BtfZJm3V.mjs → edvak99-voice-receptionist-widget-wizard-page.component-CQttbEzW.mjs} +2 -2
  30. package/fesm2022/{edvak99-voice-receptionist-widget-wizard-page.component-BtfZJm3V.mjs.map → edvak99-voice-receptionist-widget-wizard-page.component-CQttbEzW.mjs.map} +1 -1
  31. package/fesm2022/edvak99-voice-receptionist-widget.mjs +1 -1
  32. package/lib/models/ai-receptionist.types.d.ts +17 -0
  33. package/lib/pages/analytics-page/analytics-page.component.d.ts +25 -5
  34. package/lib/pages/call-history-page/call-history-page.component.d.ts +1 -0
  35. package/lib/services/ai-receptionist-api.mock.d.ts +5 -8
  36. package/lib/services/ai-receptionist-api.service.d.ts +10 -8
  37. package/lib/utils/csv-download.util.d.ts +2 -0
  38. package/package.json +1 -1
  39. package/styles/embed.scss +29 -1
  40. package/fesm2022/edvak99-voice-receptionist-widget-activities-page.component-D3FI89cY.mjs +0 -510
  41. package/fesm2022/edvak99-voice-receptionist-widget-activities-page.component-D3FI89cY.mjs.map +0 -1
  42. package/fesm2022/edvak99-voice-receptionist-widget-analytics-page.component-DjmJ2eUU.mjs +0 -363
  43. package/fesm2022/edvak99-voice-receptionist-widget-analytics-page.component-DjmJ2eUU.mjs.map +0 -1
  44. package/fesm2022/edvak99-voice-receptionist-widget-audit-page.component-DY_zyJli.mjs +0 -78
  45. package/fesm2022/edvak99-voice-receptionist-widget-audit-page.component-DY_zyJli.mjs.map +0 -1
  46. package/fesm2022/edvak99-voice-receptionist-widget-call-history-page.component-BftVST1n.mjs +0 -259
  47. package/fesm2022/edvak99-voice-receptionist-widget-call-history-page.component-BftVST1n.mjs.map +0 -1
  48. package/fesm2022/edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-Cbn5DmQI.mjs.map +0 -1
  49. package/fesm2022/edvak99-voice-receptionist-widget-live-monitor-page.component-jHHs_DbW.mjs.map +0 -1
  50. package/fesm2022/edvak99-voice-receptionist-widget-outbound-purposes-page.component-C8wLTIF0.mjs.map +0 -1
  51. package/fesm2022/edvak99-voice-receptionist-widget-tasks-page.component-C0TaBp8P.mjs +0 -150
  52. package/fesm2022/edvak99-voice-receptionist-widget-tasks-page.component-C0TaBp8P.mjs.map +0 -1
@@ -0,0 +1,150 @@
1
+ import { DatePipe } from '@angular/common';
2
+ import * as i0 from '@angular/core';
3
+ import { inject, signal, computed, CUSTOM_ELEMENTS_SCHEMA, ChangeDetectionStrategy, Component } from '@angular/core';
4
+ import { ActivatedRoute, RouterLink } from '@angular/router';
5
+ import { A as AiReceptionistApiService, m as DEFAULT_PAGE_SIZE, n as totalPages, f as EdButtonComponent, g as EdSkeletonComponent } from './edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-DDS7VdnD.mjs';
6
+ import { a as TASK_TYPE_OPTIONS, t as taskStatusLabel, b as taskStatusTone, c as taskPriorityTone, d as taskSourceLabel, e as taskTypeTone, f as taskCallRoute, T as TaskDetailDrawerComponent } from './edvak99-voice-receptionist-widget-task-detail-drawer.component-aDTKTV79.mjs';
7
+ import { S as SmartTooltipDirective } from './edvak99-voice-receptionist-widget-smart-tooltip.directive-ChEdIem3.mjs';
8
+ import { T as TABLE_SKELETON_ROWS } from './edvak99-voice-receptionist-widget-table-skeleton.constants-C1Dg9Z_2.mjs';
9
+
10
+ class TasksPageComponent {
11
+ constructor() {
12
+ this.api = inject(AiReceptionistApiService);
13
+ this.route = inject(ActivatedRoute);
14
+ this.pageSize = DEFAULT_PAGE_SIZE;
15
+ this.tasks = signal([]);
16
+ this.total = signal(0);
17
+ this.page = signal(1);
18
+ this.loading = signal(true);
19
+ this.skeletonRows = TABLE_SKELETON_ROWS;
20
+ this.selectedTask = signal(null);
21
+ /** Default to Open so staff see actionable work; Done tab for completed. */
22
+ this.statusFilter = signal('open');
23
+ this.typeFilter = signal('');
24
+ this.sourceFilter = signal('');
25
+ this.callIdFilter = signal('');
26
+ this.statusTabs = [
27
+ { id: 'open', label: 'Open' },
28
+ { id: 'in_progress', label: 'In progress' },
29
+ { id: 'done', label: 'Done' },
30
+ { id: '', label: 'All' },
31
+ ];
32
+ this.typeOptions = TASK_TYPE_OPTIONS;
33
+ this.taskStatusLabel = taskStatusLabel;
34
+ this.taskStatusTone = taskStatusTone;
35
+ this.taskPriorityTone = taskPriorityTone;
36
+ this.taskSourceLabel = taskSourceLabel;
37
+ this.taskTypeTone = taskTypeTone;
38
+ this.taskCallRoute = taskCallRoute;
39
+ this.hasActiveFilters = computed(() => !!this.typeFilter() ||
40
+ !!this.sourceFilter() ||
41
+ !!this.callIdFilter());
42
+ }
43
+ ngOnInit() {
44
+ const callId = this.route.snapshot.queryParamMap.get('callId') ?? '';
45
+ if (callId)
46
+ this.callIdFilter.set(callId);
47
+ this.load();
48
+ }
49
+ setStatusFilter(value) {
50
+ this.statusFilter.set(value);
51
+ this.page.set(1);
52
+ this.load();
53
+ }
54
+ setTypeFilter(value) {
55
+ this.typeFilter.set(value);
56
+ this.page.set(1);
57
+ this.load();
58
+ }
59
+ setSourceFilter(value) {
60
+ this.sourceFilter.set(value);
61
+ this.page.set(1);
62
+ this.load();
63
+ }
64
+ setCallIdFilter(value) {
65
+ this.callIdFilter.set(value);
66
+ this.page.set(1);
67
+ this.load();
68
+ }
69
+ clearFilters() {
70
+ this.statusFilter.set('open');
71
+ this.typeFilter.set('');
72
+ this.sourceFilter.set('');
73
+ this.callIdFilter.set('');
74
+ this.page.set(1);
75
+ this.load();
76
+ }
77
+ openTask(task) {
78
+ this.selectedTask.set(task);
79
+ }
80
+ closeDrawer() {
81
+ this.selectedTask.set(null);
82
+ }
83
+ onStatusChange(status) {
84
+ const task = this.selectedTask();
85
+ if (!task)
86
+ return;
87
+ this.api.patchTask(task.id, status).subscribe(({ data }) => {
88
+ if (data) {
89
+ this.selectedTask.set(data);
90
+ // Refresh list so Open/Done tabs stay accurate after status change.
91
+ this.load();
92
+ }
93
+ });
94
+ }
95
+ totalPages() {
96
+ return totalPages(this.total(), DEFAULT_PAGE_SIZE);
97
+ }
98
+ prevPage() {
99
+ if (this.page() <= 1)
100
+ return;
101
+ this.page.update((p) => p - 1);
102
+ this.load();
103
+ }
104
+ nextPage() {
105
+ if (this.page() >= this.totalPages())
106
+ return;
107
+ this.page.update((p) => p + 1);
108
+ this.load();
109
+ }
110
+ load() {
111
+ this.loading.set(true);
112
+ const filters = {
113
+ page: this.page(),
114
+ limit: DEFAULT_PAGE_SIZE,
115
+ };
116
+ if (this.statusFilter())
117
+ filters.status = this.statusFilter();
118
+ if (this.typeFilter())
119
+ filters.type = this.typeFilter();
120
+ if (this.sourceFilter())
121
+ filters.source = this.sourceFilter();
122
+ if (this.callIdFilter().trim())
123
+ filters.callId = this.callIdFilter().trim();
124
+ this.api.getTasks(filters).subscribe({
125
+ next: ({ items, total, page }) => {
126
+ this.tasks.set(items);
127
+ this.total.set(total);
128
+ this.page.set(page);
129
+ this.loading.set(false);
130
+ },
131
+ error: () => this.loading.set(false),
132
+ });
133
+ }
134
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: TasksPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
135
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: TasksPageComponent, isStandalone: true, selector: "eds-tasks-page", host: { classAttribute: "block h-full min-h-0" }, ngImport: i0, template: "<div class=\"flex h-full min-h-0 flex-col overflow-hidden bg-lighter p-base tasks-page\">\n <header class=\"relative z-10 mb-base flex shrink-0 items-start justify-between gap-base bg-lighter\">\n <div>\n <h4>Tasks & follow-ups</h4>\n <p class=\"fs-sm text-light\">Action items from calls \u2014 all types, not just refills</p>\n </div>\n </header>\n\n <nav class=\"mb-4 flex flex-wrap gap-2\" aria-label=\"Task status\">\n @for (tab of statusTabs; track tab.id) {\n <button\n type=\"button\"\n [class]=\"\n statusFilter() === tab.id\n ? 'cursor-pointer rounded-full border-none bg-blue-50 px-4 py-2 text-sm font-medium text-blue-600 transition-colors'\n : 'cursor-pointer rounded-full border-none bg-transparent px-4 py-2 text-sm font-medium text-zinc-500 transition-colors hover:bg-white hover:text-zinc-700'\n \"\n (click)=\"setStatusFilter(tab.id)\"\n >\n {{ tab.label }}\n </button>\n }\n </nav>\n\n <section class=\"flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden rounded-lg border border-base bg-white shadow-sm\">\n <div class=\"flex flex-wrap items-end gap-4 border-b border-zinc-200 px-6 py-4 max-[920px]:px-4 max-[920px]:py-4\">\n <div class=\"mb-sm\">\n <label for=\"task-type\">Type</label>\n <select\n id=\"task-type\"\n class=\"form-select min-w-36\"\n [value]=\"typeFilter()\"\n (change)=\"setTypeFilter($any($event.target).value)\"\n autocomplete=\"off\"\n >\n <option value=\"\">All types</option>\n @for (t of typeOptions; track t) {\n <option [value]=\"t\">{{ t }}</option>\n }\n </select>\n </div>\n <div class=\"mb-sm\">\n <label for=\"task-source\">Source</label>\n <select\n id=\"task-source\"\n class=\"form-select min-w-36\"\n [value]=\"sourceFilter()\"\n (change)=\"setSourceFilter($any($event.target).value)\"\n autocomplete=\"off\"\n >\n <option value=\"\">All sources</option>\n <option value=\"voice\">Voice</option>\n <option value=\"sync\">Sync</option>\n <option value=\"manual\">Manual</option>\n </select>\n </div>\n <div class=\"mb-sm\">\n <label for=\"task-call\">Call ID</label>\n <input\n id=\"task-call\"\n class=\"form-input\"\n type=\"text\"\n [value]=\"callIdFilter()\"\n placeholder=\"Filter by call\"\n (change)=\"setCallIdFilter($any($event.target).value)\"\n autocomplete=\"off\"\n />\n </div>\n @if (hasActiveFilters()) {\n <button\n type=\"button\"\n class=\"cursor-pointer border-none bg-transparent p-0 text-sm font-medium text-blue-600 hover:underline\"\n (click)=\"clearFilters()\"\n >\n Clear filters\n </button>\n }\n </div>\n\n <div class=\"eds-table-scroll min-h-0 min-w-0 flex-1\">\n <table class=\"table-default eds-sticky-table min-w-3xl w-full\">\n <thead>\n <tr>\n <th>Created</th>\n <th>Title</th>\n <th>Type</th>\n <th>Patient</th>\n <th>Priority</th>\n <th>Status</th>\n <th>Source</th>\n <th>Call</th>\n </tr>\n </thead>\n @if (loading()) {\n <tbody aria-busy=\"true\">\n @for (_ of skeletonRows; track _) {\n <tr>\n <td><ed-skeleton class=\"h-3 w-24\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-3 w-48\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-5 w-20 !rounded-full\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-3 w-28\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-5 w-16 !rounded-full\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-5 w-20 !rounded-full\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-3 w-16\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-3 w-20\"></ed-skeleton></td>\n </tr>\n }\n </tbody>\n } @else {\n <tbody>\n @for (task of tasks(); track task.id) {\n <tr tabindex=\"0\" (click)=\"openTask(task)\" (keyup.enter)=\"openTask(task)\">\n <td class=\"fs-sm text-light\">{{ task.created | date: 'MM/dd/yy, h:mm a' }}</td>\n <td>\n <span\n class=\"inline-block min-w-0 max-w-72 truncate font-medium text-dark\"\n [smartTooltip]=\"task.title\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ task.title }}</span>\n </td>\n <td><ed-badge-2 [attr.variant]=\"taskTypeTone(task.type)\">{{ task.type }}</ed-badge-2></td>\n <td>\n <span\n class=\"inline-block min-w-0 max-w-56 truncate\"\n [smartTooltip]=\"task.patient\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ task.patient }}</span>\n </td>\n <td>\n <ed-badge-2 [attr.variant]=\"taskPriorityTone(task.priority)\">\n {{ task.priority === 'urgent' ? 'Urgent' : 'Normal' }}\n </ed-badge-2>\n </td>\n <td><ed-badge-2 [attr.variant]=\"taskStatusTone(task.status)\">{{ taskStatusLabel(task.status) }}</ed-badge-2></td>\n <td class=\"fs-sm text-light\">{{ taskSourceLabel(task.source) }}</td>\n <td (click)=\"$event.stopPropagation()\">\n @if (task.callId) {\n <a\n [routerLink]=\"taskCallRoute(task.callId)\"\n class=\"text-sm font-medium text-blue-600 no-underline hover:underline\"\n >{{ task.callId }}</a>\n } @else {\n <span class=\"text-zinc-500\">\u2014</span>\n }\n </td>\n </tr>\n } @empty {\n <tr>\n <td colspan=\"8\" class=\"fs-sm text-light p-8 text-center\">No tasks match these filters.</td>\n </tr>\n }\n </tbody>\n }\n </table>\n </div>\n\n <footer class=\"flex items-center justify-between border-t border-zinc-200 px-6 py-4 text-sm text-zinc-500\">\n <span>Page {{ page() }} of {{ totalPages() }} \u00B7 {{ total() }} total</span>\n <div class=\"flex gap-2\">\n <ed-button variant=\"secondary\" outline size=\"sm\" [disabled]=\"page() <= 1\" (click$)=\"prevPage()\">Previous</ed-button>\n <ed-button variant=\"secondary\" outline size=\"sm\" [disabled]=\"page() >= totalPages()\" (click$)=\"nextPage()\">Next</ed-button>\n </div>\n </footer>\n </section>\n</div>\n\n@if (selectedTask(); as task) {\n <eds-task-detail-drawer\n [task]=\"task\"\n (closed)=\"closeDrawer()\"\n (statusChange)=\"onStatusChange($event)\"\n />\n}\n", dependencies: [{ kind: "pipe", type: DatePipe, name: "date" }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: EdButtonComponent, selector: "ed-button", inputs: ["variant", "size", "disabled", "ghost", "outline", "subtle", "fill", "loading", "block", "elevated", "shape", "type", "href", "routerLink", "rel", "target", "download", "ariaLabel"], outputs: ["click$"] }, { kind: "component", type: TaskDetailDrawerComponent, selector: "eds-task-detail-drawer", inputs: ["task"], outputs: ["closed", "statusChange"] }, { kind: "directive", type: SmartTooltipDirective, selector: "[smartTooltip]", inputs: ["smartTooltip", "tooltipAllowHtml", "tooltipTemplate", "tooltipTemplateContext", "tooltipPlacement", "tooltipTrigger", "tooltipDelayShow", "tooltipDelayHide", "tooltipOffset", "tooltipMaxWidth", "tooltipZIndex", "tooltipClass", "tooltipDisabled", "tooltipArrow", "tooltipHoverIntentMs", "tooltipHoverIntentRadius", "tooltipId", "tooltipRole", "tooltipAnimEnterMs", "tooltipAnimExitMs", "tooltipAnimEasing", "tooltipHoverable", "tooltipHandoffMs", "tooltipOpen", "tooltipOnlyWhenTruncated"] }, { kind: "component", type: EdSkeletonComponent, selector: "ed-skeleton", inputs: ["class"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
136
+ }
137
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: TasksPageComponent, decorators: [{
138
+ type: Component,
139
+ args: [{ selector: 'eds-tasks-page', imports: [
140
+ DatePipe,
141
+ RouterLink,
142
+ EdButtonComponent,
143
+ TaskDetailDrawerComponent,
144
+ SmartTooltipDirective,
145
+ EdSkeletonComponent,
146
+ ], changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'block h-full min-h-0' }, schemas: [CUSTOM_ELEMENTS_SCHEMA], template: "<div class=\"flex h-full min-h-0 flex-col overflow-hidden bg-lighter p-base tasks-page\">\n <header class=\"relative z-10 mb-base flex shrink-0 items-start justify-between gap-base bg-lighter\">\n <div>\n <h4>Tasks & follow-ups</h4>\n <p class=\"fs-sm text-light\">Action items from calls \u2014 all types, not just refills</p>\n </div>\n </header>\n\n <nav class=\"mb-4 flex flex-wrap gap-2\" aria-label=\"Task status\">\n @for (tab of statusTabs; track tab.id) {\n <button\n type=\"button\"\n [class]=\"\n statusFilter() === tab.id\n ? 'cursor-pointer rounded-full border-none bg-blue-50 px-4 py-2 text-sm font-medium text-blue-600 transition-colors'\n : 'cursor-pointer rounded-full border-none bg-transparent px-4 py-2 text-sm font-medium text-zinc-500 transition-colors hover:bg-white hover:text-zinc-700'\n \"\n (click)=\"setStatusFilter(tab.id)\"\n >\n {{ tab.label }}\n </button>\n }\n </nav>\n\n <section class=\"flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden rounded-lg border border-base bg-white shadow-sm\">\n <div class=\"flex flex-wrap items-end gap-4 border-b border-zinc-200 px-6 py-4 max-[920px]:px-4 max-[920px]:py-4\">\n <div class=\"mb-sm\">\n <label for=\"task-type\">Type</label>\n <select\n id=\"task-type\"\n class=\"form-select min-w-36\"\n [value]=\"typeFilter()\"\n (change)=\"setTypeFilter($any($event.target).value)\"\n autocomplete=\"off\"\n >\n <option value=\"\">All types</option>\n @for (t of typeOptions; track t) {\n <option [value]=\"t\">{{ t }}</option>\n }\n </select>\n </div>\n <div class=\"mb-sm\">\n <label for=\"task-source\">Source</label>\n <select\n id=\"task-source\"\n class=\"form-select min-w-36\"\n [value]=\"sourceFilter()\"\n (change)=\"setSourceFilter($any($event.target).value)\"\n autocomplete=\"off\"\n >\n <option value=\"\">All sources</option>\n <option value=\"voice\">Voice</option>\n <option value=\"sync\">Sync</option>\n <option value=\"manual\">Manual</option>\n </select>\n </div>\n <div class=\"mb-sm\">\n <label for=\"task-call\">Call ID</label>\n <input\n id=\"task-call\"\n class=\"form-input\"\n type=\"text\"\n [value]=\"callIdFilter()\"\n placeholder=\"Filter by call\"\n (change)=\"setCallIdFilter($any($event.target).value)\"\n autocomplete=\"off\"\n />\n </div>\n @if (hasActiveFilters()) {\n <button\n type=\"button\"\n class=\"cursor-pointer border-none bg-transparent p-0 text-sm font-medium text-blue-600 hover:underline\"\n (click)=\"clearFilters()\"\n >\n Clear filters\n </button>\n }\n </div>\n\n <div class=\"eds-table-scroll min-h-0 min-w-0 flex-1\">\n <table class=\"table-default eds-sticky-table min-w-3xl w-full\">\n <thead>\n <tr>\n <th>Created</th>\n <th>Title</th>\n <th>Type</th>\n <th>Patient</th>\n <th>Priority</th>\n <th>Status</th>\n <th>Source</th>\n <th>Call</th>\n </tr>\n </thead>\n @if (loading()) {\n <tbody aria-busy=\"true\">\n @for (_ of skeletonRows; track _) {\n <tr>\n <td><ed-skeleton class=\"h-3 w-24\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-3 w-48\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-5 w-20 !rounded-full\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-3 w-28\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-5 w-16 !rounded-full\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-5 w-20 !rounded-full\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-3 w-16\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-3 w-20\"></ed-skeleton></td>\n </tr>\n }\n </tbody>\n } @else {\n <tbody>\n @for (task of tasks(); track task.id) {\n <tr tabindex=\"0\" (click)=\"openTask(task)\" (keyup.enter)=\"openTask(task)\">\n <td class=\"fs-sm text-light\">{{ task.created | date: 'MM/dd/yy, h:mm a' }}</td>\n <td>\n <span\n class=\"inline-block min-w-0 max-w-72 truncate font-medium text-dark\"\n [smartTooltip]=\"task.title\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ task.title }}</span>\n </td>\n <td><ed-badge-2 [attr.variant]=\"taskTypeTone(task.type)\">{{ task.type }}</ed-badge-2></td>\n <td>\n <span\n class=\"inline-block min-w-0 max-w-56 truncate\"\n [smartTooltip]=\"task.patient\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ task.patient }}</span>\n </td>\n <td>\n <ed-badge-2 [attr.variant]=\"taskPriorityTone(task.priority)\">\n {{ task.priority === 'urgent' ? 'Urgent' : 'Normal' }}\n </ed-badge-2>\n </td>\n <td><ed-badge-2 [attr.variant]=\"taskStatusTone(task.status)\">{{ taskStatusLabel(task.status) }}</ed-badge-2></td>\n <td class=\"fs-sm text-light\">{{ taskSourceLabel(task.source) }}</td>\n <td (click)=\"$event.stopPropagation()\">\n @if (task.callId) {\n <a\n [routerLink]=\"taskCallRoute(task.callId)\"\n class=\"text-sm font-medium text-blue-600 no-underline hover:underline\"\n >{{ task.callId }}</a>\n } @else {\n <span class=\"text-zinc-500\">\u2014</span>\n }\n </td>\n </tr>\n } @empty {\n <tr>\n <td colspan=\"8\" class=\"fs-sm text-light p-8 text-center\">No tasks match these filters.</td>\n </tr>\n }\n </tbody>\n }\n </table>\n </div>\n\n <footer class=\"flex items-center justify-between border-t border-zinc-200 px-6 py-4 text-sm text-zinc-500\">\n <span>Page {{ page() }} of {{ totalPages() }} \u00B7 {{ total() }} total</span>\n <div class=\"flex gap-2\">\n <ed-button variant=\"secondary\" outline size=\"sm\" [disabled]=\"page() <= 1\" (click$)=\"prevPage()\">Previous</ed-button>\n <ed-button variant=\"secondary\" outline size=\"sm\" [disabled]=\"page() >= totalPages()\" (click$)=\"nextPage()\">Next</ed-button>\n </div>\n </footer>\n </section>\n</div>\n\n@if (selectedTask(); as task) {\n <eds-task-detail-drawer\n [task]=\"task\"\n (closed)=\"closeDrawer()\"\n (statusChange)=\"onStatusChange($event)\"\n />\n}\n" }]
147
+ }] });
148
+
149
+ export { TasksPageComponent };
150
+ //# sourceMappingURL=edvak99-voice-receptionist-widget-tasks-page.component-Dj1nWx6V.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edvak99-voice-receptionist-widget-tasks-page.component-Dj1nWx6V.mjs","sources":["../../../src/lib/pages/tasks-page/tasks-page.component.ts","../../../src/lib/pages/tasks-page/tasks-page.component.html"],"sourcesContent":["import { DatePipe } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, CUSTOM_ELEMENTS_SCHEMA, computed, inject, OnInit, signal } from '@angular/core';\nimport { ActivatedRoute, RouterLink } from '@angular/router';\n\nimport { EdButtonComponent } from '../../ui/ed-button.component';\nimport { EdSkeletonComponent } from '../../ui/ed-skeleton.component';\n\nimport { TaskDetailDrawerComponent } from '../../components/task-detail-drawer/task-detail-drawer.component';\n\nimport { SmartTooltipDirective } from '../../shared/smart-tooltip.directive';\nimport { TABLE_SKELETON_ROWS } from '../../shared/table-skeleton.constants';\nimport {\n TaskFilters,\n TaskItem,\n TaskSource,\n TaskStatus,\n} from '../../models/ai-receptionist.types';\nimport { DEFAULT_PAGE_SIZE, totalPages as calcTotalPages } from '../../models/pagination';\nimport { AiReceptionistApiService } from '../../services/ai-receptionist-api.service';\nimport {\n TASK_TYPE_OPTIONS,\n taskCallRoute,\n taskPriorityTone,\n taskSourceLabel,\n taskStatusLabel,\n taskStatusTone,\n taskTypeTone,\n} from '../../utils/task.util';\n\n@Component({\n selector: 'eds-tasks-page',\n imports: [\n DatePipe,\n RouterLink,\n EdButtonComponent,\n TaskDetailDrawerComponent,\n SmartTooltipDirective,\n EdSkeletonComponent,\n ],\n templateUrl: './tasks-page.component.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: { class: 'block h-full min-h-0' },\n schemas: [CUSTOM_ELEMENTS_SCHEMA],\n})\nexport class TasksPageComponent implements OnInit {\n private readonly api = inject(AiReceptionistApiService);\n private readonly route = inject(ActivatedRoute);\n\n protected readonly pageSize = DEFAULT_PAGE_SIZE;\n protected readonly tasks = signal<TaskItem[]>([]);\n protected readonly total = signal(0);\n protected readonly page = signal(1);\n protected readonly loading = signal(true);\n protected readonly skeletonRows = TABLE_SKELETON_ROWS;\n protected readonly selectedTask = signal<TaskItem | null>(null);\n\n /** Default to Open so staff see actionable work; Done tab for completed. */\n protected readonly statusFilter = signal<'' | TaskStatus>('open');\n protected readonly typeFilter = signal('');\n protected readonly sourceFilter = signal<'' | TaskSource>('');\n protected readonly callIdFilter = signal('');\n\n protected readonly statusTabs: { id: '' | TaskStatus; label: string }[] = [\n { id: 'open', label: 'Open' },\n { id: 'in_progress', label: 'In progress' },\n { id: 'done', label: 'Done' },\n { id: '', label: 'All' },\n ];\n\n protected readonly typeOptions = TASK_TYPE_OPTIONS;\n protected readonly taskStatusLabel = taskStatusLabel;\n protected readonly taskStatusTone = taskStatusTone;\n protected readonly taskPriorityTone = taskPriorityTone;\n protected readonly taskSourceLabel = taskSourceLabel;\n protected readonly taskTypeTone = taskTypeTone;\n protected readonly taskCallRoute = taskCallRoute;\n\n protected readonly hasActiveFilters = computed(\n () =>\n !!this.typeFilter() ||\n !!this.sourceFilter() ||\n !!this.callIdFilter(),\n );\n\n ngOnInit(): void {\n const callId = this.route.snapshot.queryParamMap.get('callId') ?? '';\n if (callId) this.callIdFilter.set(callId);\n this.load();\n }\n\n protected setStatusFilter(value: string): void {\n this.statusFilter.set(value as '' | TaskStatus);\n this.page.set(1);\n this.load();\n }\n\n protected setTypeFilter(value: string): void {\n this.typeFilter.set(value);\n this.page.set(1);\n this.load();\n }\n\n protected setSourceFilter(value: string): void {\n this.sourceFilter.set(value as '' | TaskSource);\n this.page.set(1);\n this.load();\n }\n\n protected setCallIdFilter(value: string): void {\n this.callIdFilter.set(value);\n this.page.set(1);\n this.load();\n }\n\n protected clearFilters(): void {\n this.statusFilter.set('open');\n this.typeFilter.set('');\n this.sourceFilter.set('');\n this.callIdFilter.set('');\n this.page.set(1);\n this.load();\n }\n\n protected openTask(task: TaskItem): void {\n this.selectedTask.set(task);\n }\n\n protected closeDrawer(): void {\n this.selectedTask.set(null);\n }\n\n protected onStatusChange(status: TaskStatus): void {\n const task = this.selectedTask();\n if (!task) return;\n this.api.patchTask(task.id, status).subscribe(({ data }) => {\n if (data) {\n this.selectedTask.set(data);\n // Refresh list so Open/Done tabs stay accurate after status change.\n this.load();\n }\n });\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 private load(): void {\n this.loading.set(true);\n const filters: TaskFilters = {\n page: this.page(),\n limit: DEFAULT_PAGE_SIZE,\n };\n if (this.statusFilter()) filters.status = this.statusFilter() as TaskStatus;\n if (this.typeFilter()) filters.type = this.typeFilter();\n if (this.sourceFilter()) filters.source = this.sourceFilter() as TaskSource;\n if (this.callIdFilter().trim()) filters.callId = this.callIdFilter().trim();\n\n this.api.getTasks(filters).subscribe({\n next: ({ items, total, page }) => {\n this.tasks.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","<div class=\"flex h-full min-h-0 flex-col overflow-hidden bg-lighter p-base tasks-page\">\n <header class=\"relative z-10 mb-base flex shrink-0 items-start justify-between gap-base bg-lighter\">\n <div>\n <h4>Tasks & follow-ups</h4>\n <p class=\"fs-sm text-light\">Action items from calls — all types, not just refills</p>\n </div>\n </header>\n\n <nav class=\"mb-4 flex flex-wrap gap-2\" aria-label=\"Task status\">\n @for (tab of statusTabs; track tab.id) {\n <button\n type=\"button\"\n [class]=\"\n statusFilter() === tab.id\n ? 'cursor-pointer rounded-full border-none bg-blue-50 px-4 py-2 text-sm font-medium text-blue-600 transition-colors'\n : 'cursor-pointer rounded-full border-none bg-transparent px-4 py-2 text-sm font-medium text-zinc-500 transition-colors hover:bg-white hover:text-zinc-700'\n \"\n (click)=\"setStatusFilter(tab.id)\"\n >\n {{ tab.label }}\n </button>\n }\n </nav>\n\n <section class=\"flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden rounded-lg border border-base bg-white shadow-sm\">\n <div class=\"flex flex-wrap items-end gap-4 border-b border-zinc-200 px-6 py-4 max-[920px]:px-4 max-[920px]:py-4\">\n <div class=\"mb-sm\">\n <label for=\"task-type\">Type</label>\n <select\n id=\"task-type\"\n class=\"form-select min-w-36\"\n [value]=\"typeFilter()\"\n (change)=\"setTypeFilter($any($event.target).value)\"\n autocomplete=\"off\"\n >\n <option value=\"\">All types</option>\n @for (t of typeOptions; track t) {\n <option [value]=\"t\">{{ t }}</option>\n }\n </select>\n </div>\n <div class=\"mb-sm\">\n <label for=\"task-source\">Source</label>\n <select\n id=\"task-source\"\n class=\"form-select min-w-36\"\n [value]=\"sourceFilter()\"\n (change)=\"setSourceFilter($any($event.target).value)\"\n autocomplete=\"off\"\n >\n <option value=\"\">All sources</option>\n <option value=\"voice\">Voice</option>\n <option value=\"sync\">Sync</option>\n <option value=\"manual\">Manual</option>\n </select>\n </div>\n <div class=\"mb-sm\">\n <label for=\"task-call\">Call ID</label>\n <input\n id=\"task-call\"\n class=\"form-input\"\n type=\"text\"\n [value]=\"callIdFilter()\"\n placeholder=\"Filter by call\"\n (change)=\"setCallIdFilter($any($event.target).value)\"\n autocomplete=\"off\"\n />\n </div>\n @if (hasActiveFilters()) {\n <button\n type=\"button\"\n class=\"cursor-pointer border-none bg-transparent p-0 text-sm font-medium text-blue-600 hover:underline\"\n (click)=\"clearFilters()\"\n >\n Clear filters\n </button>\n }\n </div>\n\n <div class=\"eds-table-scroll min-h-0 min-w-0 flex-1\">\n <table class=\"table-default eds-sticky-table min-w-3xl w-full\">\n <thead>\n <tr>\n <th>Created</th>\n <th>Title</th>\n <th>Type</th>\n <th>Patient</th>\n <th>Priority</th>\n <th>Status</th>\n <th>Source</th>\n <th>Call</th>\n </tr>\n </thead>\n @if (loading()) {\n <tbody aria-busy=\"true\">\n @for (_ of skeletonRows; track _) {\n <tr>\n <td><ed-skeleton class=\"h-3 w-24\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-3 w-48\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-5 w-20 !rounded-full\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-3 w-28\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-5 w-16 !rounded-full\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-5 w-20 !rounded-full\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-3 w-16\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-3 w-20\"></ed-skeleton></td>\n </tr>\n }\n </tbody>\n } @else {\n <tbody>\n @for (task of tasks(); track task.id) {\n <tr tabindex=\"0\" (click)=\"openTask(task)\" (keyup.enter)=\"openTask(task)\">\n <td class=\"fs-sm text-light\">{{ task.created | date: 'MM/dd/yy, h:mm a' }}</td>\n <td>\n <span\n class=\"inline-block min-w-0 max-w-72 truncate font-medium text-dark\"\n [smartTooltip]=\"task.title\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ task.title }}</span>\n </td>\n <td><ed-badge-2 [attr.variant]=\"taskTypeTone(task.type)\">{{ task.type }}</ed-badge-2></td>\n <td>\n <span\n class=\"inline-block min-w-0 max-w-56 truncate\"\n [smartTooltip]=\"task.patient\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ task.patient }}</span>\n </td>\n <td>\n <ed-badge-2 [attr.variant]=\"taskPriorityTone(task.priority)\">\n {{ task.priority === 'urgent' ? 'Urgent' : 'Normal' }}\n </ed-badge-2>\n </td>\n <td><ed-badge-2 [attr.variant]=\"taskStatusTone(task.status)\">{{ taskStatusLabel(task.status) }}</ed-badge-2></td>\n <td class=\"fs-sm text-light\">{{ taskSourceLabel(task.source) }}</td>\n <td (click)=\"$event.stopPropagation()\">\n @if (task.callId) {\n <a\n [routerLink]=\"taskCallRoute(task.callId)\"\n class=\"text-sm font-medium text-blue-600 no-underline hover:underline\"\n >{{ task.callId }}</a>\n } @else {\n <span class=\"text-zinc-500\">—</span>\n }\n </td>\n </tr>\n } @empty {\n <tr>\n <td colspan=\"8\" class=\"fs-sm text-light p-8 text-center\">No tasks match these filters.</td>\n </tr>\n }\n </tbody>\n }\n </table>\n </div>\n\n <footer class=\"flex items-center justify-between border-t border-zinc-200 px-6 py-4 text-sm text-zinc-500\">\n <span>Page {{ page() }} of {{ totalPages() }} · {{ total() }} total</span>\n <div class=\"flex gap-2\">\n <ed-button variant=\"secondary\" outline size=\"sm\" [disabled]=\"page() <= 1\" (click$)=\"prevPage()\">Previous</ed-button>\n <ed-button variant=\"secondary\" outline size=\"sm\" [disabled]=\"page() >= totalPages()\" (click$)=\"nextPage()\">Next</ed-button>\n </div>\n </footer>\n </section>\n</div>\n\n@if (selectedTask(); as task) {\n <eds-task-detail-drawer\n [task]=\"task\"\n (closed)=\"closeDrawer()\"\n (statusChange)=\"onStatusChange($event)\"\n />\n}\n"],"names":["calcTotalPages"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { inject, signal, computed, CUSTOM_ELEMENTS_SCHEMA, ChangeDetectionStrategy, Component } from '@angular/core';
3
- import { A as AiReceptionistApiService, I as IconComponent, f as EdButtonComponent, g as EdSkeletonComponent } from './edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-Cbn5DmQI.mjs';
3
+ import { A as AiReceptionistApiService, I as IconComponent, f as EdButtonComponent, g as EdSkeletonComponent } from './edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-DDS7VdnD.mjs';
4
4
 
5
5
  class WizardPageComponent {
6
6
  constructor() {
@@ -44,4 +44,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
44
44
  }] });
45
45
 
46
46
  export { WizardPageComponent };
47
- //# sourceMappingURL=edvak99-voice-receptionist-widget-wizard-page.component-BtfZJm3V.mjs.map
47
+ //# sourceMappingURL=edvak99-voice-receptionist-widget-wizard-page.component-CQttbEzW.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"edvak99-voice-receptionist-widget-wizard-page.component-BtfZJm3V.mjs","sources":["../../../src/lib/pages/wizard-page/wizard-page.component.ts","../../../src/lib/pages/wizard-page/wizard-page.component.html"],"sourcesContent":["import { ChangeDetectionStrategy, Component, CUSTOM_ELEMENTS_SCHEMA, computed, inject, OnInit, signal } from '@angular/core';\n\nimport { EdButtonComponent } from '../../ui/ed-button.component';\nimport { EdSkeletonComponent } from '../../ui/ed-skeleton.component';\n\nimport { SetupData, SetupStep } from '../../models/ai-receptionist.types';\nimport { AiReceptionistApiService } from '../../services/ai-receptionist-api.service';\nimport { IconComponent } from '../../ui/ed-icon.component';\n\n@Component({\n selector: 'eds-wizard-page',\n imports: [IconComponent, EdButtonComponent, EdSkeletonComponent],\n templateUrl: './wizard-page.component.html',\n styleUrl: './wizard-page.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n schemas: [CUSTOM_ELEMENTS_SCHEMA],\n})\nexport class WizardPageComponent implements OnInit {\n private readonly api = inject(AiReceptionistApiService);\n\n protected readonly setup = signal<SetupData | null>(null);\n protected readonly activeStep = signal(1);\n protected readonly loading = signal(true);\n protected readonly activated = signal(false);\n protected readonly stepSkeletonRows = [0, 1, 2, 3, 4] as const;\n protected readonly transcriptSkeletonRows = [0, 1, 2] as const;\n\n protected readonly completedCount = computed(() => {\n return this.setup()?.steps.filter((s) => s.complete).length ?? 0;\n });\n\n ngOnInit(): void {\n this.api.getSetup().subscribe(({ data }) => {\n this.setup.set(data);\n const firstIncomplete = data.steps.find((s) => !s.complete);\n this.activeStep.set(firstIncomplete?.id ?? 1);\n this.loading.set(false);\n });\n }\n\n protected selectStep(step: SetupStep): void {\n this.activeStep.set(step.id);\n }\n\n protected progressPercent(): number {\n return this.setup()?.readiness ?? 0;\n }\n\n protected activate(): void {\n this.api.activateSetup().subscribe(() => {\n this.api.setAgentOn(true);\n this.activated.set(true);\n });\n }\n}\n","<div class=\"p-md bg-lighter min-h-full wizard-page\">\n <header class=\"mb-5 flex items-start justify-between gap-5\">\n <div>\n <h4>Setup wizard</h4>\n <p class=\"fs-sm text-light\">Configure and activate your AI receptionist</p>\n </div>\n <div class=\"flex min-w-52 flex-col items-end gap-2\">\n <span class=\"fs-sm font-semibold text-light\">Readiness</span>\n <div class=\"h-2 w-52 overflow-hidden rounded bg-zinc-100\">\n <span\n class=\"block h-full rounded bg-gradient-to-r from-blue-600 to-violet-600 transition-[width] duration-300 ease-in-out\"\n [style.width.%]=\"progressPercent()\"\n ></span>\n </div>\n <span class=\"fs-sm font-semibold text-dark\">{{ progressPercent() }}%</span>\n </div>\n </header>\n\n @if (loading()) {\n <div class=\"wizard-page__layout\" aria-busy=\"true\">\n <nav class=\"rounded-lg border border-base bg-white flex flex-col gap-1 overflow-y-auto p-2 shadow-sm\">\n @for (_ of stepSkeletonRows; track _) {\n <div class=\"flex w-full items-start gap-3 rounded-md p-3\">\n <ed-skeleton class=\"h-7 w-7 !rounded-full\"></ed-skeleton>\n <div class=\"grid flex-1 gap-2xs\">\n <ed-skeleton class=\"h-3 w-28\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-40\"></ed-skeleton>\n </div>\n </div>\n }\n </nav>\n <article class=\"rounded-lg border border-base bg-white p-5 shadow-sm\">\n <header class=\"mb-3 flex items-center justify-between gap-3\">\n <ed-skeleton class=\"h-6 w-48\"></ed-skeleton>\n <ed-skeleton class=\"h-5 w-20 !rounded-full\"></ed-skeleton>\n </header>\n <ed-skeleton class=\"mb-6 h-4 w-72\"></ed-skeleton>\n <section class=\"mt-6 border-t border-zinc-200 pt-5\">\n <ed-skeleton class=\"mb-3 h-5 w-40\"></ed-skeleton>\n @for (_ of transcriptSkeletonRows; track _) {\n <div class=\"mb-3 rounded-md bg-zinc-50 px-3 py-3\">\n <ed-skeleton class=\"mb-1 h-3 w-16\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-full\"></ed-skeleton>\n </div>\n }\n </section>\n </article>\n </div>\n } @else if (setup()) {\n <div class=\"wizard-page__layout\">\n <nav class=\"rounded-lg border border-base bg-white wizard-page__steps flex flex-col gap-1 overflow-y-auto p-2 shadow-sm\">\n @for (step of setup()!.steps; track step.id) {\n <button\n type=\"button\"\n class=\"wizard-page__step flex w-full cursor-pointer items-start gap-3 rounded-md border-none bg-transparent p-3 text-left hover:bg-zinc-50\"\n [class.wizard-page__step--active]=\"activeStep() === step.id\"\n [class.wizard-page__step--done]=\"step.complete\"\n (click)=\"selectStep(step)\"\n >\n <span class=\"wizard-page__step-num flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-zinc-100 text-xs font-semibold\">\n @if (step.complete) {\n <ed-icon name=\"check\" [size]=\"16\" />\n } @else {\n {{ step.id }}\n }\n </span>\n <div class=\"flex flex-col gap-1\">\n <span class=\"fs-sm font-semibold text-dark\">{{ step.title }}</span>\n <span class=\"fs-sm text-light\">{{ step.description }}</span>\n </div>\n </button>\n }\n </nav>\n\n <article class=\"rounded-lg border border-base bg-white p-5 shadow-sm\">\n @for (step of setup()!.steps; track step.id) {\n @if (activeStep() === step.id) {\n <header class=\"mb-3 flex items-center justify-between gap-3\">\n <h2>Step {{ step.id }}: {{ step.title }}</h2>\n <ed-badge-2 [attr.variant]=\"step.complete ? 'success' : 'warning'\">\n {{ step.complete ? 'Complete' : 'Incomplete' }}\n </ed-badge-2>\n </header>\n <p class=\"fs-base text-dark\">{{ step.description }}</p>\n }\n }\n\n <section class=\"mt-6 border-t border-zinc-200 pt-5\">\n <h3>Test transcript preview</h3>\n <div class=\"mt-3 flex flex-col gap-3\">\n @for (line of setup()!.testTranscript; track $index) {\n <div class=\"wizard-page__line rounded-md bg-zinc-50 px-3 py-3\" [attr.data-who]=\"line.who\">\n <span class=\"fs-sm font-semibold text-light\">{{ line.who }}</span>\n <p class=\"m-0 mt-1 text-sm\">{{ line.text }}</p>\n </div>\n }\n </div>\n </section>\n\n <footer class=\"mt-6 flex items-center justify-between border-t border-zinc-200 pt-4\">\n <p class=\"fs-sm text-light\">\n {{ completedCount() }} of {{ setup()!.steps.length }} steps complete\n </p>\n @if (activated()) {\n <ed-badge-2 variant=\"success\">Agent activated</ed-badge-2>\n } @else {\n <ed-button variant=\"primary\" fill size=\"sm\" (click$)=\"activate()\">\n <ed-icon slot=\"prefix\" name=\"rocket_launch\" [size]=\"16\" /> Activate AI receptionist\n </ed-button>\n }\n </footer>\n </article>\n </div>\n }\n</div>\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"edvak99-voice-receptionist-widget-wizard-page.component-CQttbEzW.mjs","sources":["../../../src/lib/pages/wizard-page/wizard-page.component.ts","../../../src/lib/pages/wizard-page/wizard-page.component.html"],"sourcesContent":["import { ChangeDetectionStrategy, Component, CUSTOM_ELEMENTS_SCHEMA, computed, inject, OnInit, signal } from '@angular/core';\n\nimport { EdButtonComponent } from '../../ui/ed-button.component';\nimport { EdSkeletonComponent } from '../../ui/ed-skeleton.component';\n\nimport { SetupData, SetupStep } from '../../models/ai-receptionist.types';\nimport { AiReceptionistApiService } from '../../services/ai-receptionist-api.service';\nimport { IconComponent } from '../../ui/ed-icon.component';\n\n@Component({\n selector: 'eds-wizard-page',\n imports: [IconComponent, EdButtonComponent, EdSkeletonComponent],\n templateUrl: './wizard-page.component.html',\n styleUrl: './wizard-page.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n schemas: [CUSTOM_ELEMENTS_SCHEMA],\n})\nexport class WizardPageComponent implements OnInit {\n private readonly api = inject(AiReceptionistApiService);\n\n protected readonly setup = signal<SetupData | null>(null);\n protected readonly activeStep = signal(1);\n protected readonly loading = signal(true);\n protected readonly activated = signal(false);\n protected readonly stepSkeletonRows = [0, 1, 2, 3, 4] as const;\n protected readonly transcriptSkeletonRows = [0, 1, 2] as const;\n\n protected readonly completedCount = computed(() => {\n return this.setup()?.steps.filter((s) => s.complete).length ?? 0;\n });\n\n ngOnInit(): void {\n this.api.getSetup().subscribe(({ data }) => {\n this.setup.set(data);\n const firstIncomplete = data.steps.find((s) => !s.complete);\n this.activeStep.set(firstIncomplete?.id ?? 1);\n this.loading.set(false);\n });\n }\n\n protected selectStep(step: SetupStep): void {\n this.activeStep.set(step.id);\n }\n\n protected progressPercent(): number {\n return this.setup()?.readiness ?? 0;\n }\n\n protected activate(): void {\n this.api.activateSetup().subscribe(() => {\n this.api.setAgentOn(true);\n this.activated.set(true);\n });\n }\n}\n","<div class=\"p-md bg-lighter min-h-full wizard-page\">\n <header class=\"mb-5 flex items-start justify-between gap-5\">\n <div>\n <h4>Setup wizard</h4>\n <p class=\"fs-sm text-light\">Configure and activate your AI receptionist</p>\n </div>\n <div class=\"flex min-w-52 flex-col items-end gap-2\">\n <span class=\"fs-sm font-semibold text-light\">Readiness</span>\n <div class=\"h-2 w-52 overflow-hidden rounded bg-zinc-100\">\n <span\n class=\"block h-full rounded bg-gradient-to-r from-blue-600 to-violet-600 transition-[width] duration-300 ease-in-out\"\n [style.width.%]=\"progressPercent()\"\n ></span>\n </div>\n <span class=\"fs-sm font-semibold text-dark\">{{ progressPercent() }}%</span>\n </div>\n </header>\n\n @if (loading()) {\n <div class=\"wizard-page__layout\" aria-busy=\"true\">\n <nav class=\"rounded-lg border border-base bg-white flex flex-col gap-1 overflow-y-auto p-2 shadow-sm\">\n @for (_ of stepSkeletonRows; track _) {\n <div class=\"flex w-full items-start gap-3 rounded-md p-3\">\n <ed-skeleton class=\"h-7 w-7 !rounded-full\"></ed-skeleton>\n <div class=\"grid flex-1 gap-2xs\">\n <ed-skeleton class=\"h-3 w-28\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-40\"></ed-skeleton>\n </div>\n </div>\n }\n </nav>\n <article class=\"rounded-lg border border-base bg-white p-5 shadow-sm\">\n <header class=\"mb-3 flex items-center justify-between gap-3\">\n <ed-skeleton class=\"h-6 w-48\"></ed-skeleton>\n <ed-skeleton class=\"h-5 w-20 !rounded-full\"></ed-skeleton>\n </header>\n <ed-skeleton class=\"mb-6 h-4 w-72\"></ed-skeleton>\n <section class=\"mt-6 border-t border-zinc-200 pt-5\">\n <ed-skeleton class=\"mb-3 h-5 w-40\"></ed-skeleton>\n @for (_ of transcriptSkeletonRows; track _) {\n <div class=\"mb-3 rounded-md bg-zinc-50 px-3 py-3\">\n <ed-skeleton class=\"mb-1 h-3 w-16\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-full\"></ed-skeleton>\n </div>\n }\n </section>\n </article>\n </div>\n } @else if (setup()) {\n <div class=\"wizard-page__layout\">\n <nav class=\"rounded-lg border border-base bg-white wizard-page__steps flex flex-col gap-1 overflow-y-auto p-2 shadow-sm\">\n @for (step of setup()!.steps; track step.id) {\n <button\n type=\"button\"\n class=\"wizard-page__step flex w-full cursor-pointer items-start gap-3 rounded-md border-none bg-transparent p-3 text-left hover:bg-zinc-50\"\n [class.wizard-page__step--active]=\"activeStep() === step.id\"\n [class.wizard-page__step--done]=\"step.complete\"\n (click)=\"selectStep(step)\"\n >\n <span class=\"wizard-page__step-num flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-zinc-100 text-xs font-semibold\">\n @if (step.complete) {\n <ed-icon name=\"check\" [size]=\"16\" />\n } @else {\n {{ step.id }}\n }\n </span>\n <div class=\"flex flex-col gap-1\">\n <span class=\"fs-sm font-semibold text-dark\">{{ step.title }}</span>\n <span class=\"fs-sm text-light\">{{ step.description }}</span>\n </div>\n </button>\n }\n </nav>\n\n <article class=\"rounded-lg border border-base bg-white p-5 shadow-sm\">\n @for (step of setup()!.steps; track step.id) {\n @if (activeStep() === step.id) {\n <header class=\"mb-3 flex items-center justify-between gap-3\">\n <h2>Step {{ step.id }}: {{ step.title }}</h2>\n <ed-badge-2 [attr.variant]=\"step.complete ? 'success' : 'warning'\">\n {{ step.complete ? 'Complete' : 'Incomplete' }}\n </ed-badge-2>\n </header>\n <p class=\"fs-base text-dark\">{{ step.description }}</p>\n }\n }\n\n <section class=\"mt-6 border-t border-zinc-200 pt-5\">\n <h3>Test transcript preview</h3>\n <div class=\"mt-3 flex flex-col gap-3\">\n @for (line of setup()!.testTranscript; track $index) {\n <div class=\"wizard-page__line rounded-md bg-zinc-50 px-3 py-3\" [attr.data-who]=\"line.who\">\n <span class=\"fs-sm font-semibold text-light\">{{ line.who }}</span>\n <p class=\"m-0 mt-1 text-sm\">{{ line.text }}</p>\n </div>\n }\n </div>\n </section>\n\n <footer class=\"mt-6 flex items-center justify-between border-t border-zinc-200 pt-4\">\n <p class=\"fs-sm text-light\">\n {{ completedCount() }} of {{ setup()!.steps.length }} steps complete\n </p>\n @if (activated()) {\n <ed-badge-2 variant=\"success\">Agent activated</ed-badge-2>\n } @else {\n <ed-button variant=\"primary\" fill size=\"sm\" (click$)=\"activate()\">\n <ed-icon slot=\"prefix\" name=\"rocket_launch\" [size]=\"16\" /> Activate AI receptionist\n </ed-button>\n }\n </footer>\n </article>\n </div>\n }\n</div>\n"],"names":[],"mappings":";;;;MAiBa,mBAAmB,CAAA;AARhC,IAAA,WAAA,GAAA;AASmB,QAAA,IAAA,CAAA,GAAG,GAAG,MAAM,CAAC,wBAAwB,CAAC;AAEpC,QAAA,IAAA,CAAA,KAAK,GAAG,MAAM,CAAmB,IAAI,CAAC;AACtC,QAAA,IAAA,CAAA,UAAU,GAAG,MAAM,CAAC,CAAC,CAAC;AACtB,QAAA,IAAA,CAAA,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC;AACtB,QAAA,IAAA,CAAA,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC;AACzB,QAAA,IAAA,CAAA,gBAAgB,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAU;QAC3C,IAAA,CAAA,sBAAsB,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAU;AAE3C,QAAA,IAAA,CAAA,cAAc,GAAG,QAAQ,CAAC,MAAK;YAChD,OAAO,IAAI,CAAC,KAAK,EAAE,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,IAAI,CAAC;AAClE,QAAA,CAAC,CAAC;AAyBH,IAAA;IAvBC,QAAQ,GAAA;AACN,QAAA,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,KAAI;AACzC,YAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;AACpB,YAAA,MAAM,eAAe,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC;YAC3D,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,eAAe,EAAE,EAAE,IAAI,CAAC,CAAC;AAC7C,YAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;AACzB,QAAA,CAAC,CAAC;IACJ;AAEU,IAAA,UAAU,CAAC,IAAe,EAAA;QAClC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;IAC9B;IAEU,eAAe,GAAA;QACvB,OAAO,IAAI,CAAC,KAAK,EAAE,EAAE,SAAS,IAAI,CAAC;IACrC;IAEU,QAAQ,GAAA;QAChB,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC,SAAS,CAAC,MAAK;AACtC,YAAA,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC;AACzB,YAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;AAC1B,QAAA,CAAC,CAAC;IACJ;+GApCW,mBAAmB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;AAAnB,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,mBAAmB,2ECjBhC,8uKAmHA,EAAA,MAAA,EAAA,CAAA,gbAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EDxGc,aAAa,EAAA,QAAA,EAAA,SAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,MAAA,EAAA,OAAA,EAAA,UAAA,EAAA,YAAA,EAAA,YAAA,EAAA,WAAA,EAAA,OAAA,EAAA,MAAA,EAAA,WAAA,EAAA,UAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,iBAAiB,2QAAE,mBAAmB,EAAA,QAAA,EAAA,aAAA,EAAA,MAAA,EAAA,CAAA,OAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA,CAAA;;4FAMtD,mBAAmB,EAAA,UAAA,EAAA,CAAA;kBAR/B,SAAS;AACI,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,iBAAiB,EAAA,OAAA,EAClB,CAAC,aAAa,EAAE,iBAAiB,EAAE,mBAAmB,CAAC,EAAA,eAAA,EAG/C,uBAAuB,CAAC,MAAM,EAAA,OAAA,EACtC,CAAC,sBAAsB,CAAC,EAAA,QAAA,EAAA,8uKAAA,EAAA,MAAA,EAAA,CAAA,gbAAA,CAAA,EAAA;;;;;"}
@@ -1,2 +1,2 @@
1
- export { E as EdAvatarComponent, I as EdIconComponent, v as EdsAppShellComponent, w as EdsBadgeComponent, x as EdsButtonComponent, y as EdsRouteProgressComponent, I as IconComponent, z as ToastContainerComponent, T as ToastService, V as VOICE_RECEPTIONIST_CONFIG, B as VOICE_RECEPTIONIST_FEATURE_ROUTES, C as VOICE_RECEPTIONIST_ROUTES, F as VOICE_RECEPTIONIST_SESSION, G as provideVoiceReceptionist } from './edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-Cbn5DmQI.mjs';
1
+ export { E as EdAvatarComponent, I as EdIconComponent, w as EdsAppShellComponent, x as EdsBadgeComponent, y as EdsButtonComponent, z as EdsRouteProgressComponent, I as IconComponent, B as ToastContainerComponent, T as ToastService, V as VOICE_RECEPTIONIST_CONFIG, C as VOICE_RECEPTIONIST_FEATURE_ROUTES, F as VOICE_RECEPTIONIST_ROUTES, G as VOICE_RECEPTIONIST_SESSION, H as provideVoiceReceptionist } from './edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-DDS7VdnD.mjs';
2
2
  //# sourceMappingURL=edvak99-voice-receptionist-widget.mjs.map
@@ -5,6 +5,23 @@ export type CallControlMode = 'ai' | 'takeover' | 'listen' | 'paused';
5
5
  export type Sentiment = 'calm' | 'neutral' | 'frustrated' | 'urgent';
6
6
  export type ToolState = 'ok' | 'warn' | 'error' | 'active';
7
7
  export type TranscriptWho = 'ai' | 'patient' | 'staff' | 'system';
8
+ /** Shared Call History / Analytics list filters (HTTP: search, direction, …). */
9
+ export interface CallListFilters {
10
+ q?: string;
11
+ dir?: string;
12
+ outcome?: string;
13
+ location?: string;
14
+ review?: 'needs' | 'reviewed';
15
+ }
16
+ export interface AnalyticsQuery extends CallListFilters {
17
+ range?: string;
18
+ startDate?: string;
19
+ endDate?: string;
20
+ }
21
+ export interface CsvExportResult {
22
+ blob: Blob;
23
+ filename: string;
24
+ }
8
25
  export interface TranscriptLine {
9
26
  who: TranscriptWho;
10
27
  text: string;
@@ -40,9 +40,13 @@ interface VolumePointVm {
40
40
  }
41
41
  export declare class AnalyticsPageComponent implements OnInit {
42
42
  private readonly api;
43
+ private readonly toast;
43
44
  protected readonly data: import("@angular/core").WritableSignal<AnalyticsData | null>;
44
45
  protected readonly range: import("@angular/core").WritableSignal<string>;
46
+ protected readonly startDate: import("@angular/core").WritableSignal<string>;
47
+ protected readonly endDate: import("@angular/core").WritableSignal<string>;
45
48
  protected readonly loading: import("@angular/core").WritableSignal<boolean>;
49
+ protected readonly exporting: import("@angular/core").WritableSignal<boolean>;
46
50
  protected readonly kpiSkeletonRows: readonly [0, 1, 2, 3];
47
51
  protected readonly legendSkeletonRows: readonly [0, 1, 2];
48
52
  protected readonly chartRowSkeletonRows: readonly [0, 1, 2, 3, 4];
@@ -50,10 +54,16 @@ export declare class AnalyticsPageComponent implements OnInit {
50
54
  protected readonly chartsReady: import("@angular/core").WritableSignal<boolean>;
51
55
  protected readonly hoveredVolume: import("@angular/core").WritableSignal<number | null>;
52
56
  protected readonly filtersOpen: import("@angular/core").WritableSignal<boolean>;
53
- protected readonly ranges: {
54
- id: string;
55
- label: string;
56
- }[];
57
+ protected readonly ranges: readonly [{
58
+ readonly id: "7d";
59
+ readonly label: "7 days";
60
+ }, {
61
+ readonly id: "30d";
62
+ readonly label: "30 days";
63
+ }, {
64
+ readonly id: "90d";
65
+ readonly label: "90 days";
66
+ }];
57
67
  protected readonly impactKpi: import("@angular/core").Signal<AnalyticsKpiCard | null>;
58
68
  protected readonly resolutionKpi: import("@angular/core").Signal<AnalyticsKpiCard | null>;
59
69
  protected readonly impactSubPrimary: import("@angular/core").Signal<string>;
@@ -80,8 +90,15 @@ export declare class AnalyticsPageComponent implements OnInit {
80
90
  protected readonly periodLabel: import("@angular/core").Signal<string>;
81
91
  protected readonly volumeAxisLabels: import("@angular/core").Signal<string[]>;
82
92
  ngOnInit(): void;
83
- protected toggleFilters(): void;
93
+ protected toggleFilters(event?: Event): void;
94
+ protected closeFilters(): void;
95
+ protected onFiltersDocClick(event: MouseEvent): void;
84
96
  protected setRange(id: string): void;
97
+ protected onStartDate(value: string): void;
98
+ protected onEndDate(value: string): void;
99
+ protected applyFilters(): void;
100
+ protected resetFilters(): void;
101
+ protected exportCsv(): void;
85
102
  protected onVolumeEnter(index: number): void;
86
103
  protected onVolumeLeave(): void;
87
104
  private buildVolumePath;
@@ -97,6 +114,9 @@ export declare class AnalyticsPageComponent implements OnInit {
97
114
  private formatPeriodRange;
98
115
  private parseIsoDate;
99
116
  private findKpi;
117
+ private activeFilters;
118
+ private applyPresetDates;
119
+ private toIsoDate;
100
120
  private load;
101
121
  static ɵfac: i0.ɵɵFactoryDeclaration<AnalyticsPageComponent, never>;
102
122
  static ɵcmp: i0.ɵɵComponentDeclaration<AnalyticsPageComponent, "eds-analytics-page", never, {}, {}, never, never, true, never>;
@@ -44,6 +44,7 @@ export declare class CallHistoryPageComponent implements OnInit {
44
44
  protected readonly location: import("@angular/core").WritableSignal<string>;
45
45
  protected readonly reviewTab: import("@angular/core").WritableSignal<ReviewFilterTab>;
46
46
  protected readonly filtersOpen: import("@angular/core").WritableSignal<boolean>;
47
+ protected readonly exporting: import("@angular/core").WritableSignal<boolean>;
47
48
  protected toggleFilters(event?: Event): void;
48
49
  protected closeFilters(): void;
49
50
  protected onFiltersDocClick(event: MouseEvent): void;
@@ -1,5 +1,5 @@
1
1
  import { Observable } from 'rxjs';
2
- import { AgentSettings, AiReceptionistStatus, AnalyticsData, AuditEvent, DashboardData, CallRecordingMeta, HistoryCall, HistoryDetail, LiveCall, LocationOption, ProviderOption, SetupData, TaskItem, CreateTaskRequest, TaskFilters, RegenerateSummaryResult, ToolEvent, TranscriptLine } from '../models/ai-receptionist.types';
2
+ import { AgentSettings, AiReceptionistStatus, AnalyticsData, AnalyticsQuery, AuditEvent, CallListFilters, CsvExportResult, DashboardData, CallRecordingMeta, HistoryCall, HistoryDetail, LiveCall, LocationOption, ProviderOption, SetupData, TaskItem, CreateTaskRequest, TaskFilters, RegenerateSummaryResult, ToolEvent, TranscriptLine } from '../models/ai-receptionist.types';
3
3
  import { StaffMediaJoinResult, StaffMediaMode } from '../models/staff-media.types';
4
4
  import { type PaginatedResult } from '../models/pagination';
5
5
  import { ApiLogDetail, ApiLogFilters, ApiLogListResponse, ApiLogStats } from '../models/api-log.types';
@@ -41,12 +41,7 @@ export declare class AiReceptionistApiMockService {
41
41
  }>;
42
42
  getCallRecording(callId: string): Observable<CallRecordingMeta>;
43
43
  getCallRecordingBlob(): Observable<Blob>;
44
- getHistory(filters?: {
45
- q?: string;
46
- dir?: string;
47
- outcome?: string;
48
- location?: string;
49
- review?: 'needs' | 'reviewed';
44
+ getHistory(filters?: CallListFilters & {
50
45
  page?: number;
51
46
  limit?: number;
52
47
  }): Observable<PaginatedResult<HistoryCall>>;
@@ -119,9 +114,11 @@ export declare class AiReceptionistApiMockService {
119
114
  patchTask(id: string, status: TaskItem['status']): Observable<{
120
115
  data: TaskItem | null;
121
116
  }>;
122
- getAnalytics(range: string): Observable<{
117
+ getAnalytics(query: string | AnalyticsQuery): Observable<{
123
118
  data: AnalyticsData;
124
119
  }>;
120
+ exportHistoryCsv(filters?: CallListFilters): Observable<CsvExportResult>;
121
+ exportAnalyticsCsv(filters?: AnalyticsQuery): Observable<CsvExportResult>;
125
122
  getSettings(): Observable<{
126
123
  data: AgentSettings;
127
124
  }>;
@@ -3,7 +3,7 @@ import { ApiLogDetail, ApiLogFilters, ApiLogListResponse, ApiLogStats } from '..
3
3
  import { CreateOutboundPurposeRequest, OutboundPurpose, OutboundPurposesResponse, PlaceOutboundCallRequest, PlaceOutboundCallResponse, UpdateOutboundPurposeRequest } from '../models/outbound-purpose.types';
4
4
  import { type OutboundAppointmentHit, type OutboundPatientHit } from '../models/outbound-patient.types';
5
5
  import { type StaffMediaJoinResult, type StaffMediaMode } from '../models/staff-media.types';
6
- import { AgentSettings, AiReceptionistStatus, AnalyticsData, AuditEvent, DashboardData, HistoryCall, HistoryDetail, LiveCall, RegenerateSummaryResult, LocationOption, ProviderOption, SetupData, TaskItem, CreateTaskRequest, TaskFilters, ToolEvent, TranscriptLine, CallRecordingMeta } from '../models/ai-receptionist.types';
6
+ import { AgentSettings, AiReceptionistStatus, AnalyticsData, AnalyticsQuery, AuditEvent, CallListFilters, CsvExportResult, DashboardData, HistoryCall, HistoryDetail, LiveCall, RegenerateSummaryResult, LocationOption, ProviderOption, SetupData, TaskItem, CreateTaskRequest, TaskFilters, ToolEvent, TranscriptLine, CallRecordingMeta } from '../models/ai-receptionist.types';
7
7
  import { type AgentActivity, type AgentActivityFilters } from '../models/agent-activity.types';
8
8
  import { type PaginatedResult } from '../models/pagination';
9
9
  import * as i0 from "@angular/core";
@@ -45,12 +45,7 @@ export declare class AiReceptionistApiService {
45
45
  getCallRecording(callId: string): Observable<CallRecordingMeta>;
46
46
  /** Fetch audio bytes with JWT (interceptor). Pass relative path from metadata.url. */
47
47
  getCallRecordingBlob(audioPath: string): Observable<Blob>;
48
- getHistory(filters?: {
49
- q?: string;
50
- dir?: string;
51
- outcome?: string;
52
- location?: string;
53
- review?: 'needs' | 'reviewed';
48
+ getHistory(filters?: CallListFilters & {
54
49
  page?: number;
55
50
  limit?: number;
56
51
  }): Observable<PaginatedResult<HistoryCall>>;
@@ -129,9 +124,13 @@ export declare class AiReceptionistApiService {
129
124
  patchTask(id: string, status: TaskItem['status']): Observable<{
130
125
  data: TaskItem | null;
131
126
  }>;
132
- getAnalytics(range: string): Observable<{
127
+ getAnalytics(query: string | AnalyticsQuery): Observable<{
133
128
  data: AnalyticsData;
134
129
  }>;
130
+ /** GET /calls/history/export — same filters as getHistory, no pagination. */
131
+ exportHistoryCsv(filters?: CallListFilters): Observable<CsvExportResult>;
132
+ /** GET /analytics/export — same filters as getAnalytics including range. */
133
+ exportAnalyticsCsv(filters?: AnalyticsQuery): Observable<CsvExportResult>;
135
134
  getSettings(): Observable<{
136
135
  data: AgentSettings;
137
136
  }>;
@@ -212,6 +211,9 @@ export declare class AiReceptionistApiService {
212
211
  private mapPatientHits;
213
212
  private mapAppointmentHits;
214
213
  private postCallAction;
214
+ private analyticsParams;
215
+ private callListParams;
216
+ private getCsvExport;
215
217
  private apiErrorMessage;
216
218
  static ɵfac: i0.ɵɵFactoryDeclaration<AiReceptionistApiService, never>;
217
219
  static ɵprov: i0.ɵɵInjectableDeclaration<AiReceptionistApiService>;
@@ -0,0 +1,2 @@
1
+ export declare function filenameFromContentDisposition(header: string | null | undefined, fallback: string): string;
2
+ export declare function triggerBlobDownload(blob: Blob, filename: string): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@edvak99/voice-receptionist-widget",
3
- "version": "1.1.19",
3
+ "version": "1.1.21",
4
4
  "description": "Edvak AI Receptionist — embeddable Angular routes and UI for EHR hosts",
5
5
  "peerDependencies": {
6
6
  "@angular/common": "^19.2.0",
package/styles/embed.scss CHANGED
@@ -273,7 +273,8 @@ eds-live-monitor-page {
273
273
 
274
274
  .live-monitor-page {
275
275
  height: auto;
276
- overflow: visible;
276
+ min-height: calc(100vh - var(--eds-topbar-height, 0px));
277
+ overflow: hidden;
277
278
  }
278
279
 
279
280
  .live-monitor-page__grid {
@@ -295,3 +296,30 @@ eds-live-monitor-page {
295
296
  margin-left: 0;
296
297
  }
297
298
  }
299
+
300
+ /* Sticky list headers: `border-collapse` + padded overflow let tbody paint
301
+ through / above thead (rows overlap the page title and column labels). */
302
+ .eds-table-scroll {
303
+ overflow: auto;
304
+ min-height: 0;
305
+ min-width: 0;
306
+ }
307
+
308
+ .eds-sticky-table {
309
+ border-collapse: separate !important;
310
+ border-spacing: 0;
311
+ }
312
+
313
+ .eds-sticky-table > thead {
314
+ position: sticky;
315
+ top: 0;
316
+ z-index: 5;
317
+ }
318
+
319
+ .eds-sticky-table > thead > tr > th {
320
+ position: sticky;
321
+ top: 0;
322
+ z-index: 5;
323
+ background-color: #f4f4f5 !important;
324
+ box-shadow: inset 0 -1px 0 #d9d9de;
325
+ }