@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.
- package/fesm2022/edvak99-voice-receptionist-widget-activities-page.component-CpXa1J9-.mjs +510 -0
- package/fesm2022/edvak99-voice-receptionist-widget-activities-page.component-CpXa1J9-.mjs.map +1 -0
- package/fesm2022/edvak99-voice-receptionist-widget-analytics-page.component-CmImX5FN.mjs +435 -0
- package/fesm2022/edvak99-voice-receptionist-widget-analytics-page.component-CmImX5FN.mjs.map +1 -0
- package/fesm2022/edvak99-voice-receptionist-widget-audit-page.component-DTAB2WTX.mjs +78 -0
- package/fesm2022/edvak99-voice-receptionist-widget-audit-page.component-DTAB2WTX.mjs.map +1 -0
- 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
- 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
- package/fesm2022/edvak99-voice-receptionist-widget-call-history-page.component-BACON4uq.mjs +247 -0
- package/fesm2022/edvak99-voice-receptionist-widget-call-history-page.component-BACON4uq.mjs.map +1 -0
- 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
- 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
- package/fesm2022/{edvak99-voice-receptionist-widget-call-review.service-C5BQdHNZ.mjs → edvak99-voice-receptionist-widget-call-review.service-BhbCmB1S.mjs} +2 -2
- package/fesm2022/{edvak99-voice-receptionist-widget-call-review.service-C5BQdHNZ.mjs.map → edvak99-voice-receptionist-widget-call-review.service-BhbCmB1S.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-dashboard-page.component-CE2Zh0eJ.mjs → edvak99-voice-receptionist-widget-dashboard-page.component-CxNYLBbg.mjs} +2 -2
- package/fesm2022/{edvak99-voice-receptionist-widget-dashboard-page.component-CE2Zh0eJ.mjs.map → edvak99-voice-receptionist-widget-dashboard-page.component-CxNYLBbg.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-Cbn5DmQI.mjs → edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-DDS7VdnD.mjs} +153 -28
- package/fesm2022/edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-DDS7VdnD.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-live-calls-page.component-OYQuPU33.mjs → edvak99-voice-receptionist-widget-live-calls-page.component-4LtgT4lS.mjs} +2 -2
- 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
- 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
- package/fesm2022/edvak99-voice-receptionist-widget-live-monitor-page.component-B1lKfw-j.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-outbound-purposes-page.component-C8wLTIF0.mjs → edvak99-voice-receptionist-widget-outbound-purposes-page.component-BkIHblSu.mjs} +4 -4
- package/fesm2022/edvak99-voice-receptionist-widget-outbound-purposes-page.component-BkIHblSu.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-task-detail-drawer.component-CDaYKu5_.mjs → edvak99-voice-receptionist-widget-task-detail-drawer.component-aDTKTV79.mjs} +2 -2
- 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
- package/fesm2022/edvak99-voice-receptionist-widget-tasks-page.component-Dj1nWx6V.mjs +150 -0
- package/fesm2022/edvak99-voice-receptionist-widget-tasks-page.component-Dj1nWx6V.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-wizard-page.component-BtfZJm3V.mjs → edvak99-voice-receptionist-widget-wizard-page.component-CQttbEzW.mjs} +2 -2
- package/fesm2022/{edvak99-voice-receptionist-widget-wizard-page.component-BtfZJm3V.mjs.map → edvak99-voice-receptionist-widget-wizard-page.component-CQttbEzW.mjs.map} +1 -1
- package/fesm2022/edvak99-voice-receptionist-widget.mjs +1 -1
- package/lib/models/ai-receptionist.types.d.ts +17 -0
- package/lib/pages/analytics-page/analytics-page.component.d.ts +25 -5
- package/lib/pages/call-history-page/call-history-page.component.d.ts +1 -0
- package/lib/services/ai-receptionist-api.mock.d.ts +5 -8
- package/lib/services/ai-receptionist-api.service.d.ts +10 -8
- package/lib/utils/csv-download.util.d.ts +2 -0
- package/package.json +1 -1
- package/styles/embed.scss +29 -1
- package/fesm2022/edvak99-voice-receptionist-widget-activities-page.component-D3FI89cY.mjs +0 -510
- package/fesm2022/edvak99-voice-receptionist-widget-activities-page.component-D3FI89cY.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-analytics-page.component-DjmJ2eUU.mjs +0 -363
- package/fesm2022/edvak99-voice-receptionist-widget-analytics-page.component-DjmJ2eUU.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-audit-page.component-DY_zyJli.mjs +0 -78
- package/fesm2022/edvak99-voice-receptionist-widget-audit-page.component-DY_zyJli.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-call-history-page.component-BftVST1n.mjs +0 -259
- package/fesm2022/edvak99-voice-receptionist-widget-call-history-page.component-BftVST1n.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-Cbn5DmQI.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-live-monitor-page.component-jHHs_DbW.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-outbound-purposes-page.component-C8wLTIF0.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-tasks-page.component-C0TaBp8P.mjs +0 -150
- package/fesm2022/edvak99-voice-receptionist-widget-tasks-page.component-C0TaBp8P.mjs.map +0 -1
package/fesm2022/edvak99-voice-receptionist-widget-call-history-page.component-BACON4uq.mjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edvak99-voice-receptionist-widget-call-history-page.component-BACON4uq.mjs","sources":["../../../src/lib/pages/call-history-page/call-history-page.component.ts","../../../src/lib/pages/call-history-page/call-history-page.component.html"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n computed,\n CUSTOM_ELEMENTS_SCHEMA,\n inject,\n OnInit,\n signal,\n} from '@angular/core';\nimport { ActivatedRoute, Router } from '@angular/router';\nimport { FormsModule } from '@angular/forms';\n\nimport { HistoryCall } from '../../models/ai-receptionist.types';\nimport { DEFAULT_PAGE_SIZE, totalPages as calcTotalPages } from '../../models/pagination';\nimport { AiReceptionistApiService } from '../../services/ai-receptionist-api.service';\nimport { CallReviewService } from '../../services/call-review.service';\nimport {\n callerMetaLine,\n historyResolution,\n historyResolutionLabel,\n historyResultChips,\n resultChipIcon,\n} from '../../utils/call-history-display.util';\nimport { isNeedsReview, ReviewFilterTab } from '../../utils/call-review.util';\nimport { EdButtonComponent } from '../../ui/ed-button.component';\nimport { EdSkeletonComponent } from '../../ui/ed-skeleton.component';\n\nimport { SmartTooltipDirective } from '../../shared/smart-tooltip.directive';\nimport { TABLE_SKELETON_ROWS } from '../../shared/table-skeleton.constants';\nimport { ToastService } from '../../shared/toast.service';\nimport { triggerBlobDownload } from '../../utils/csv-download.util';\nimport { EdAvatarComponent } from '../../ui/ed-avatar.component';\nimport { IconComponent } from '../../ui/ed-icon.component';\nimport { EdIconButtonComponent } from '../../ui/ed-icon-button.component';\nimport { EdsSearchFieldComponent } from '../../ui/eds-search-field.component';\n\ninterface HistoryRowVm {\n id: string;\n name: string;\n initials: string;\n avatarTone: 'gray' | 'brand';\n metaLine: string;\n timeLabel: string;\n dateLabel: string;\n direction: 'inbound' | 'outbound';\n directionIcon: string;\n directionTitle: string;\n goals: string[];\n handledLabel: string;\n handledVariant: 'opened' | 'primary';\n resolutionLabel: string;\n resolutionVariant: 'success' | 'warning';\n resultChips: { label: string; icon: string }[];\n durationLabel: string;\n needsReview: boolean;\n}\n\n@Component({\n selector: 'eds-call-history-page',\n imports: [\n FormsModule,\n EdAvatarComponent,\n IconComponent,\n EdIconButtonComponent,\n EdButtonComponent,\n EdsSearchFieldComponent,\n SmartTooltipDirective,\n EdSkeletonComponent,\n ],\n templateUrl: './call-history-page.component.html',\n styleUrl: './call-history-page.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n schemas: [CUSTOM_ELEMENTS_SCHEMA],\n host: { class: 'block h-full min-h-0' },\n})\nexport class CallHistoryPageComponent implements OnInit {\n private readonly api = inject(AiReceptionistApiService);\n private readonly reviewService = inject(CallReviewService);\n private readonly toast = inject(ToastService);\n private readonly route = inject(ActivatedRoute);\n private readonly router = inject(Router);\n\n protected readonly pageSize = DEFAULT_PAGE_SIZE;\n protected readonly rows = signal<HistoryCall[]>([]);\n protected readonly total = signal(0);\n protected readonly page = signal(1);\n protected readonly loading = signal(true);\n protected readonly skeletonRows = TABLE_SKELETON_ROWS;\n protected readonly reviewingId = signal<string | null>(null);\n protected readonly search = signal('');\n protected readonly direction = signal('');\n protected readonly outcome = signal('');\n protected readonly location = signal('');\n protected readonly reviewTab = signal<ReviewFilterTab>('all');\n protected readonly filtersOpen = signal(false);\n protected readonly exporting = signal(false);\n\n protected toggleFilters(event?: Event): void {\n event?.stopPropagation();\n this.filtersOpen.update((open) => !open);\n }\n\n protected closeFilters(): void {\n this.filtersOpen.set(false);\n }\n\n protected onFiltersDocClick(event: MouseEvent): void {\n const target = event.target as HTMLElement | null;\n if (!target?.closest('[data-history-filters]')) {\n this.filtersOpen.set(false);\n }\n }\n\n protected readonly reviewTabs: { id: ReviewFilterTab; label: string }[] = [\n { id: 'all', label: 'All' },\n { id: 'needs', label: 'Needs review' },\n { id: 'reviewed', label: 'Reviewed' },\n ];\n\n protected readonly totalPages = computed(() => calcTotalPages(this.total(), DEFAULT_PAGE_SIZE));\n\n protected readonly tableRows = computed(() => this.rows().map((row) => this.toRow(row)));\n\n ngOnInit(): void {\n const reviewParam = this.route.snapshot.queryParamMap.get('review');\n if (reviewParam === 'needs' || reviewParam === 'reviewed') {\n this.reviewTab.set(reviewParam);\n }\n this.load();\n }\n\n protected load(): void {\n this.loading.set(true);\n const tab = this.reviewTab();\n this.api\n .getHistory({\n q: this.search() || undefined,\n dir: this.direction() || undefined,\n outcome: this.outcome() || undefined,\n location: this.location() || undefined,\n review: tab === 'all' ? undefined : tab,\n page: this.page(),\n limit: DEFAULT_PAGE_SIZE,\n })\n .subscribe({\n next: ({ items, total, page }) => {\n this.rows.set(items);\n this.total.set(total);\n this.page.set(page);\n this.loading.set(false);\n },\n error: () => this.loading.set(false),\n });\n }\n\n protected applyFilters(): void {\n this.page.set(1);\n this.load();\n }\n\n protected setReviewTab(tab: ReviewFilterTab): void {\n this.reviewTab.set(tab);\n this.page.set(1);\n void this.router.navigate([], {\n relativeTo: this.route,\n queryParams: tab === 'all' ? { review: null } : { review: tab },\n queryParamsHandling: 'merge',\n replaceUrl: true,\n });\n this.load();\n }\n\n protected tabBadgeCount(tab: ReviewFilterTab): number | null {\n if (tab !== 'needs' || this.reviewTab() !== 'needs') return null;\n const count = this.total();\n return count > 0 ? count : null;\n }\n\n protected prevPage(): void {\n if (this.page() <= 1) return;\n this.page.update((p) => p - 1);\n this.load();\n }\n\n protected nextPage(): void {\n if (this.page() >= this.totalPages()) return;\n this.page.update((p) => p + 1);\n this.load();\n }\n\n protected markReviewed(row: HistoryCall, event: Event): void {\n event.preventDefault();\n event.stopPropagation();\n if (!isNeedsReview(row.review) || this.reviewingId()) return;\n\n this.reviewingId.set(row.id);\n this.rows.update((list) =>\n list.map((r) => (r.id === row.id ? { ...r, review: 'reviewed' as const } : r)),\n );\n\n this.reviewService.markReviewed(row.id).subscribe({\n next: () => {\n this.reviewingId.set(null);\n this.toast.show('Call marked as reviewed', 'success');\n if (this.reviewTab() === 'needs') this.load();\n },\n error: () => {\n this.reviewingId.set(null);\n this.rows.update((list) =>\n list.map((r) => (r.id === row.id ? { ...r, review: 'needs' as const } : r)),\n );\n this.toast.show('Failed to mark call as reviewed', 'error');\n },\n });\n }\n\n protected openCallDetail(id: string): void {\n void this.router.navigate(['../history', id], { relativeTo: this.route });\n }\n\n protected exportCsv(): void {\n if (this.exporting()) return;\n this.exporting.set(true);\n const tab = this.reviewTab();\n this.api\n .exportHistoryCsv({\n q: this.search() || undefined,\n dir: this.direction() || undefined,\n outcome: this.outcome() || undefined,\n location: this.location() || undefined,\n review: tab === 'all' ? undefined : tab,\n })\n .subscribe({\n next: ({ blob, filename }) => {\n triggerBlobDownload(blob, filename);\n this.exporting.set(false);\n this.toast.show('Export downloaded', 'success');\n },\n error: (err: { message?: string }) => {\n this.exporting.set(false);\n this.toast.show(err.message ?? 'Failed to export CSV', 'error');\n },\n });\n }\n\n private toRow(row: HistoryCall): HistoryRowVm {\n const resolution = historyResolution({\n outcome: row.outcome,\n resolution: row.resolution,\n risk: row.risk,\n });\n const handledByStaff = row.handledBy === 'staff';\n\n return {\n id: row.id,\n name: row.name?.trim() || 'Unknown Caller',\n initials: row.initials || '?',\n avatarTone: this.avatarTone(row),\n metaLine: callerMetaLine({\n dob: row.dob,\n age: row.age,\n gender: row.gender,\n phone: row.phone,\n name: row.name,\n }),\n timeLabel: row.started ? this.formatTime(row.started) : row.whenLabel || '—',\n dateLabel: row.started ? this.formatDate(row.started) : '',\n direction: row.direction,\n directionIcon: row.direction === 'inbound' ? 'call_received' : 'call_made',\n directionTitle: row.direction === 'inbound' ? 'Incoming call' : 'Outgoing call',\n goals: this.goalLines(row.reason),\n handledLabel: handledByStaff ? 'STAFF' : 'AI',\n handledVariant: handledByStaff ? 'primary' : 'opened',\n resolutionLabel: historyResolutionLabel(resolution),\n resolutionVariant: resolution === 'resolved' ? 'success' : 'warning',\n resultChips: historyResultChips(row.results, row.outcome).map((label) => ({\n label,\n icon: resultChipIcon(label),\n })),\n durationLabel: row.durationLabel ?? this.formatDuration(row.duration),\n needsReview: isNeedsReview(row.review),\n };\n }\n\n private goalLines(reason: string | undefined): string[] {\n const raw = String(reason ?? '').trim();\n if (!raw) return [];\n return raw\n .split(/[\\n;|/]+/)\n .map((part) => part.trim())\n .filter(Boolean);\n }\n\n private avatarTone(row: HistoryCall): 'gray' | 'brand' {\n if (!row.name?.trim() || /^unknown/i.test(row.name) || row.initials === '?') return 'gray';\n return 'brand';\n }\n\n private formatTime(ts: number): string {\n return new Date(ts).toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' });\n }\n\n private formatDate(ts: number): string {\n return new Date(ts).toLocaleDateString([], { month: 'short', day: 'numeric', year: 'numeric' });\n }\n\n private 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","<div class=\"call-history-page flex min-h-0 flex-col overflow-hidden bg-lighter p-base\">\n <header class=\"relative z-10 mb-md flex shrink-0 items-start justify-between gap-base bg-lighter\">\n <div class=\"grid gap-2xs\">\n <h4>Call History</h4>\n <p class=\"fs-sm text-light\">\n Review past conversations and understand what happened during each call\n </p>\n </div>\n <div class=\"flex shrink-0 items-center gap-base\">\n <div class=\"relative w-60\">\n <eds-search-field\n inputClass=\"form-input w-full\"\n placeholder=\"Search here\"\n ariaLabel=\"Search call history\"\n [value]=\"search()\"\n (valueChange)=\"search.set($event)\"\n (enter)=\"applyFilters()\"\n />\n <span class=\"pointer-events-none absolute inset-y-0 right-3 inline-flex items-center text-lighter\">\n <ed-icon name=\"search\" [size]=\"20\" color=\"currentColor\" />\n </span>\n </div>\n <div\n class=\"relative\"\n data-history-filters\n (document:click)=\"onFiltersDocClick($event)\"\n >\n <ed-icon-button\n name=\"filter_alt\"\n label=\"Filters\"\n size=\"md\"\n outline\n allowBubble\n [pressed]=\"filtersOpen()\"\n toggle\n (click$)=\"toggleFilters($event)\"\n />\n @if (filtersOpen()) {\n <div\n class=\"absolute right-0 top-[calc(100%+4px)] z-20 w-80 rounded-md border border-light bg-white shadow-md\"\n role=\"dialog\"\n aria-label=\"Filter Options\"\n (click)=\"$event.stopPropagation()\"\n >\n <header class=\"flex items-center justify-between border-b border-light px-base py-sm\">\n <h5 class=\"m-0\">Filter Options</h5>\n <ed-icon-button\n name=\"close\"\n size=\"sm\"\n label=\"Close filters\"\n (click$)=\"closeFilters()\"\n />\n </header>\n <section class=\"grid gap-sm p-base\">\n <div class=\"grid gap-2xs\">\n <label class=\"fs-sm font-semibold text-light\" for=\"call-history-direction\">Direction</label>\n <select\n id=\"call-history-direction\"\n class=\"form-select is-sm\"\n [ngModel]=\"direction()\"\n (ngModelChange)=\"direction.set($event)\"\n autocomplete=\"off\"\n aria-label=\"Direction\"\n >\n <option value=\"\">All directions</option>\n <option value=\"inbound\">Inbound</option>\n <option value=\"outbound\">Outbound</option>\n </select>\n </div>\n <div class=\"grid gap-2xs\">\n <label class=\"fs-sm font-semibold text-light\">Outcome</label>\n <eds-search-field\n type=\"text\"\n inputClass=\"form-input is-sm\"\n placeholder=\"Outcome\"\n ariaLabel=\"Outcome\"\n [value]=\"outcome()\"\n (valueChange)=\"outcome.set($event)\"\n (enter)=\"applyFilters(); closeFilters()\"\n />\n </div>\n <div class=\"grid gap-2xs\">\n <label class=\"fs-sm font-semibold text-light\">Location</label>\n <eds-search-field\n type=\"text\"\n inputClass=\"form-input is-sm\"\n placeholder=\"Location\"\n ariaLabel=\"Location\"\n [value]=\"location()\"\n (valueChange)=\"location.set($event)\"\n (enter)=\"applyFilters(); closeFilters()\"\n />\n </div>\n </section>\n <footer class=\"flex flex-row-reverse flex-wrap items-center gap-sm border-t border-light px-base py-sm\">\n <ed-button\n variant=\"primary\"\n fill\n size=\"sm\"\n (click$)=\"applyFilters(); closeFilters()\"\n >\n Apply\n </ed-button>\n <ed-button\n variant=\"secondary\"\n outline\n size=\"sm\"\n [disabled]=\"exporting()\"\n (click$)=\"exportCsv()\"\n >\n <ed-icon slot=\"prefix\" name=\"download\" [size]=\"16\" />\n Export CSV\n </ed-button>\n </footer>\n </div>\n }\n </div>\n </div>\n </header>\n\n <div class=\"call-history-page__table eds-table-scroll min-h-0 min-w-0 flex-1 rounded-md bg-white\">\n <table class=\"table-default eds-sticky-table min-w-5xl w-full\" aria-label=\"Call history\">\n <thead>\n <tr>\n <th class=\"bg-light\">Time</th>\n <th class=\"bg-light\">Patient/Caller</th>\n <th class=\"bg-light text-center\">\n <span class=\"inline-flex items-center justify-center gap-2xs\">\n <ed-icon name=\"call_received\" [size]=\"12\" class=\"text-success\" color=\"currentColor\" />\n <span class=\"text-light\">/</span>\n <ed-icon name=\"call_made\" [size]=\"12\" class=\"text-primary\" color=\"currentColor\" />\n </span>\n </th>\n <th class=\"bg-light\">Goal</th>\n <th class=\"bg-light\">Handled By</th>\n <th class=\"bg-light\">Resolution</th>\n <th class=\"bg-light\">Result</th>\n <th class=\"bg-light\">Duration</th>\n </tr>\n </thead>\n @if (loading()) {\n <tbody aria-busy=\"true\">\n @for (_ of skeletonRows; track _) {\n <tr>\n <td>\n <div class=\"grid gap-2xs py-2xs\">\n <ed-skeleton class=\"h-3 w-16\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-20\"></ed-skeleton>\n </div>\n </td>\n <td>\n <div class=\"flex items-center gap-xs py-2xs\">\n <ed-skeleton class=\"h-8 w-8 !rounded-md\"></ed-skeleton>\n <div class=\"grid gap-2xs\">\n <ed-skeleton class=\"h-3 w-28\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-36\"></ed-skeleton>\n </div>\n </div>\n </td>\n <td class=\"text-center\">\n <div class=\"flex justify-center py-2xs\">\n <ed-skeleton class=\"h-5 w-5 !rounded\"></ed-skeleton>\n </div>\n </td>\n <td><ed-skeleton class=\"h-3 w-32\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-5 w-20 !rounded-full\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-5 w-24 !rounded-full\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-5 w-28 !rounded\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-3 w-12\"></ed-skeleton></td>\n </tr>\n }\n </tbody>\n } @else {\n <tbody>\n @for (row of tableRows(); track row.id; let i = $index) {\n <tr\n class=\"focus-visible:outline focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-primary\"\n role=\"button\"\n [attr.tabindex]=\"i === 0 ? 0 : -1\"\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=\"grid gap-2xs whitespace-nowrap\">\n <span class=\"fs-xs font-medium text-dark\">{{ row.timeLabel }}</span>\n <span class=\"fs-xs text-light\">{{ row.dateLabel }}</span>\n </div>\n </td>\n\n <td>\n <div class=\"flex min-w-52 items-center gap-xs\">\n <ed-avatar\n shape=\"box\"\n size=\"base\"\n [initials]=\"row.initials\"\n [tone]=\"row.avatarTone\"\n />\n <div class=\"grid min-w-0 gap-2xs\">\n <div class=\"flex min-w-0 items-center gap-2xs\">\n <span\n class=\"inline-block min-w-0 max-w-56 truncate fs-sm font-semibold text-dark\"\n [smartTooltip]=\"row.name\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ row.name }}</span>\n <!-- <span class=\"inline-flex shrink-0 text-light\">\n <ed-icon name=\"TagSimple\" [size]=\"14\" color=\"currentColor\" />\n </span> -->\n </div>\n <span\n class=\"inline-block min-w-0 max-w-64 truncate fs-xs text-light\"\n [smartTooltip]=\"row.metaLine\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ row.metaLine }}</span>\n </div>\n </div>\n </td>\n\n <td class=\"text-center\">\n <span\n class=\"inline-flex h-5 w-5 items-center justify-center rounded\"\n [class.bg-success-50]=\"row.direction === 'inbound'\"\n [class.text-success]=\"row.direction === 'inbound'\"\n [class.bg-primary-50]=\"row.direction === 'outbound'\"\n [class.text-primary]=\"row.direction === 'outbound'\"\n [smartTooltip]=\"row.directionTitle\"\n [attr.aria-label]=\"row.directionTitle\"\n >\n <ed-icon [name]=\"row.directionIcon\" [size]=\"12\" color=\"currentColor\" />\n </span>\n </td>\n\n <td>\n <div class=\"grid gap-2xs\">\n @for (goal of row.goals; track goal) {\n <span\n class=\"inline-block min-w-0 max-w-56 truncate fs-sm font-medium text-dark\"\n [smartTooltip]=\"goal\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ goal }}</span>\n } @empty {\n <span class=\"fs-sm text-light\">—</span>\n }\n </div>\n </td>\n\n <td>\n <ed-badge-2 [attr.variant]=\"row.handledVariant\" pill uppercase>\n {{ row.handledLabel }}\n </ed-badge-2>\n </td>\n\n <td>\n <ed-badge-2 [attr.variant]=\"row.resolutionVariant\" pill uppercase>\n {{ row.resolutionLabel }}\n </ed-badge-2>\n </td>\n\n <td>\n <div class=\"flex min-w-0 max-w-80 flex-wrap gap-2xs\">\n @for (chip of row.resultChips; track chip.label) {\n <span\n class=\"inline-flex h-5 max-w-48 min-w-0 items-center gap-2xs rounded bg-light px-2xs fs-xs font-medium text-dark\"\n >\n <ed-icon [name]=\"chip.icon\" [size]=\"12\" color=\"currentColor\" />\n <span\n class=\"min-w-0 truncate\"\n [smartTooltip]=\"chip.label\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ chip.label }}</span>\n </span>\n } @empty {\n <span class=\"fs-sm text-light\">—</span>\n }\n </div>\n </td>\n\n <td class=\"whitespace-nowrap tabular-nums fs-sm font-medium\">\n {{ row.durationLabel }}\n </td>\n </tr>\n } @empty {\n <tr class=\"empty-row\">\n <td colspan=\"8\" class=\"py-lg text-center fs-sm text-light\">\n No calls match this filter.\n </td>\n </tr>\n }\n </tbody>\n }\n </table>\n </div>\n\n <footer class=\"mt-base flex shrink-0 items-center justify-between border-t border-light pt-sm hidden\">\n <span class=\"fs-sm text-light\">\n Page {{ page() }} of {{ totalPages() }} · {{ total() }} total\n </span>\n <div class=\"flex gap-xs\">\n <ed-button\n variant=\"secondary\"\n outline\n size=\"sm\"\n [disabled]=\"page() <= 1\"\n (click$)=\"prevPage()\"\n >\n Previous\n </ed-button>\n <ed-button\n variant=\"secondary\"\n outline\n size=\"sm\"\n [disabled]=\"page() >= totalPages()\"\n (click$)=\"nextPage()\"\n >\n Next\n </ed-button>\n </div>\n </footer>\n</div>\n"],"names":["calcTotalPages"],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import * as i0 from '@angular/core';
|
|
|
2
2
|
import { input, output, viewChild, inject, DestroyRef, signal, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
3
|
import { toObservable, takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
4
4
|
import { distinctUntilChanged, tap, switchMap, EMPTY, map, catchError } from 'rxjs';
|
|
5
|
-
import { A as AiReceptionistApiService, I as IconComponent, g as EdSkeletonComponent } from './edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-
|
|
5
|
+
import { A as AiReceptionistApiService, I as IconComponent, g as EdSkeletonComponent } from './edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-DDS7VdnD.mjs';
|
|
6
6
|
|
|
7
7
|
class CallRecordingPlayerComponent {
|
|
8
8
|
constructor() {
|
|
@@ -107,4 +107,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
107
107
|
}], ctorParameters: () => [] });
|
|
108
108
|
|
|
109
109
|
export { CallRecordingPlayerComponent as C };
|
|
110
|
-
//# sourceMappingURL=edvak99-voice-receptionist-widget-call-recording-player.component-
|
|
110
|
+
//# sourceMappingURL=edvak99-voice-receptionist-widget-call-recording-player.component-4fL-zUWy.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"edvak99-voice-receptionist-widget-call-recording-player.component-CSKZTNFs.mjs","sources":["../../../src/lib/components/call-recording-player/call-recording-player.component.ts","../../../src/lib/components/call-recording-player/call-recording-player.component.html"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n ElementRef,\n inject,\n input,\n output,\n signal,\n viewChild,\n} from '@angular/core';\nimport { takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop';\nimport { catchError, distinctUntilChanged, EMPTY, map, switchMap, tap } from 'rxjs';\n\nimport { EdSkeletonComponent } from '../../ui/ed-skeleton.component';\n\nimport { CallRecordingStatus } from '../../models/ai-receptionist.types';\nimport { AiReceptionistApiService } from '../../services/ai-receptionist-api.service';\nimport { IconComponent } from '../../ui/ed-icon.component';\n\ntype PlayerPhase = 'loading' | CallRecordingStatus | 'error';\n\n@Component({\n selector: 'eds-call-recording-player',\n imports: [IconComponent, EdSkeletonComponent],\n templateUrl: './call-recording-player.component.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class CallRecordingPlayerComponent {\n readonly callId = input.required<string>();\n readonly currentTimeChange = output<number>();\n readonly durationChange = output<number>();\n\n private readonly audioRef = viewChild<ElementRef<HTMLAudioElement>>('audioEl');\n\n private readonly api = inject(AiReceptionistApiService);\n private readonly destroyRef = inject(DestroyRef);\n\n protected readonly phase = signal<PlayerPhase>('loading');\n protected readonly blobUrl = signal<string | null>(null);\n protected readonly durationSeconds = signal<number | null>(null);\n protected readonly message = signal<string | null>(null);\n\n /** Tracked outside signals so cleanup never reads blobUrl (avoids effect/subscription loops). */\n private objectUrl: string | null = null;\n\n constructor() {\n toObservable(this.callId)\n .pipe(\n distinctUntilChanged(),\n tap(() => this.revokeObjectUrl()),\n switchMap((id) => {\n if (!id) {\n this.resetUi();\n return EMPTY;\n }\n this.phase.set('loading');\n this.message.set(null);\n return this.api.getCallRecording(id).pipe(\n switchMap((meta) => {\n if (meta.status !== 'ready' || !meta.url) {\n this.phase.set(meta.status);\n this.message.set(meta.message ?? null);\n this.durationSeconds.set(meta.durationSeconds ?? null);\n return EMPTY;\n }\n this.durationSeconds.set(meta.durationSeconds ?? null);\n return this.api.getCallRecordingBlob(meta.url).pipe(\n map((blob) => blob),\n catchError(() => {\n this.phase.set('error');\n this.message.set('Could not load recording audio.');\n return EMPTY;\n }),\n );\n }),\n catchError(() => {\n this.phase.set('unavailable');\n this.message.set('Could not load recording metadata.');\n return EMPTY;\n }),\n );\n }),\n takeUntilDestroyed(),\n )\n .subscribe((blob) => {\n this.revokeObjectUrl();\n this.objectUrl = URL.createObjectURL(blob);\n this.blobUrl.set(this.objectUrl);\n this.phase.set('ready');\n this.message.set(null);\n const dur = this.durationSeconds();\n if (dur != null && dur > 0) {\n this.durationChange.emit(dur);\n }\n });\n\n this.destroyRef.onDestroy(() => this.revokeObjectUrl());\n }\n\n protected formatDuration(seconds: number): string {\n const m = Math.floor(seconds / 60);\n const s = seconds % 60;\n return `${m}:${s.toString().padStart(2, '0')}`;\n }\n\n protected onAudioError(): void {\n this.phase.set('error');\n this.message.set('Playback error — try reloading the page.');\n }\n\n protected onTimeUpdate(event: Event): void {\n const el = event.target as HTMLAudioElement;\n this.currentTimeChange.emit(el.currentTime);\n }\n\n protected onLoadedMetadata(event: Event): void {\n const el = event.target as HTMLAudioElement;\n if (Number.isFinite(el.duration) && el.duration > 0) {\n this.durationChange.emit(el.duration);\n }\n }\n\n /** Seek playback — used by synced transcript lines. */\n seekTo(seconds: number): void {\n const el = this.audioRef()?.nativeElement;\n if (!el) return;\n el.currentTime = Math.max(0, seconds);\n void el.play().catch(() => undefined);\n this.currentTimeChange.emit(el.currentTime);\n }\n\n private revokeObjectUrl(): void {\n if (this.objectUrl) {\n URL.revokeObjectURL(this.objectUrl);\n this.objectUrl = null;\n }\n this.blobUrl.set(null);\n }\n\n private resetUi(): void {\n this.phase.set('loading');\n this.durationSeconds.set(null);\n this.message.set(null);\n }\n}\n","<section class=\"flex flex-col gap-3 rounded-lg border border-base bg-lighter p-4\" aria-labelledby=\"call-recording-title\">\n <header class=\"flex items-center gap-2\">\n <ed-icon name=\"graph_new\" [size]=\"20\" />\n <h4 id=\"call-recording-title\" class=\"m-0 flex-1\">Call recording</h4>\n @if (durationSeconds(); as dur) {\n <span class=\"font-['IBM_Plex_Mono'] fs-sm text-light\">{{ formatDuration(dur) }}</span>\n }\n </header>\n\n @switch (phase()) {\n @case ('loading') {\n <div class=\"grid gap-2\" aria-busy=\"true\">\n <ed-skeleton class=\"h-10 w-full !rounded-md\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-24\"></ed-skeleton>\n </div>\n }\n @case ('ready') {\n @if (blobUrl(); as src) {\n <audio\n #audioEl\n class=\"h-10 w-full\"\n controls\n [src]=\"src\"\n (error)=\"onAudioError()\"\n (timeupdate)=\"onTimeUpdate($event)\"\n (loadedmetadata)=\"onLoadedMetadata($event)\"\n >\n Your browser does not support audio playback.\n </audio>\n }\n }\n @case ('pending') {\n <p class=\"fs-sm text-light m-0\">\n {{ message() ?? 'Recording is still processing…' }}\n </p>\n }\n @case ('unavailable') {\n <p class=\"fs-sm text-light m-0\">\n {{ message() ?? 'No recording available for this call.' }}\n </p>\n }\n @case ('failed') {\n <p class=\"fs-sm text-red-600 m-0\">\n {{ message() ?? 'Recording could not be retrieved.' }}\n </p>\n }\n @case ('error') {\n <p class=\"fs-sm text-red-600 m-0\">\n {{ message() ?? 'Playback error.' }}\n </p>\n }\n }\n</section>\n"],"names":[],"mappings":";;;;;;MA4Ba,4BAA4B,CAAA;AAkBvC,IAAA,WAAA,GAAA;AAjBS,QAAA,IAAA,CAAA,MAAM,GAAG,KAAK,CAAC,QAAQ,EAAU;QACjC,IAAA,CAAA,iBAAiB,GAAG,MAAM,EAAU;QACpC,IAAA,CAAA,cAAc,GAAG,MAAM,EAAU;AAEzB,QAAA,IAAA,CAAA,QAAQ,GAAG,SAAS,CAA+B,SAAS,CAAC;AAE7D,QAAA,IAAA,CAAA,GAAG,GAAG,MAAM,CAAC,wBAAwB,CAAC;AACtC,QAAA,IAAA,CAAA,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;AAE7B,QAAA,IAAA,CAAA,KAAK,GAAG,MAAM,CAAc,SAAS,CAAC;AACtC,QAAA,IAAA,CAAA,OAAO,GAAG,MAAM,CAAgB,IAAI,CAAC;AACrC,QAAA,IAAA,CAAA,eAAe,GAAG,MAAM,CAAgB,IAAI,CAAC;AAC7C,QAAA,IAAA,CAAA,OAAO,GAAG,MAAM,CAAgB,IAAI,CAAC;;QAGhD,IAAA,CAAA,SAAS,GAAkB,IAAI;AAGrC,QAAA,YAAY,CAAC,IAAI,CAAC,MAAM;aACrB,IAAI,CACH,oBAAoB,EAAE,EACtB,GAAG,CAAC,MAAM,IAAI,CAAC,eAAe,EAAE,CAAC,EACjC,SAAS,CAAC,CAAC,EAAE,KAAI;YACf,IAAI,CAAC,EAAE,EAAE;gBACP,IAAI,CAAC,OAAO,EAAE;AACd,gBAAA,OAAO,KAAK;YACd;AACA,YAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC;AACzB,YAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;AACtB,YAAA,OAAO,IAAI,CAAC,GAAG,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,IAAI,CACvC,SAAS,CAAC,CAAC,IAAI,KAAI;gBACjB,IAAI,IAAI,CAAC,MAAM,KAAK,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE;oBACxC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC;oBAC3B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC;oBACtC,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,eAAe,IAAI,IAAI,CAAC;AACtD,oBAAA,OAAO,KAAK;gBACd;gBACA,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,eAAe,IAAI,IAAI,CAAC;gBACtD,OAAO,IAAI,CAAC,GAAG,CAAC,oBAAoB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CACjD,GAAG,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,EACnB,UAAU,CAAC,MAAK;AACd,oBAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC;AACvB,oBAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC;AACnD,oBAAA,OAAO,KAAK;gBACd,CAAC,CAAC,CACH;AACH,YAAA,CAAC,CAAC,EACF,UAAU,CAAC,MAAK;AACd,gBAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC;AAC7B,gBAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC;AACtD,gBAAA,OAAO,KAAK;YACd,CAAC,CAAC,CACH;AACH,QAAA,CAAC,CAAC,EACF,kBAAkB,EAAE;AAErB,aAAA,SAAS,CAAC,CAAC,IAAI,KAAI;YAClB,IAAI,CAAC,eAAe,EAAE;YACtB,IAAI,CAAC,SAAS,GAAG,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC;YAC1C,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC;AAChC,YAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC;AACvB,YAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;AACtB,YAAA,MAAM,GAAG,GAAG,IAAI,CAAC,eAAe,EAAE;YAClC,IAAI,GAAG,IAAI,IAAI,IAAI,GAAG,GAAG,CAAC,EAAE;AAC1B,gBAAA,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC;YAC/B;AACF,QAAA,CAAC,CAAC;AAEJ,QAAA,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,MAAM,IAAI,CAAC,eAAe,EAAE,CAAC;IACzD;AAEU,IAAA,cAAc,CAAC,OAAe,EAAA;QACtC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,EAAE,CAAC;AAClC,QAAA,MAAM,CAAC,GAAG,OAAO,GAAG,EAAE;AACtB,QAAA,OAAO,CAAA,EAAG,CAAC,CAAA,CAAA,EAAI,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;IAChD;IAEU,YAAY,GAAA;AACpB,QAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC;AACvB,QAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,0CAA0C,CAAC;IAC9D;AAEU,IAAA,YAAY,CAAC,KAAY,EAAA;AACjC,QAAA,MAAM,EAAE,GAAG,KAAK,CAAC,MAA0B;QAC3C,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC;IAC7C;AAEU,IAAA,gBAAgB,CAAC,KAAY,EAAA;AACrC,QAAA,MAAM,EAAE,GAAG,KAAK,CAAC,MAA0B;AAC3C,QAAA,IAAI,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,QAAQ,GAAG,CAAC,EAAE;YACnD,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC;QACvC;IACF;;AAGA,IAAA,MAAM,CAAC,OAAe,EAAA;QACpB,MAAM,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,EAAE,aAAa;AACzC,QAAA,IAAI,CAAC,EAAE;YAAE;QACT,EAAE,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC;AACrC,QAAA,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,MAAM,SAAS,CAAC;QACrC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC;IAC7C;IAEQ,eAAe,GAAA;AACrB,QAAA,IAAI,IAAI,CAAC,SAAS,EAAE;AAClB,YAAA,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,SAAS,CAAC;AACnC,YAAA,IAAI,CAAC,SAAS,GAAG,IAAI;QACvB;AACA,QAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;IACxB;IAEQ,OAAO,GAAA;AACb,QAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC;AACzB,QAAA,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC;AAC9B,QAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;IACxB;+GApHW,4BAA4B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;AAA5B,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,4BAA4B,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,2BAAA,EAAA,MAAA,EAAA,EAAA,MAAA,EAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,OAAA,EAAA,EAAA,iBAAA,EAAA,mBAAA,EAAA,cAAA,EAAA,gBAAA,EAAA,EAAA,WAAA,EAAA,CAAA,EAAA,YAAA,EAAA,UAAA,EAAA,KAAA,EAAA,IAAA,EAAA,SAAA,EAAA,CAAA,SAAA,CAAA,EAAA,WAAA,EAAA,IAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EC5BzC,usDAqDA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,ED7Bc,aAAa,sLAAE,mBAAmB,EAAA,QAAA,EAAA,aAAA,EAAA,MAAA,EAAA,CAAA,OAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA,CAAA;;4FAInC,4BAA4B,EAAA,UAAA,EAAA,CAAA;kBANxC,SAAS;+BACI,2BAA2B,EAAA,OAAA,EAC5B,CAAC,aAAa,EAAE,mBAAmB,CAAC,EAAA,eAAA,EAE5B,uBAAuB,CAAC,MAAM,EAAA,QAAA,EAAA,usDAAA,EAAA;;;;;"}
|
|
1
|
+
{"version":3,"file":"edvak99-voice-receptionist-widget-call-recording-player.component-4fL-zUWy.mjs","sources":["../../../src/lib/components/call-recording-player/call-recording-player.component.ts","../../../src/lib/components/call-recording-player/call-recording-player.component.html"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n ElementRef,\n inject,\n input,\n output,\n signal,\n viewChild,\n} from '@angular/core';\nimport { takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop';\nimport { catchError, distinctUntilChanged, EMPTY, map, switchMap, tap } from 'rxjs';\n\nimport { EdSkeletonComponent } from '../../ui/ed-skeleton.component';\n\nimport { CallRecordingStatus } from '../../models/ai-receptionist.types';\nimport { AiReceptionistApiService } from '../../services/ai-receptionist-api.service';\nimport { IconComponent } from '../../ui/ed-icon.component';\n\ntype PlayerPhase = 'loading' | CallRecordingStatus | 'error';\n\n@Component({\n selector: 'eds-call-recording-player',\n imports: [IconComponent, EdSkeletonComponent],\n templateUrl: './call-recording-player.component.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class CallRecordingPlayerComponent {\n readonly callId = input.required<string>();\n readonly currentTimeChange = output<number>();\n readonly durationChange = output<number>();\n\n private readonly audioRef = viewChild<ElementRef<HTMLAudioElement>>('audioEl');\n\n private readonly api = inject(AiReceptionistApiService);\n private readonly destroyRef = inject(DestroyRef);\n\n protected readonly phase = signal<PlayerPhase>('loading');\n protected readonly blobUrl = signal<string | null>(null);\n protected readonly durationSeconds = signal<number | null>(null);\n protected readonly message = signal<string | null>(null);\n\n /** Tracked outside signals so cleanup never reads blobUrl (avoids effect/subscription loops). */\n private objectUrl: string | null = null;\n\n constructor() {\n toObservable(this.callId)\n .pipe(\n distinctUntilChanged(),\n tap(() => this.revokeObjectUrl()),\n switchMap((id) => {\n if (!id) {\n this.resetUi();\n return EMPTY;\n }\n this.phase.set('loading');\n this.message.set(null);\n return this.api.getCallRecording(id).pipe(\n switchMap((meta) => {\n if (meta.status !== 'ready' || !meta.url) {\n this.phase.set(meta.status);\n this.message.set(meta.message ?? null);\n this.durationSeconds.set(meta.durationSeconds ?? null);\n return EMPTY;\n }\n this.durationSeconds.set(meta.durationSeconds ?? null);\n return this.api.getCallRecordingBlob(meta.url).pipe(\n map((blob) => blob),\n catchError(() => {\n this.phase.set('error');\n this.message.set('Could not load recording audio.');\n return EMPTY;\n }),\n );\n }),\n catchError(() => {\n this.phase.set('unavailable');\n this.message.set('Could not load recording metadata.');\n return EMPTY;\n }),\n );\n }),\n takeUntilDestroyed(),\n )\n .subscribe((blob) => {\n this.revokeObjectUrl();\n this.objectUrl = URL.createObjectURL(blob);\n this.blobUrl.set(this.objectUrl);\n this.phase.set('ready');\n this.message.set(null);\n const dur = this.durationSeconds();\n if (dur != null && dur > 0) {\n this.durationChange.emit(dur);\n }\n });\n\n this.destroyRef.onDestroy(() => this.revokeObjectUrl());\n }\n\n protected formatDuration(seconds: number): string {\n const m = Math.floor(seconds / 60);\n const s = seconds % 60;\n return `${m}:${s.toString().padStart(2, '0')}`;\n }\n\n protected onAudioError(): void {\n this.phase.set('error');\n this.message.set('Playback error — try reloading the page.');\n }\n\n protected onTimeUpdate(event: Event): void {\n const el = event.target as HTMLAudioElement;\n this.currentTimeChange.emit(el.currentTime);\n }\n\n protected onLoadedMetadata(event: Event): void {\n const el = event.target as HTMLAudioElement;\n if (Number.isFinite(el.duration) && el.duration > 0) {\n this.durationChange.emit(el.duration);\n }\n }\n\n /** Seek playback — used by synced transcript lines. */\n seekTo(seconds: number): void {\n const el = this.audioRef()?.nativeElement;\n if (!el) return;\n el.currentTime = Math.max(0, seconds);\n void el.play().catch(() => undefined);\n this.currentTimeChange.emit(el.currentTime);\n }\n\n private revokeObjectUrl(): void {\n if (this.objectUrl) {\n URL.revokeObjectURL(this.objectUrl);\n this.objectUrl = null;\n }\n this.blobUrl.set(null);\n }\n\n private resetUi(): void {\n this.phase.set('loading');\n this.durationSeconds.set(null);\n this.message.set(null);\n }\n}\n","<section class=\"flex flex-col gap-3 rounded-lg border border-base bg-lighter p-4\" aria-labelledby=\"call-recording-title\">\n <header class=\"flex items-center gap-2\">\n <ed-icon name=\"graph_new\" [size]=\"20\" />\n <h4 id=\"call-recording-title\" class=\"m-0 flex-1\">Call recording</h4>\n @if (durationSeconds(); as dur) {\n <span class=\"font-['IBM_Plex_Mono'] fs-sm text-light\">{{ formatDuration(dur) }}</span>\n }\n </header>\n\n @switch (phase()) {\n @case ('loading') {\n <div class=\"grid gap-2\" aria-busy=\"true\">\n <ed-skeleton class=\"h-10 w-full !rounded-md\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-24\"></ed-skeleton>\n </div>\n }\n @case ('ready') {\n @if (blobUrl(); as src) {\n <audio\n #audioEl\n class=\"h-10 w-full\"\n controls\n [src]=\"src\"\n (error)=\"onAudioError()\"\n (timeupdate)=\"onTimeUpdate($event)\"\n (loadedmetadata)=\"onLoadedMetadata($event)\"\n >\n Your browser does not support audio playback.\n </audio>\n }\n }\n @case ('pending') {\n <p class=\"fs-sm text-light m-0\">\n {{ message() ?? 'Recording is still processing…' }}\n </p>\n }\n @case ('unavailable') {\n <p class=\"fs-sm text-light m-0\">\n {{ message() ?? 'No recording available for this call.' }}\n </p>\n }\n @case ('failed') {\n <p class=\"fs-sm text-red-600 m-0\">\n {{ message() ?? 'Recording could not be retrieved.' }}\n </p>\n }\n @case ('error') {\n <p class=\"fs-sm text-red-600 m-0\">\n {{ message() ?? 'Playback error.' }}\n </p>\n }\n }\n</section>\n"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { inject, signal, Injectable } from '@angular/core';
|
|
3
3
|
import { tap, map } from 'rxjs';
|
|
4
|
-
import { A as AiReceptionistApiService } from './edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-
|
|
4
|
+
import { A as AiReceptionistApiService } from './edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-DDS7VdnD.mjs';
|
|
5
5
|
|
|
6
6
|
class CallReviewService {
|
|
7
7
|
constructor() {
|
|
@@ -26,4 +26,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
26
26
|
}] });
|
|
27
27
|
|
|
28
28
|
export { CallReviewService as C };
|
|
29
|
-
//# sourceMappingURL=edvak99-voice-receptionist-widget-call-review.service-
|
|
29
|
+
//# sourceMappingURL=edvak99-voice-receptionist-widget-call-review.service-BhbCmB1S.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"edvak99-voice-receptionist-widget-call-review.service-
|
|
1
|
+
{"version":3,"file":"edvak99-voice-receptionist-widget-call-review.service-BhbCmB1S.mjs","sources":["../../../src/lib/services/call-review.service.ts"],"sourcesContent":["import { Injectable, inject, signal } from '@angular/core';\nimport { Observable, map, tap } from 'rxjs';\n\nimport { CallReviewStatus } from '../utils/call-review.util';\nimport { AiReceptionistApiService } from './ai-receptionist-api.service';\n\n@Injectable({ providedIn: 'root' })\nexport class CallReviewService {\n private readonly api = inject(AiReceptionistApiService);\n\n /** Cached from dashboard summary; decremented optimistically on review. */\n readonly needsReviewCount = signal<number | null>(null);\n\n setNeedsReviewCount(count: number): void {\n this.needsReviewCount.set(count);\n }\n\n markReviewed(callId: string): Observable<CallReviewStatus> {\n return this.api.postReview(callId).pipe(\n tap(() => {\n this.needsReviewCount.update((c) => (c != null && c > 0 ? c - 1 : c));\n }),\n map(() => 'reviewed'),\n );\n }\n}\n"],"names":[],"mappings":";;;;;MAOa,iBAAiB,CAAA;AAD9B,IAAA,WAAA,GAAA;AAEmB,QAAA,IAAA,CAAA,GAAG,GAAG,MAAM,CAAC,wBAAwB,CAAC;;AAG9C,QAAA,IAAA,CAAA,gBAAgB,GAAG,MAAM,CAAgB,IAAI,CAAC;AAcxD,IAAA;AAZC,IAAA,mBAAmB,CAAC,KAAa,EAAA;AAC/B,QAAA,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC;IAClC;AAEA,IAAA,YAAY,CAAC,MAAc,EAAA;AACzB,QAAA,OAAO,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,IAAI,CACrC,GAAG,CAAC,MAAK;AACP,YAAA,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;QACvE,CAAC,CAAC,EACF,GAAG,CAAC,MAAM,UAAU,CAAC,CACtB;IACH;+GAjBW,iBAAiB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA,CAAA;AAAjB,IAAA,SAAA,IAAA,CAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,iBAAiB,cADJ,MAAM,EAAA,CAAA,CAAA;;4FACnB,iBAAiB,EAAA,UAAA,EAAA,CAAA;kBAD7B,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;;;"}
|
|
@@ -2,7 +2,7 @@ import * as i0 from '@angular/core';
|
|
|
2
2
|
import { inject, signal, computed, CUSTOM_ELEMENTS_SCHEMA, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
3
|
import { Router, ActivatedRoute, RouterLink } from '@angular/router';
|
|
4
4
|
import { DatePipe } from '@angular/common';
|
|
5
|
-
import { A as AiReceptionistApiService, L as LiveCallsListService, a as AgentOnlineService, h as historyResolution, i as isUnknownCaller, c as callerMetaLine, b as ageFromDob, d as historyResultChips, r as resultChipIcon, e as historyResolutionLabel, E as EdAvatarComponent, f as EdButtonComponent, I as IconComponent, g as EdSkeletonComponent } from './edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-
|
|
5
|
+
import { A as AiReceptionistApiService, L as LiveCallsListService, a as AgentOnlineService, h as historyResolution, i as isUnknownCaller, c as callerMetaLine, b as ageFromDob, d as historyResultChips, r as resultChipIcon, e as historyResolutionLabel, E as EdAvatarComponent, f as EdButtonComponent, I as IconComponent, g as EdSkeletonComponent } from './edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-DDS7VdnD.mjs';
|
|
6
6
|
import { s as sentimentIconSrc, a as sentimentLabel, E as EdsElapsedPipe } from './edvak99-voice-receptionist-widget-eds-elapsed.pipe-Dra7e7xN.mjs';
|
|
7
7
|
import { i as isNeedsReview } from './edvak99-voice-receptionist-widget-call-review.util-rWIPxDtQ.mjs';
|
|
8
8
|
import { S as SmartTooltipDirective } from './edvak99-voice-receptionist-widget-smart-tooltip.directive-ChEdIem3.mjs';
|
|
@@ -288,4 +288,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
288
288
|
}] });
|
|
289
289
|
|
|
290
290
|
export { DashboardPageComponent };
|
|
291
|
-
//# sourceMappingURL=edvak99-voice-receptionist-widget-dashboard-page.component-
|
|
291
|
+
//# sourceMappingURL=edvak99-voice-receptionist-widget-dashboard-page.component-CxNYLBbg.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"edvak99-voice-receptionist-widget-dashboard-page.component-CE2Zh0eJ.mjs","sources":["../../../src/lib/pages/dashboard-page/dashboard-page.component.ts","../../../src/lib/pages/dashboard-page/dashboard-page.component.html"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n computed,\n CUSTOM_ELEMENTS_SCHEMA,\n inject,\n OnDestroy,\n OnInit,\n signal,\n} from '@angular/core';\nimport { ActivatedRoute, Router, RouterLink } from '@angular/router';\nimport { DatePipe } from '@angular/common';\n\nimport {\n CallStatus,\n DashboardData,\n HistoryCall,\n LiveCall,\n Sentiment,\n} from '../../models/ai-receptionist.types';\nimport { AiReceptionistApiService } from '../../services/ai-receptionist-api.service';\nimport { AgentOnlineService } from '../../services/agent-online.service';\nimport { LiveCallsListService } from '../../services/live-calls-list.service';\nimport {\n ageFromDob,\n callerMetaLine,\n historyResolution,\n historyResolutionLabel,\n historyResultChips,\n HistoryResolution,\n isUnknownCaller,\n resultChipIcon,\n} from '../../utils/call-history-display.util';\nimport { sentimentIconSrc, sentimentLabel } from '../../utils/sentiment-display.util';\nimport { isNeedsReview } from '../../utils/call-review.util';\nimport { EdButtonComponent } from '../../ui/ed-button.component';\nimport { EdSkeletonComponent } from '../../ui/ed-skeleton.component';\n\nimport { SmartTooltipDirective } from '../../shared/smart-tooltip.directive';\nimport { TABLE_SKELETON_ROWS } from '../../shared/table-skeleton.constants';\nimport { EdAvatarComponent } from '../../ui/ed-avatar.component';\nimport { IconComponent } from '../../ui/ed-icon.component';\nimport { EdsPulseDotComponent } from '../../ui/eds-pulse-dot.component';\nimport { EdsElapsedPipe } from '../../pipes/eds-elapsed.pipe';\n\ninterface KpiCardVm {\n id: string;\n label: string;\n value: string;\n meta: string;\n link?: string;\n queryParams?: Record<string, string>;\n}\n\ninterface LiveCallRowVm {\n id: string;\n name: string;\n initials: string;\n avatarTone: 'gray' | 'brand' | 'warm';\n metaLine: string;\n sentiment: Sentiment;\n sentimentLabel: string;\n sentimentIconSrc: string;\n direction: 'inbound' | 'outbound';\n directionIcon: string;\n directionTitle: string;\n goal: string;\n statusSubtitle: string;\n handlingLabel: string;\n handlingVariant: 'opened' | 'danger' | 'success';\n needsAssistance: boolean;\n started: number;\n}\n\ninterface AttentionRowVm {\n id: string;\n callId: string;\n name: string;\n initials: string;\n avatarTone: 'gray' | 'brand' | 'violet';\n metaLine: string;\n badge: string;\n detail: string;\n timeLabel: string;\n direction: 'inbound' | 'outbound';\n directionIcon: string;\n directionTitle: string;\n}\n\ninterface RecentHistoryRowVm {\n id: string;\n name: string;\n initials: string;\n avatarTone: 'gray' | 'brand';\n metaLine: string;\n direction: 'inbound' | 'outbound';\n directionIcon: string;\n directionTitle: string;\n reason: string;\n handledByLabel: string;\n handledByVariant: 'opened' | 'primary';\n resolution: HistoryResolution | null;\n resolutionLabel: string;\n resolutionVariant: 'success' | 'warning';\n resultChips: { label: string; icon: string }[];\n durationLabel: string;\n started: number | null;\n whenLabel: string;\n needsReview: boolean;\n}\n\n@Component({\n selector: 'eds-dashboard-page',\n imports: [\n RouterLink,\n DatePipe,\n EdAvatarComponent,\n EdButtonComponent,\n IconComponent,\n EdsPulseDotComponent,\n EdsElapsedPipe,\n SmartTooltipDirective,\n EdSkeletonComponent,\n ],\n templateUrl: './dashboard-page.component.html',\n styleUrl: './dashboard-page.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n schemas: [CUSTOM_ELEMENTS_SCHEMA],\n host: { class: 'block h-full min-h-0' },\n})\nexport class DashboardPageComponent implements OnInit, OnDestroy {\n private readonly api = inject(AiReceptionistApiService);\n private readonly liveCallsList = inject(LiveCallsListService);\n private readonly agentOnline = inject(AgentOnlineService);\n private readonly router = inject(Router);\n private readonly route = inject(ActivatedRoute);\n\n protected readonly data = signal<DashboardData | null>(null);\n protected readonly loading = signal(true);\n protected readonly kpiSkeletonRows = [0, 1, 2, 3] as const;\n protected readonly listSkeletonRows = [0, 1, 2] as const;\n protected readonly skeletonRows = TABLE_SKELETON_ROWS;\n\n protected readonly liveCalls = this.liveCallsList.calls;\n protected readonly liveCallsLoading = this.liveCallsList.loading;\n protected readonly liveCallsError = this.liveCallsList.error;\n protected readonly agentOffline = computed(() => this.agentOnline.online() === false);\n\n protected readonly kpiCards = computed((): KpiCardVm[] => {\n const stats = this.data()?.stats;\n if (!stats) return [];\n const calls = stats.answeredToday;\n const resolvedCount = Math.round((stats.completionRate / 100) * Math.max(calls, 1));\n return [\n {\n id: 'calls',\n label: 'Calls handled',\n value: String(calls),\n meta: 'Today',\n link: '../history',\n },\n {\n id: 'appointments',\n label: 'Appointments booked',\n value: String(stats.appointmentsBooked),\n meta: 'Created by AI',\n link: '../activities',\n queryParams: { tab: 'appointments' },\n },\n {\n id: 'tasks',\n label: 'Tasks created',\n value: String(stats.tasksCreated),\n meta: 'Created by AI',\n link: '../activities',\n },\n {\n id: 'resolved',\n label: 'Resolved without staff',\n value: `${stats.completionRate}%`,\n meta: calls > 0 ? `${resolvedCount} of ${calls} calls` : 'AI handled',\n link: '../activities',\n },\n ];\n });\n\n protected readonly liveCallRows = computed(() =>\n this.liveCalls().map((call) => this.toLiveCallRow(call)),\n );\n\n protected readonly liveCallCount = computed(() => this.liveCallRows().length);\n\n protected readonly attentionRows = computed((): AttentionRowVm[] => {\n const fromLive = this.liveCalls()\n .filter((c) => this.isAssistanceStatus(c.status) || c.sentiment === 'frustrated' || c.sentiment === 'urgent')\n .map((c) => this.toAttentionFromLive(c));\n\n const fromHistory = (this.data()?.recentHistory ?? [])\n .filter(\n (row) =>\n historyResolution({\n outcome: row.outcome,\n resolution: row.resolution,\n risk: row.risk,\n }) === 'needs_attention',\n )\n .map((row) => this.toAttentionFromHistory(row));\n\n const seen = new Set<string>();\n const merged: AttentionRowVm[] = [];\n for (const item of [...fromLive, ...fromHistory]) {\n if (seen.has(item.callId)) continue;\n seen.add(item.callId);\n merged.push(item);\n if (merged.length >= 6) break;\n }\n return merged;\n });\n\n protected readonly attentionCount = computed(() => this.attentionRows().length);\n\n protected readonly recentHistoryRows = computed(() =>\n (this.data()?.recentHistory ?? []).map((row) => this.toRecentHistoryRow(row)),\n );\n\n protected readonly recentHistoryCount = computed(() => this.recentHistoryRows().length);\n\n ngOnInit(): void {\n this.liveCallsList.start();\n this.api.getDashboard().subscribe(({ data }) => {\n this.data.set(data);\n this.loading.set(false);\n });\n }\n\n ngOnDestroy(): void {\n this.liveCallsList.stop();\n }\n\n protected exportCsv(): void {\n // mock export\n }\n\n protected openHistoryDetail(id: string): void {\n void this.router.navigate(['../history', id], { relativeTo: this.route });\n }\n\n protected openLiveCall(id: string): void {\n void this.router.navigate(['../live', id], { relativeTo: this.route });\n }\n\n protected openAttention(item: AttentionRowVm): void {\n const live = this.liveCalls().some((c) => c.id === item.callId);\n void this.router.navigate(live ? ['../live', item.callId] : ['../history', item.callId], {\n relativeTo: this.route,\n });\n }\n\n private toLiveCallRow(call: LiveCall): LiveCallRowVm {\n const unknown = isUnknownCaller(call.name, call.matched);\n const needsAssistance = this.isAssistanceStatus(call.status);\n const staffHandling = call.status === 'takeover' || call.controlMode === 'takeover';\n const lastTool = call.tools[call.tools.length - 1];\n\n return {\n id: call.id,\n name: unknown ? 'Unknown Caller' : call.name.trim() || 'Unknown Caller',\n initials: unknown ? '?' : call.initials || '?',\n avatarTone: unknown ? 'gray' : 'warm',\n metaLine: callerMetaLine({\n name: call.name,\n matched: call.matched,\n phone: call.phone,\n dob: call.dob,\n age: call.age ?? ageFromDob(call.dob),\n gender: call.gender,\n }),\n sentiment: call.sentiment,\n sentimentLabel: sentimentLabel(call.sentiment),\n sentimentIconSrc: sentimentIconSrc(call.sentiment),\n direction: call.direction,\n directionIcon: call.direction === 'inbound' ? 'call_received' : 'call_made',\n directionTitle: call.direction === 'inbound' ? 'Incoming call' : 'Outgoing call',\n goal: call.reason || call.goal || '—',\n statusSubtitle: lastTool?.result || call.goal || 'In progress…',\n handlingLabel: needsAssistance\n ? 'NEED ASSISTANCE'\n : staffHandling\n ? 'STAFF HANDLING'\n : 'AI HANDLING',\n handlingVariant: needsAssistance ? 'danger' : staffHandling ? 'success' : 'opened',\n needsAssistance,\n started: call.started,\n };\n }\n\n private toAttentionFromLive(call: LiveCall): AttentionRowVm {\n const unknown = isUnknownCaller(call.name, call.matched);\n return {\n id: `live-${call.id}`,\n callId: call.id,\n name: unknown ? 'Unknown Caller' : call.name.trim() || 'Unknown Caller',\n initials: unknown ? '?' : call.initials || '?',\n avatarTone: unknown ? 'gray' : 'violet',\n metaLine: callerMetaLine({\n name: call.name,\n matched: call.matched,\n phone: call.phone,\n dob: call.dob,\n age: call.age ?? ageFromDob(call.dob),\n gender: call.gender,\n }),\n badge: this.attentionBadgeFromLive(call),\n detail: call.goal || call.reason || 'Needs staff follow-up.',\n timeLabel: 'Just now',\n direction: call.direction,\n directionIcon: call.direction === 'inbound' ? 'call_received' : 'call_made',\n directionTitle: call.direction === 'inbound' ? 'Incoming call' : 'Outgoing call',\n };\n }\n\n private toAttentionFromHistory(row: HistoryCall): AttentionRowVm {\n const unknown = isUnknownCaller(row.name);\n const inbound = row.direction === 'inbound';\n return {\n id: `hist-${row.id}`,\n callId: row.id,\n name: unknown ? 'Unknown Caller' : row.name.trim() || 'Unknown Caller',\n initials: unknown || !row.initials ? '?' : row.initials,\n avatarTone: unknown || row.initials === '?' ? 'gray' : 'violet',\n metaLine: callerMetaLine({\n dob: row.dob,\n age: row.age,\n gender: row.gender,\n phone: row.phone,\n name: row.name,\n }),\n badge: this.attentionBadgeFromHistory(row),\n detail: row.reason || row.outcome || 'Needs review.',\n timeLabel: row.whenLabel || 'Recently',\n direction: row.direction,\n directionIcon: inbound ? 'call_received' : 'call_made',\n directionTitle: inbound ? 'Incoming call' : 'Outgoing call',\n };\n }\n\n private toRecentHistoryRow(row: HistoryCall): RecentHistoryRowVm {\n const unknown = isUnknownCaller(row.name);\n const resolution = historyResolution({\n outcome: row.outcome,\n resolution: row.resolution,\n risk: row.risk,\n });\n const handledByStaff = row.handledBy === 'staff';\n const inbound = row.direction === 'inbound';\n const chips = historyResultChips(row.results, row.outcome);\n\n return {\n id: row.id,\n name: row.name || 'Unknown Caller',\n initials: row.initials || '?',\n avatarTone: unknown || row.initials === '?' ? 'gray' : 'brand',\n metaLine: callerMetaLine({\n dob: row.dob,\n age: row.age,\n gender: row.gender,\n phone: row.phone,\n name: row.name,\n }),\n direction: row.direction,\n directionIcon: inbound ? 'call_received' : 'call_made',\n directionTitle: inbound ? 'Incoming call' : 'Outgoing call',\n reason: row.reason || '—',\n handledByLabel: handledByStaff ? 'STAFF' : 'AI',\n handledByVariant: handledByStaff ? 'primary' : 'opened',\n resolution,\n resolutionLabel: historyResolutionLabel(resolution),\n resolutionVariant: resolution === 'resolved' ? 'success' : 'warning',\n resultChips: chips.map((label) => ({ label, icon: resultChipIcon(label) })),\n durationLabel: row.durationLabel ?? this.formatDuration(row.duration),\n started: row.started || null,\n whenLabel: row.whenLabel || '—',\n needsReview: isNeedsReview(row.review),\n };\n }\n\n private isAssistanceStatus(status: CallStatus): boolean {\n return status === 'needs-help' || status === 'human-requested' || status === 'urgent';\n }\n\n private attentionBadgeFromLive(call: LiveCall): string {\n if (call.status === 'urgent') return 'SAFETY ESCALATION';\n if (call.status === 'human-requested') return 'HUMAN REQUESTED';\n if (call.verification === 'failed' || call.verification === 'unknown') return 'IDENTITY UNRESOLVED';\n if (call.status === 'needs-help') return 'NEED ASSISTANCE';\n return 'NEEDS REVIEW';\n }\n\n private attentionBadgeFromHistory(row: HistoryCall): string {\n const o = (row.outcome || row.reason || '').toLowerCase();\n if (o.includes('book') || o.includes('appoint')) return 'BOOKING FAILURE';\n if (o.includes('ident') || row.verification === 'failed' || row.verification === 'unknown') {\n return 'IDENTITY UNRESOLVED';\n }\n if (row.risk === 'urgent') return 'SAFETY ESCALATION';\n return 'NEEDS REVIEW';\n }\n\n private 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","<div class=\"flex h-full flex-col overflow-auto bg-lighter p-base dashboard-page\">\n <header class=\"mb-base flex shrink-0 items-start justify-between gap-base\">\n <div class=\"flex flex-col gap-2xs\">\n <h3>Dashboard</h3>\n <p class=\"fs-sm text-light\">Monitor AI receptionist activity and follow up where needed</p>\n </div>\n <ed-button\n class=\"shrink-0\"\n variant=\"default\"\n size=\"sm\"\n (click$)=\"exportCsv()\">\n <ed-icon slot=\"prefix\" name=\"download\" [size]=\"16\" />\n Export CSV\n </ed-button>\n </header>\n\n <div class=\"flex flex-1 flex-col gap-base \">\n @if (loading()) {\n <section class=\"grid grid-cols-1 gap-base sm:grid-cols-2 xl:grid-cols-4\" aria-label=\"Overview KPIs\" aria-busy=\"true\">\n @for (_ of kpiSkeletonRows; track _) {\n <article class=\"flex flex-col gap-xs overflow-hidden rounded-md border border-light bg-white p-base\">\n <ed-skeleton class=\"h-3 w-28\"></ed-skeleton>\n <ed-skeleton class=\"h-6 w-14\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-24\"></ed-skeleton>\n </article>\n }\n </section>\n\n <section\n class=\"grid grid-cols-1 items-start gap-base xl:grid-cols-[minmax(0,785fr)_minmax(0,415fr)]\"\n aria-label=\"Live calls and needs attention\"\n aria-busy=\"true\"\n >\n <article class=\"flex flex-col gap-base overflow-hidden rounded-lg border border-light bg-white p-base\">\n <header class=\"flex shrink-0 items-center justify-between gap-sm\">\n <div class=\"flex items-center gap-sm\">\n <h4>Live Calls</h4>\n <ed-skeleton class=\"h-5 w-16 !rounded-full\"></ed-skeleton>\n </div>\n <ed-skeleton class=\"h-3 w-16\"></ed-skeleton>\n </header>\n <ul class=\"m-0 grid max-h-64 list-none content-start gap-xs overflow-x-hidden overflow-y-auto p-0\">\n @for (_ of listSkeletonRows; track _) {\n <li>\n <div class=\"flex w-full items-center gap-base rounded-md border border-light bg-white p-sm\">\n <div class=\"flex min-w-0 flex-1 items-center gap-xs xl:max-w-xs\">\n <ed-skeleton class=\"h-9 w-9 shrink-0 !rounded-md\"></ed-skeleton>\n <div class=\"grid min-w-0 flex-1 gap-2xs\">\n <ed-skeleton class=\"h-3 w-32\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-40\"></ed-skeleton>\n </div>\n </div>\n <div class=\"hidden min-w-0 flex-1 items-center gap-xs xl:flex\">\n <ed-skeleton class=\"h-9 w-9 shrink-0 !rounded-md\"></ed-skeleton>\n <div class=\"grid min-w-0 gap-2xs\">\n <ed-skeleton class=\"h-3 w-28\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-24\"></ed-skeleton>\n </div>\n </div>\n <div class=\"grid shrink-0 justify-items-end gap-2xs self-stretch\">\n <ed-skeleton class=\"h-5 w-24 !rounded-full\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-12\"></ed-skeleton>\n </div>\n </div>\n </li>\n }\n </ul>\n </article>\n\n <article class=\"flex flex-col gap-base overflow-hidden rounded-lg border border-light bg-white p-base\">\n <header class=\"flex shrink-0 items-center justify-between gap-sm\">\n <div class=\"flex items-center gap-sm\">\n <h4>Needs Attention</h4>\n <ed-skeleton class=\"h-5 w-8 !rounded-full\"></ed-skeleton>\n </div>\n <ed-skeleton class=\"h-3 w-16\"></ed-skeleton>\n </header>\n <ul class=\"m-0 grid max-h-64 list-none content-start gap-xs overflow-x-hidden overflow-y-auto p-0\">\n @for (_ of listSkeletonRows; track _) {\n <li>\n <div class=\"flex w-full flex-col gap-xs overflow-hidden rounded-md border border-light bg-white p-sm\">\n <div class=\"flex w-full min-w-0 items-center gap-xs\">\n <div class=\"flex min-w-0 flex-1 items-center gap-xs\">\n <ed-skeleton class=\"h-9 w-9 shrink-0 !rounded-md\"></ed-skeleton>\n <div class=\"flex min-w-0 flex-1 flex-col gap-2xs\">\n <ed-skeleton class=\"h-3 w-32\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-36\"></ed-skeleton>\n </div>\n </div>\n <ed-skeleton class=\"h-5 w-28 shrink-0 !rounded-full\"></ed-skeleton>\n </div>\n <div class=\"flex w-full min-w-0 items-center gap-sm\">\n <div class=\"flex min-w-0 flex-1 items-center gap-xs\">\n <ed-skeleton class=\"h-8 w-8 shrink-0 !rounded-md\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-full max-w-xs\"></ed-skeleton>\n </div>\n <ed-skeleton class=\"h-3 w-14 shrink-0\"></ed-skeleton>\n </div>\n </div>\n </li>\n }\n </ul>\n </article>\n </section>\n\n <article class=\"flex flex-col gap-base overflow-hidden rounded-lg border border-light bg-white p-base\" aria-busy=\"true\">\n <header class=\"flex items-center justify-between gap-xs\">\n <div class=\"flex items-center gap-sm\">\n <h4>Recent Calls</h4>\n <ed-skeleton class=\"h-5 w-8 !rounded-full\"></ed-skeleton>\n </div>\n <ed-skeleton class=\"h-3 w-16\"></ed-skeleton>\n </header>\n <div class=\"overflow-x-auto bg-white rounded-md\">\n <table class=\"table-default relative min-w-5xl w-full\" aria-label=\"Recent calls\">\n <thead>\n <tr>\n <th>Time</th>\n <th>Patient/Caller</th>\n <th class=\"w-16 text-center\" aria-label=\"Direction\">\n <span class=\"inline-flex items-center justify-center gap-2xs\">\n <ed-icon name=\"call_received\" [size]=\"12\" class=\"text-success\" color=\"currentColor\" />\n <span class=\"text-light\">/</span>\n <ed-icon name=\"call_made\" [size]=\"12\" class=\"text-primary\" color=\"currentColor\" />\n </span>\n </th>\n <th>Goal</th>\n <th>Handled By</th>\n <th>Resolution</th>\n <th>Result</th>\n <th>Duration</th>\n </tr>\n </thead>\n <tbody>\n @for (_ of skeletonRows; track _) {\n <tr>\n <td>\n <div class=\"grid gap-2xs py-2xs\">\n <ed-skeleton class=\"h-3 w-12\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-20\"></ed-skeleton>\n </div>\n </td>\n <td>\n <div class=\"flex items-center gap-xs py-2xs\">\n <ed-skeleton class=\"h-8 w-8 !rounded-md\"></ed-skeleton>\n <div class=\"grid gap-2xs\">\n <ed-skeleton class=\"h-3 w-28\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-36\"></ed-skeleton>\n </div>\n </div>\n </td>\n <td class=\"text-center\">\n <div class=\"flex justify-center py-2xs\">\n <ed-skeleton class=\"h-5 w-5 !rounded\"></ed-skeleton>\n </div>\n </td>\n <td><ed-skeleton class=\"h-3 w-32\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-5 w-12 !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-5 w-28 !rounded\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-3 w-10\"></ed-skeleton></td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n </article>\n } @else if (data()) {\n <section class=\"grid grid-cols-1 gap-base sm:grid-cols-2 xl:grid-cols-4\" aria-label=\"Overview KPIs\">\n @for (tile of kpiCards(); track tile.id) {\n @if (tile.link) {\n <a\n [routerLink]=\"tile.link\"\n [queryParams]=\"tile.queryParams ?? null\"\n class=\"flex flex-col gap-xs overflow-hidden rounded-md border border-light bg-white p-base no-underline text-inherit transition-colors hover:bg-primary-100 hover:shadow-sm\">\n <span class=\"fs-xs font-semibold uppercase tracking-wide text-light\">{{ tile.label }}</span>\n <h3>{{ tile.value }}</h3>\n <span class=\"fs-xs text-light\">{{ tile.meta }}</span>\n </a>\n } @else {\n <article class=\"flex flex-col gap-xs overflow-hidden rounded-md border border-light bg-white p-base\">\n <span class=\"fs-xs font-semibold uppercase tracking-wide text-light\">{{ tile.label }}</span>\n <h3>{{ tile.value }}</h3>\n <span class=\"fs-sm text-light\">{{ tile.meta }}</span>\n </article>\n }\n }\n </section>\n\n <section\n class=\"grid grid-cols-1 items-start gap-base xl:grid-cols-[minmax(0,785fr)_minmax(0,415fr)]\"\n aria-label=\"Live calls and needs attention\">\n <article class=\"flex flex-col gap-base overflow-hidden rounded-lg border border-light bg-white p-base\">\n <header class=\"flex shrink-0 items-center justify-between gap-sm\">\n <div class=\"flex items-center gap-sm\">\n <h4>Live Calls</h4>\n @if (agentOffline()) {\n <span class=\"inline-flex items-center gap-2xs fs-sm font-semibold text-danger\">\n <ed-icon name=\"phone_disabled\" [size]=\"18\" />\n Offline\n </span>\n } @else {\n <ed-badge-2 variant=\"success\" pill uppercase>\n {{ liveCallCount() }} LIVE\n </ed-badge-2>\n }\n </div>\n <a routerLink=\"../live\"\n class=\"inline-flex items-center gap-2xs fs-sm font-medium text-primary no-underline\">\n View All\n <ed-icon name=\"chevron_right\" [size]=\"16\" color=\"currentColor\" />\n </a>\n </header>\n\n <ul class=\"m-0 grid max-h-64 list-none content-start gap-xs overflow-x-hidden overflow-y-auto p-0\">\n @if (liveCallsError()) {\n <li class=\"fs-sm text-light\" role=\"alert\">{{ liveCallsError() }}</li>\n }\n @if (liveCallsLoading() && liveCallRows().length === 0) {\n @for (_ of listSkeletonRows; track _) {\n <li>\n <div class=\"flex w-full items-center gap-base rounded-md border border-light bg-white p-sm\">\n <div class=\"flex min-w-0 flex-1 items-center gap-xs xl:max-w-xs\">\n <ed-skeleton class=\"h-9 w-9 shrink-0 !rounded-md\"></ed-skeleton>\n <div class=\"grid min-w-0 flex-1 gap-2xs\">\n <ed-skeleton class=\"h-3 w-32\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-40\"></ed-skeleton>\n </div>\n </div>\n <div class=\"hidden min-w-0 flex-1 items-center gap-xs xl:flex\">\n <ed-skeleton class=\"h-9 w-9 shrink-0 !rounded-md\"></ed-skeleton>\n <div class=\"grid min-w-0 gap-2xs\">\n <ed-skeleton class=\"h-3 w-28\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-24\"></ed-skeleton>\n </div>\n </div>\n <div class=\"grid shrink-0 justify-items-end gap-2xs self-stretch\">\n <ed-skeleton class=\"h-5 w-24 !rounded-full\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-12\"></ed-skeleton>\n </div>\n </div>\n </li>\n }\n }\n @for (call of liveCallRows(); track call.id) {\n <li>\n <button\n type=\"button\"\n class=\"flex w-full cursor-pointer items-center gap-base rounded-md border border-light bg-white p-sm text-left transition-colors hover:bg-lighter hover:shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-primary\"\n [class.border-danger]=\"call.needsAssistance\"\n [class.bg-danger-50]=\"call.needsAssistance\"\n (click)=\"openLiveCall(call.id)\"\n >\n <div class=\"flex min-w-0 flex-1 items-center gap-xs xl:max-w-xs\">\n <ed-avatar\n shape=\"box\"\n size=\"base\"\n [initials]=\"call.initials\"\n [tone]=\"call.avatarTone\"\n />\n <div class=\"grid min-w-0 flex-1 gap-2xs\">\n <div class=\"flex min-w-0 flex-wrap items-center gap-sm\">\n <span class=\"fs-sm font-semibold text-dark\">{{ call.name }}</span>\n <span class=\"vr-sentiment\" [attr.data-sentiment]=\"call.sentiment\">\n <span class=\"vr-sentiment__icon\" aria-hidden=\"true\">\n <img [src]=\"call.sentimentIconSrc\" alt=\"\" width=\"16\" height=\"16\" />\n </span>\n <span>{{ call.sentimentLabel }}</span>\n </span>\n </div>\n <span class=\"fs-sm whitespace-nowrap text-light\">{{ call.metaLine }}</span>\n </div>\n </div>\n\n <div class=\"hidden min-w-0 flex-1 items-center gap-xs xl:flex\">\n <span\n class=\"inline-flex size-9 shrink-0 items-center justify-center rounded-md\"\n [class.bg-success-50]=\"call.direction === 'inbound'\"\n [class.text-success]=\"call.direction === 'inbound'\"\n [class.bg-primary-50]=\"call.direction === 'outbound'\"\n [class.text-primary]=\"call.direction === 'outbound'\"\n [smartTooltip]=\"call.directionTitle\"\n >\n <ed-icon [name]=\"call.directionIcon\" [size]=\"18\" color=\"currentColor\" />\n </span>\n <div class=\"grid min-w-0 gap-2xs whitespace-nowrap\">\n <span class=\"fs-sm font-medium text-dark\">{{ call.goal }}</span>\n <span class=\"fs-xs text-light\">{{ call.statusSubtitle }}</span>\n </div>\n </div>\n\n <div class=\"grid shrink-0 justify-items-end gap-2xs self-stretch\">\n <ed-badge-2 [attr.variant]=\"call.handlingVariant\" pill uppercase>\n {{ call.handlingLabel }}\n </ed-badge-2>\n <strong\n class=\"inline-flex items-center gap-2xs fs-2xs text-primary\"\n [class.text-danger]=\"call.needsAssistance\"\n [class.text-light]=\"!call.needsAssistance\"\n >\n @if (!call.needsAssistance) {\n <eds-pulse-dot />\n }\n {{ call.started | edsElapsed }}\n </strong>\n </div>\n </button>\n </li>\n } @empty {\n @if (!liveCallsLoading()) {\n <li class=\"fs-sm text-light\">No active calls right now.</li>\n }\n }\n </ul>\n </article>\n\n <article class=\"flex flex-col gap-base overflow-hidden rounded-lg border border-light bg-white p-base\">\n <header class=\"flex shrink-0 items-center justify-between gap-sm\">\n <div class=\"flex items-center gap-sm\">\n <h4>Needs Attention</h4>\n <ed-badge-2 variant=\"warning\" pill>\n {{ attentionCount() }}\n </ed-badge-2>\n </div>\n <a\n routerLink=\"../history\"\n class=\"inline-flex items-center gap-2xs fs-sm font-medium text-primary no-underline\"\n >\n View All\n <ed-icon name=\"chevron_right\" [size]=\"16\" color=\"currentColor\" />\n </a>\n </header>\n\n <ul class=\"m-0 grid max-h-64 list-none content-start gap-xs overflow-x-hidden overflow-y-auto p-0\">\n @for (item of attentionRows(); track item.id) {\n <li>\n <div\n role=\"button\"\n tabindex=\"0\"\n class=\"flex w-full cursor-pointer flex-col gap-xs overflow-hidden rounded-md border border-light bg-white p-sm text-left transition-colors hover:bg-lighter hover:shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-primary\"\n [attr.aria-label]=\"'Open attention item for ' + item.name\"\n (click)=\"openAttention(item)\"\n (keyup.enter)=\"openAttention(item)\"\n >\n <div class=\"flex w-full min-w-0 items-center gap-xs\">\n <div class=\"flex min-w-0 flex-1 items-center gap-xs\">\n <ed-avatar\n shape=\"box\"\n size=\"base\"\n [initials]=\"item.initials\"\n [tone]=\"item.avatarTone\"\n />\n <div class=\"flex min-w-0 flex-1 flex-col gap-2xs\">\n <div class=\"flex min-w-0 items-center gap-2xs\">\n <span class=\"truncate fs-sm font-semibold text-dark\">{{ item.name }}</span>\n <!-- <span class=\"inline-flex shrink-0 text-light\">\n <ed-icon name=\"TagSimple\" [size]=\"14\" color=\"currentColor\" />\n </span> -->\n </div>\n <span class=\"truncate fs-sm text-light\">{{ item.metaLine }}</span>\n </div>\n </div>\n <ed-badge-2 class=\"shrink-0\" variant=\"light\" pill uppercase>\n {{ item.badge }}\n </ed-badge-2>\n </div>\n <div class=\"flex w-full min-w-0 items-center gap-sm\">\n <div class=\"flex min-w-0 flex-1 items-center gap-xs\">\n <span\n class=\"inline-flex size-8 shrink-0 items-center justify-center rounded-md\"\n [class.bg-success-50]=\"item.direction === 'inbound'\"\n [class.text-success]=\"item.direction === 'inbound'\"\n [class.bg-primary-50]=\"item.direction === 'outbound'\"\n [class.text-primary]=\"item.direction === 'outbound'\"\n [smartTooltip]=\"item.directionTitle\"\n >\n <ed-icon [name]=\"item.directionIcon\" [size]=\"16\" color=\"currentColor\" />\n </span>\n <span class=\"min-w-0 flex-1 truncate fs-sm text-light\">{{ item.detail }}</span>\n </div>\n <span class=\"shrink-0 whitespace-nowrap fs-xs text-light\">{{ item.timeLabel }}</span>\n </div>\n </div>\n </li>\n } @empty {\n <li class=\"fs-sm text-light\">Nothing needs attention right now.</li>\n }\n </ul>\n </article>\n </section>\n\n <article class=\"flex flex-col gap-base overflow-hidden rounded-lg border border-light bg-white p-base\">\n <header class=\"flex items-center justify-between gap-xs\">\n <div class=\"flex items-center gap-sm\">\n <h4>Recent Calls</h4>\n <ed-badge-2\n variant=\"light\"\n pill\n [attr.aria-label]=\"'Recent calls count ' + recentHistoryCount()\"\n >\n {{ recentHistoryCount() }}\n </ed-badge-2>\n </div>\n <a\n routerLink=\"../history\"\n class=\"inline-flex items-center gap-2xs fs-sm font-medium text-primary no-underline\"\n >\n View All\n <ed-icon name=\"chevron_right\" [size]=\"16\" color=\"currentColor\" />\n </a>\n </header>\n\n <div class=\"overflow-x-auto bg-white rounded-md\">\n <table class=\"table-default relative min-w-5xl w-full\" aria-label=\"Recent calls\">\n <thead>\n <tr>\n <th>Time</th>\n <th>Patient/Caller</th>\n <th class=\"w-16 text-center\" aria-label=\"Direction\">\n <span class=\"inline-flex items-center justify-center gap-2xs\">\n <ed-icon name=\"call_received\" [size]=\"12\" class=\"text-success\" color=\"currentColor\" />\n <span class=\"text-light\">/</span>\n <ed-icon name=\"call_made\" [size]=\"12\" class=\"text-primary\" color=\"currentColor\" />\n </span>\n </th>\n <th>Goal</th>\n <th>Handled By</th>\n <th>Resolution</th>\n <th>Result</th>\n <th>Duration</th>\n </tr>\n </thead>\n <tbody>\n @for (row of recentHistoryRows(); track row.id) {\n <tr\n class=\"focus-visible:outline focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-primary\"\n tabindex=\"0\"\n role=\"link\"\n [attr.aria-label]=\"'View call details for ' + row.name\"\n (click)=\"openHistoryDetail(row.id)\"\n (keyup.enter)=\"openHistoryDetail(row.id)\"\n >\n <td>\n <div class=\"flex flex-col gap-2xs whitespace-nowrap\">\n @if (row.started) {\n <span class=\"fs-xs font-medium text-light\">{{ row.started | date: 'shortTime' }}</span>\n <span class=\"fs-xs text-light\">{{ row.started | date: 'MMM d, y' }}</span>\n } @else {\n <span class=\"fs-xs font-medium text-light\">{{ row.whenLabel }}</span>\n }\n </div>\n </td>\n\n <td>\n <div class=\"flex min-w-52 items-center gap-xs\">\n <ed-avatar\n shape=\"box\"\n size=\"base\"\n [initials]=\"row.initials\"\n [tone]=\"row.avatarTone\"\n />\n <div class=\"flex min-w-0 flex-col gap-2xs\">\n <div class=\"flex min-w-0 items-center gap-2xs text-dark\">\n <span\n class=\"inline-block min-w-0 max-w-56 truncate fs-sm font-semibold\"\n [smartTooltip]=\"row.name\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ row.name }}</span>\n <!-- <span class=\"inline-flex shrink-0 text-light\">\n <ed-icon name=\"TagSimple\" [size]=\"14\" color=\"currentColor\" />\n </span> -->\n </div>\n <span\n class=\"inline-block min-w-0 max-w-64 truncate fs-xs text-light\"\n [smartTooltip]=\"row.metaLine\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ row.metaLine }}</span>\n </div>\n </div>\n </td>\n\n <td class=\"text-center\">\n <span\n class=\"inline-flex size-5 items-center justify-center rounded\"\n [class.bg-success-50]=\"row.direction === 'inbound'\"\n [class.text-success]=\"row.direction === 'inbound'\"\n [class.bg-primary-50]=\"row.direction === 'outbound'\"\n [class.text-primary]=\"row.direction === 'outbound'\"\n [smartTooltip]=\"row.directionTitle\"\n >\n <ed-icon [name]=\"row.directionIcon\" [size]=\"12\" color=\"currentColor\" />\n </span>\n </td>\n\n <td>\n <span\n class=\"inline-block min-w-0 max-w-56 truncate fs-sm font-medium text-light\"\n [smartTooltip]=\"row.reason\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ row.reason }}</span>\n </td>\n\n <td>\n <ed-badge-2 [attr.variant]=\"row.handledByVariant\" pill uppercase>\n {{ row.handledByLabel }}\n </ed-badge-2>\n </td>\n\n <td>\n @if (row.resolution) {\n <ed-badge-2 [attr.variant]=\"row.resolutionVariant\" pill uppercase>\n {{ row.resolutionLabel }}\n </ed-badge-2>\n }\n </td>\n\n <td>\n <div class=\"flex min-w-0 max-w-80 flex-wrap gap-2xs\">\n @for (chip of row.resultChips; track chip.label) {\n <span\n class=\"inline-flex h-5 max-w-48 min-w-0 items-center gap-2xs rounded bg-light px-2xs fs-xs font-medium text-dark\"\n >\n <ed-icon [name]=\"chip.icon\" [size]=\"12\" color=\"currentColor\" />\n <span\n class=\"min-w-0 truncate\"\n [smartTooltip]=\"chip.label\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ chip.label }}</span>\n </span>\n } @empty {\n <span class=\"fs-sm text-light\">—</span>\n }\n </div>\n </td>\n\n <td class=\"whitespace-nowrap tabular-nums fs-xs font-medium text-light\">\n {{ row.durationLabel }}\n </td>\n </tr>\n } @empty {\n <tr class=\"table-no-data\">\n <td colspan=\"8\" class=\"py-base text-center fs-sm text-light\">No recent calls.</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n </article>\n }\n </div>\n</div>\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"edvak99-voice-receptionist-widget-dashboard-page.component-CxNYLBbg.mjs","sources":["../../../src/lib/pages/dashboard-page/dashboard-page.component.ts","../../../src/lib/pages/dashboard-page/dashboard-page.component.html"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n computed,\n CUSTOM_ELEMENTS_SCHEMA,\n inject,\n OnDestroy,\n OnInit,\n signal,\n} from '@angular/core';\nimport { ActivatedRoute, Router, RouterLink } from '@angular/router';\nimport { DatePipe } from '@angular/common';\n\nimport {\n CallStatus,\n DashboardData,\n HistoryCall,\n LiveCall,\n Sentiment,\n} from '../../models/ai-receptionist.types';\nimport { AiReceptionistApiService } from '../../services/ai-receptionist-api.service';\nimport { AgentOnlineService } from '../../services/agent-online.service';\nimport { LiveCallsListService } from '../../services/live-calls-list.service';\nimport {\n ageFromDob,\n callerMetaLine,\n historyResolution,\n historyResolutionLabel,\n historyResultChips,\n HistoryResolution,\n isUnknownCaller,\n resultChipIcon,\n} from '../../utils/call-history-display.util';\nimport { sentimentIconSrc, sentimentLabel } from '../../utils/sentiment-display.util';\nimport { isNeedsReview } from '../../utils/call-review.util';\nimport { EdButtonComponent } from '../../ui/ed-button.component';\nimport { EdSkeletonComponent } from '../../ui/ed-skeleton.component';\n\nimport { SmartTooltipDirective } from '../../shared/smart-tooltip.directive';\nimport { TABLE_SKELETON_ROWS } from '../../shared/table-skeleton.constants';\nimport { EdAvatarComponent } from '../../ui/ed-avatar.component';\nimport { IconComponent } from '../../ui/ed-icon.component';\nimport { EdsPulseDotComponent } from '../../ui/eds-pulse-dot.component';\nimport { EdsElapsedPipe } from '../../pipes/eds-elapsed.pipe';\n\ninterface KpiCardVm {\n id: string;\n label: string;\n value: string;\n meta: string;\n link?: string;\n queryParams?: Record<string, string>;\n}\n\ninterface LiveCallRowVm {\n id: string;\n name: string;\n initials: string;\n avatarTone: 'gray' | 'brand' | 'warm';\n metaLine: string;\n sentiment: Sentiment;\n sentimentLabel: string;\n sentimentIconSrc: string;\n direction: 'inbound' | 'outbound';\n directionIcon: string;\n directionTitle: string;\n goal: string;\n statusSubtitle: string;\n handlingLabel: string;\n handlingVariant: 'opened' | 'danger' | 'success';\n needsAssistance: boolean;\n started: number;\n}\n\ninterface AttentionRowVm {\n id: string;\n callId: string;\n name: string;\n initials: string;\n avatarTone: 'gray' | 'brand' | 'violet';\n metaLine: string;\n badge: string;\n detail: string;\n timeLabel: string;\n direction: 'inbound' | 'outbound';\n directionIcon: string;\n directionTitle: string;\n}\n\ninterface RecentHistoryRowVm {\n id: string;\n name: string;\n initials: string;\n avatarTone: 'gray' | 'brand';\n metaLine: string;\n direction: 'inbound' | 'outbound';\n directionIcon: string;\n directionTitle: string;\n reason: string;\n handledByLabel: string;\n handledByVariant: 'opened' | 'primary';\n resolution: HistoryResolution | null;\n resolutionLabel: string;\n resolutionVariant: 'success' | 'warning';\n resultChips: { label: string; icon: string }[];\n durationLabel: string;\n started: number | null;\n whenLabel: string;\n needsReview: boolean;\n}\n\n@Component({\n selector: 'eds-dashboard-page',\n imports: [\n RouterLink,\n DatePipe,\n EdAvatarComponent,\n EdButtonComponent,\n IconComponent,\n EdsPulseDotComponent,\n EdsElapsedPipe,\n SmartTooltipDirective,\n EdSkeletonComponent,\n ],\n templateUrl: './dashboard-page.component.html',\n styleUrl: './dashboard-page.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n schemas: [CUSTOM_ELEMENTS_SCHEMA],\n host: { class: 'block h-full min-h-0' },\n})\nexport class DashboardPageComponent implements OnInit, OnDestroy {\n private readonly api = inject(AiReceptionistApiService);\n private readonly liveCallsList = inject(LiveCallsListService);\n private readonly agentOnline = inject(AgentOnlineService);\n private readonly router = inject(Router);\n private readonly route = inject(ActivatedRoute);\n\n protected readonly data = signal<DashboardData | null>(null);\n protected readonly loading = signal(true);\n protected readonly kpiSkeletonRows = [0, 1, 2, 3] as const;\n protected readonly listSkeletonRows = [0, 1, 2] as const;\n protected readonly skeletonRows = TABLE_SKELETON_ROWS;\n\n protected readonly liveCalls = this.liveCallsList.calls;\n protected readonly liveCallsLoading = this.liveCallsList.loading;\n protected readonly liveCallsError = this.liveCallsList.error;\n protected readonly agentOffline = computed(() => this.agentOnline.online() === false);\n\n protected readonly kpiCards = computed((): KpiCardVm[] => {\n const stats = this.data()?.stats;\n if (!stats) return [];\n const calls = stats.answeredToday;\n const resolvedCount = Math.round((stats.completionRate / 100) * Math.max(calls, 1));\n return [\n {\n id: 'calls',\n label: 'Calls handled',\n value: String(calls),\n meta: 'Today',\n link: '../history',\n },\n {\n id: 'appointments',\n label: 'Appointments booked',\n value: String(stats.appointmentsBooked),\n meta: 'Created by AI',\n link: '../activities',\n queryParams: { tab: 'appointments' },\n },\n {\n id: 'tasks',\n label: 'Tasks created',\n value: String(stats.tasksCreated),\n meta: 'Created by AI',\n link: '../activities',\n },\n {\n id: 'resolved',\n label: 'Resolved without staff',\n value: `${stats.completionRate}%`,\n meta: calls > 0 ? `${resolvedCount} of ${calls} calls` : 'AI handled',\n link: '../activities',\n },\n ];\n });\n\n protected readonly liveCallRows = computed(() =>\n this.liveCalls().map((call) => this.toLiveCallRow(call)),\n );\n\n protected readonly liveCallCount = computed(() => this.liveCallRows().length);\n\n protected readonly attentionRows = computed((): AttentionRowVm[] => {\n const fromLive = this.liveCalls()\n .filter((c) => this.isAssistanceStatus(c.status) || c.sentiment === 'frustrated' || c.sentiment === 'urgent')\n .map((c) => this.toAttentionFromLive(c));\n\n const fromHistory = (this.data()?.recentHistory ?? [])\n .filter(\n (row) =>\n historyResolution({\n outcome: row.outcome,\n resolution: row.resolution,\n risk: row.risk,\n }) === 'needs_attention',\n )\n .map((row) => this.toAttentionFromHistory(row));\n\n const seen = new Set<string>();\n const merged: AttentionRowVm[] = [];\n for (const item of [...fromLive, ...fromHistory]) {\n if (seen.has(item.callId)) continue;\n seen.add(item.callId);\n merged.push(item);\n if (merged.length >= 6) break;\n }\n return merged;\n });\n\n protected readonly attentionCount = computed(() => this.attentionRows().length);\n\n protected readonly recentHistoryRows = computed(() =>\n (this.data()?.recentHistory ?? []).map((row) => this.toRecentHistoryRow(row)),\n );\n\n protected readonly recentHistoryCount = computed(() => this.recentHistoryRows().length);\n\n ngOnInit(): void {\n this.liveCallsList.start();\n this.api.getDashboard().subscribe(({ data }) => {\n this.data.set(data);\n this.loading.set(false);\n });\n }\n\n ngOnDestroy(): void {\n this.liveCallsList.stop();\n }\n\n protected exportCsv(): void {\n // mock export\n }\n\n protected openHistoryDetail(id: string): void {\n void this.router.navigate(['../history', id], { relativeTo: this.route });\n }\n\n protected openLiveCall(id: string): void {\n void this.router.navigate(['../live', id], { relativeTo: this.route });\n }\n\n protected openAttention(item: AttentionRowVm): void {\n const live = this.liveCalls().some((c) => c.id === item.callId);\n void this.router.navigate(live ? ['../live', item.callId] : ['../history', item.callId], {\n relativeTo: this.route,\n });\n }\n\n private toLiveCallRow(call: LiveCall): LiveCallRowVm {\n const unknown = isUnknownCaller(call.name, call.matched);\n const needsAssistance = this.isAssistanceStatus(call.status);\n const staffHandling = call.status === 'takeover' || call.controlMode === 'takeover';\n const lastTool = call.tools[call.tools.length - 1];\n\n return {\n id: call.id,\n name: unknown ? 'Unknown Caller' : call.name.trim() || 'Unknown Caller',\n initials: unknown ? '?' : call.initials || '?',\n avatarTone: unknown ? 'gray' : 'warm',\n metaLine: callerMetaLine({\n name: call.name,\n matched: call.matched,\n phone: call.phone,\n dob: call.dob,\n age: call.age ?? ageFromDob(call.dob),\n gender: call.gender,\n }),\n sentiment: call.sentiment,\n sentimentLabel: sentimentLabel(call.sentiment),\n sentimentIconSrc: sentimentIconSrc(call.sentiment),\n direction: call.direction,\n directionIcon: call.direction === 'inbound' ? 'call_received' : 'call_made',\n directionTitle: call.direction === 'inbound' ? 'Incoming call' : 'Outgoing call',\n goal: call.reason || call.goal || '—',\n statusSubtitle: lastTool?.result || call.goal || 'In progress…',\n handlingLabel: needsAssistance\n ? 'NEED ASSISTANCE'\n : staffHandling\n ? 'STAFF HANDLING'\n : 'AI HANDLING',\n handlingVariant: needsAssistance ? 'danger' : staffHandling ? 'success' : 'opened',\n needsAssistance,\n started: call.started,\n };\n }\n\n private toAttentionFromLive(call: LiveCall): AttentionRowVm {\n const unknown = isUnknownCaller(call.name, call.matched);\n return {\n id: `live-${call.id}`,\n callId: call.id,\n name: unknown ? 'Unknown Caller' : call.name.trim() || 'Unknown Caller',\n initials: unknown ? '?' : call.initials || '?',\n avatarTone: unknown ? 'gray' : 'violet',\n metaLine: callerMetaLine({\n name: call.name,\n matched: call.matched,\n phone: call.phone,\n dob: call.dob,\n age: call.age ?? ageFromDob(call.dob),\n gender: call.gender,\n }),\n badge: this.attentionBadgeFromLive(call),\n detail: call.goal || call.reason || 'Needs staff follow-up.',\n timeLabel: 'Just now',\n direction: call.direction,\n directionIcon: call.direction === 'inbound' ? 'call_received' : 'call_made',\n directionTitle: call.direction === 'inbound' ? 'Incoming call' : 'Outgoing call',\n };\n }\n\n private toAttentionFromHistory(row: HistoryCall): AttentionRowVm {\n const unknown = isUnknownCaller(row.name);\n const inbound = row.direction === 'inbound';\n return {\n id: `hist-${row.id}`,\n callId: row.id,\n name: unknown ? 'Unknown Caller' : row.name.trim() || 'Unknown Caller',\n initials: unknown || !row.initials ? '?' : row.initials,\n avatarTone: unknown || row.initials === '?' ? 'gray' : 'violet',\n metaLine: callerMetaLine({\n dob: row.dob,\n age: row.age,\n gender: row.gender,\n phone: row.phone,\n name: row.name,\n }),\n badge: this.attentionBadgeFromHistory(row),\n detail: row.reason || row.outcome || 'Needs review.',\n timeLabel: row.whenLabel || 'Recently',\n direction: row.direction,\n directionIcon: inbound ? 'call_received' : 'call_made',\n directionTitle: inbound ? 'Incoming call' : 'Outgoing call',\n };\n }\n\n private toRecentHistoryRow(row: HistoryCall): RecentHistoryRowVm {\n const unknown = isUnknownCaller(row.name);\n const resolution = historyResolution({\n outcome: row.outcome,\n resolution: row.resolution,\n risk: row.risk,\n });\n const handledByStaff = row.handledBy === 'staff';\n const inbound = row.direction === 'inbound';\n const chips = historyResultChips(row.results, row.outcome);\n\n return {\n id: row.id,\n name: row.name || 'Unknown Caller',\n initials: row.initials || '?',\n avatarTone: unknown || row.initials === '?' ? 'gray' : 'brand',\n metaLine: callerMetaLine({\n dob: row.dob,\n age: row.age,\n gender: row.gender,\n phone: row.phone,\n name: row.name,\n }),\n direction: row.direction,\n directionIcon: inbound ? 'call_received' : 'call_made',\n directionTitle: inbound ? 'Incoming call' : 'Outgoing call',\n reason: row.reason || '—',\n handledByLabel: handledByStaff ? 'STAFF' : 'AI',\n handledByVariant: handledByStaff ? 'primary' : 'opened',\n resolution,\n resolutionLabel: historyResolutionLabel(resolution),\n resolutionVariant: resolution === 'resolved' ? 'success' : 'warning',\n resultChips: chips.map((label) => ({ label, icon: resultChipIcon(label) })),\n durationLabel: row.durationLabel ?? this.formatDuration(row.duration),\n started: row.started || null,\n whenLabel: row.whenLabel || '—',\n needsReview: isNeedsReview(row.review),\n };\n }\n\n private isAssistanceStatus(status: CallStatus): boolean {\n return status === 'needs-help' || status === 'human-requested' || status === 'urgent';\n }\n\n private attentionBadgeFromLive(call: LiveCall): string {\n if (call.status === 'urgent') return 'SAFETY ESCALATION';\n if (call.status === 'human-requested') return 'HUMAN REQUESTED';\n if (call.verification === 'failed' || call.verification === 'unknown') return 'IDENTITY UNRESOLVED';\n if (call.status === 'needs-help') return 'NEED ASSISTANCE';\n return 'NEEDS REVIEW';\n }\n\n private attentionBadgeFromHistory(row: HistoryCall): string {\n const o = (row.outcome || row.reason || '').toLowerCase();\n if (o.includes('book') || o.includes('appoint')) return 'BOOKING FAILURE';\n if (o.includes('ident') || row.verification === 'failed' || row.verification === 'unknown') {\n return 'IDENTITY UNRESOLVED';\n }\n if (row.risk === 'urgent') return 'SAFETY ESCALATION';\n return 'NEEDS REVIEW';\n }\n\n private 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","<div class=\"flex h-full flex-col overflow-auto bg-lighter p-base dashboard-page\">\n <header class=\"mb-base flex shrink-0 items-start justify-between gap-base\">\n <div class=\"flex flex-col gap-2xs\">\n <h3>Dashboard</h3>\n <p class=\"fs-sm text-light\">Monitor AI receptionist activity and follow up where needed</p>\n </div>\n <ed-button\n class=\"shrink-0\"\n variant=\"default\"\n size=\"sm\"\n (click$)=\"exportCsv()\">\n <ed-icon slot=\"prefix\" name=\"download\" [size]=\"16\" />\n Export CSV\n </ed-button>\n </header>\n\n <div class=\"flex flex-1 flex-col gap-base \">\n @if (loading()) {\n <section class=\"grid grid-cols-1 gap-base sm:grid-cols-2 xl:grid-cols-4\" aria-label=\"Overview KPIs\" aria-busy=\"true\">\n @for (_ of kpiSkeletonRows; track _) {\n <article class=\"flex flex-col gap-xs overflow-hidden rounded-md border border-light bg-white p-base\">\n <ed-skeleton class=\"h-3 w-28\"></ed-skeleton>\n <ed-skeleton class=\"h-6 w-14\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-24\"></ed-skeleton>\n </article>\n }\n </section>\n\n <section\n class=\"grid grid-cols-1 items-start gap-base xl:grid-cols-[minmax(0,785fr)_minmax(0,415fr)]\"\n aria-label=\"Live calls and needs attention\"\n aria-busy=\"true\"\n >\n <article class=\"flex flex-col gap-base overflow-hidden rounded-lg border border-light bg-white p-base\">\n <header class=\"flex shrink-0 items-center justify-between gap-sm\">\n <div class=\"flex items-center gap-sm\">\n <h4>Live Calls</h4>\n <ed-skeleton class=\"h-5 w-16 !rounded-full\"></ed-skeleton>\n </div>\n <ed-skeleton class=\"h-3 w-16\"></ed-skeleton>\n </header>\n <ul class=\"m-0 grid max-h-64 list-none content-start gap-xs overflow-x-hidden overflow-y-auto p-0\">\n @for (_ of listSkeletonRows; track _) {\n <li>\n <div class=\"flex w-full items-center gap-base rounded-md border border-light bg-white p-sm\">\n <div class=\"flex min-w-0 flex-1 items-center gap-xs xl:max-w-xs\">\n <ed-skeleton class=\"h-9 w-9 shrink-0 !rounded-md\"></ed-skeleton>\n <div class=\"grid min-w-0 flex-1 gap-2xs\">\n <ed-skeleton class=\"h-3 w-32\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-40\"></ed-skeleton>\n </div>\n </div>\n <div class=\"hidden min-w-0 flex-1 items-center gap-xs xl:flex\">\n <ed-skeleton class=\"h-9 w-9 shrink-0 !rounded-md\"></ed-skeleton>\n <div class=\"grid min-w-0 gap-2xs\">\n <ed-skeleton class=\"h-3 w-28\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-24\"></ed-skeleton>\n </div>\n </div>\n <div class=\"grid shrink-0 justify-items-end gap-2xs self-stretch\">\n <ed-skeleton class=\"h-5 w-24 !rounded-full\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-12\"></ed-skeleton>\n </div>\n </div>\n </li>\n }\n </ul>\n </article>\n\n <article class=\"flex flex-col gap-base overflow-hidden rounded-lg border border-light bg-white p-base\">\n <header class=\"flex shrink-0 items-center justify-between gap-sm\">\n <div class=\"flex items-center gap-sm\">\n <h4>Needs Attention</h4>\n <ed-skeleton class=\"h-5 w-8 !rounded-full\"></ed-skeleton>\n </div>\n <ed-skeleton class=\"h-3 w-16\"></ed-skeleton>\n </header>\n <ul class=\"m-0 grid max-h-64 list-none content-start gap-xs overflow-x-hidden overflow-y-auto p-0\">\n @for (_ of listSkeletonRows; track _) {\n <li>\n <div class=\"flex w-full flex-col gap-xs overflow-hidden rounded-md border border-light bg-white p-sm\">\n <div class=\"flex w-full min-w-0 items-center gap-xs\">\n <div class=\"flex min-w-0 flex-1 items-center gap-xs\">\n <ed-skeleton class=\"h-9 w-9 shrink-0 !rounded-md\"></ed-skeleton>\n <div class=\"flex min-w-0 flex-1 flex-col gap-2xs\">\n <ed-skeleton class=\"h-3 w-32\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-36\"></ed-skeleton>\n </div>\n </div>\n <ed-skeleton class=\"h-5 w-28 shrink-0 !rounded-full\"></ed-skeleton>\n </div>\n <div class=\"flex w-full min-w-0 items-center gap-sm\">\n <div class=\"flex min-w-0 flex-1 items-center gap-xs\">\n <ed-skeleton class=\"h-8 w-8 shrink-0 !rounded-md\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-full max-w-xs\"></ed-skeleton>\n </div>\n <ed-skeleton class=\"h-3 w-14 shrink-0\"></ed-skeleton>\n </div>\n </div>\n </li>\n }\n </ul>\n </article>\n </section>\n\n <article class=\"flex flex-col gap-base overflow-hidden rounded-lg border border-light bg-white p-base\" aria-busy=\"true\">\n <header class=\"flex items-center justify-between gap-xs\">\n <div class=\"flex items-center gap-sm\">\n <h4>Recent Calls</h4>\n <ed-skeleton class=\"h-5 w-8 !rounded-full\"></ed-skeleton>\n </div>\n <ed-skeleton class=\"h-3 w-16\"></ed-skeleton>\n </header>\n <div class=\"overflow-x-auto bg-white rounded-md\">\n <table class=\"table-default relative min-w-5xl w-full\" aria-label=\"Recent calls\">\n <thead>\n <tr>\n <th>Time</th>\n <th>Patient/Caller</th>\n <th class=\"w-16 text-center\" aria-label=\"Direction\">\n <span class=\"inline-flex items-center justify-center gap-2xs\">\n <ed-icon name=\"call_received\" [size]=\"12\" class=\"text-success\" color=\"currentColor\" />\n <span class=\"text-light\">/</span>\n <ed-icon name=\"call_made\" [size]=\"12\" class=\"text-primary\" color=\"currentColor\" />\n </span>\n </th>\n <th>Goal</th>\n <th>Handled By</th>\n <th>Resolution</th>\n <th>Result</th>\n <th>Duration</th>\n </tr>\n </thead>\n <tbody>\n @for (_ of skeletonRows; track _) {\n <tr>\n <td>\n <div class=\"grid gap-2xs py-2xs\">\n <ed-skeleton class=\"h-3 w-12\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-20\"></ed-skeleton>\n </div>\n </td>\n <td>\n <div class=\"flex items-center gap-xs py-2xs\">\n <ed-skeleton class=\"h-8 w-8 !rounded-md\"></ed-skeleton>\n <div class=\"grid gap-2xs\">\n <ed-skeleton class=\"h-3 w-28\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-36\"></ed-skeleton>\n </div>\n </div>\n </td>\n <td class=\"text-center\">\n <div class=\"flex justify-center py-2xs\">\n <ed-skeleton class=\"h-5 w-5 !rounded\"></ed-skeleton>\n </div>\n </td>\n <td><ed-skeleton class=\"h-3 w-32\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-5 w-12 !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-5 w-28 !rounded\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-3 w-10\"></ed-skeleton></td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n </article>\n } @else if (data()) {\n <section class=\"grid grid-cols-1 gap-base sm:grid-cols-2 xl:grid-cols-4\" aria-label=\"Overview KPIs\">\n @for (tile of kpiCards(); track tile.id) {\n @if (tile.link) {\n <a\n [routerLink]=\"tile.link\"\n [queryParams]=\"tile.queryParams ?? null\"\n class=\"flex flex-col gap-xs overflow-hidden rounded-md border border-light bg-white p-base no-underline text-inherit transition-colors hover:bg-primary-100 hover:shadow-sm\">\n <span class=\"fs-xs font-semibold uppercase tracking-wide text-light\">{{ tile.label }}</span>\n <h3>{{ tile.value }}</h3>\n <span class=\"fs-xs text-light\">{{ tile.meta }}</span>\n </a>\n } @else {\n <article class=\"flex flex-col gap-xs overflow-hidden rounded-md border border-light bg-white p-base\">\n <span class=\"fs-xs font-semibold uppercase tracking-wide text-light\">{{ tile.label }}</span>\n <h3>{{ tile.value }}</h3>\n <span class=\"fs-sm text-light\">{{ tile.meta }}</span>\n </article>\n }\n }\n </section>\n\n <section\n class=\"grid grid-cols-1 items-start gap-base xl:grid-cols-[minmax(0,785fr)_minmax(0,415fr)]\"\n aria-label=\"Live calls and needs attention\">\n <article class=\"flex flex-col gap-base overflow-hidden rounded-lg border border-light bg-white p-base\">\n <header class=\"flex shrink-0 items-center justify-between gap-sm\">\n <div class=\"flex items-center gap-sm\">\n <h4>Live Calls</h4>\n @if (agentOffline()) {\n <span class=\"inline-flex items-center gap-2xs fs-sm font-semibold text-danger\">\n <ed-icon name=\"phone_disabled\" [size]=\"18\" />\n Offline\n </span>\n } @else {\n <ed-badge-2 variant=\"success\" pill uppercase>\n {{ liveCallCount() }} LIVE\n </ed-badge-2>\n }\n </div>\n <a routerLink=\"../live\"\n class=\"inline-flex items-center gap-2xs fs-sm font-medium text-primary no-underline\">\n View All\n <ed-icon name=\"chevron_right\" [size]=\"16\" color=\"currentColor\" />\n </a>\n </header>\n\n <ul class=\"m-0 grid max-h-64 list-none content-start gap-xs overflow-x-hidden overflow-y-auto p-0\">\n @if (liveCallsError()) {\n <li class=\"fs-sm text-light\" role=\"alert\">{{ liveCallsError() }}</li>\n }\n @if (liveCallsLoading() && liveCallRows().length === 0) {\n @for (_ of listSkeletonRows; track _) {\n <li>\n <div class=\"flex w-full items-center gap-base rounded-md border border-light bg-white p-sm\">\n <div class=\"flex min-w-0 flex-1 items-center gap-xs xl:max-w-xs\">\n <ed-skeleton class=\"h-9 w-9 shrink-0 !rounded-md\"></ed-skeleton>\n <div class=\"grid min-w-0 flex-1 gap-2xs\">\n <ed-skeleton class=\"h-3 w-32\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-40\"></ed-skeleton>\n </div>\n </div>\n <div class=\"hidden min-w-0 flex-1 items-center gap-xs xl:flex\">\n <ed-skeleton class=\"h-9 w-9 shrink-0 !rounded-md\"></ed-skeleton>\n <div class=\"grid min-w-0 gap-2xs\">\n <ed-skeleton class=\"h-3 w-28\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-24\"></ed-skeleton>\n </div>\n </div>\n <div class=\"grid shrink-0 justify-items-end gap-2xs self-stretch\">\n <ed-skeleton class=\"h-5 w-24 !rounded-full\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-12\"></ed-skeleton>\n </div>\n </div>\n </li>\n }\n }\n @for (call of liveCallRows(); track call.id) {\n <li>\n <button\n type=\"button\"\n class=\"flex w-full cursor-pointer items-center gap-base rounded-md border border-light bg-white p-sm text-left transition-colors hover:bg-lighter hover:shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-primary\"\n [class.border-danger]=\"call.needsAssistance\"\n [class.bg-danger-50]=\"call.needsAssistance\"\n (click)=\"openLiveCall(call.id)\"\n >\n <div class=\"flex min-w-0 flex-1 items-center gap-xs xl:max-w-xs\">\n <ed-avatar\n shape=\"box\"\n size=\"base\"\n [initials]=\"call.initials\"\n [tone]=\"call.avatarTone\"\n />\n <div class=\"grid min-w-0 flex-1 gap-2xs\">\n <div class=\"flex min-w-0 flex-wrap items-center gap-sm\">\n <span class=\"fs-sm font-semibold text-dark\">{{ call.name }}</span>\n <span class=\"vr-sentiment\" [attr.data-sentiment]=\"call.sentiment\">\n <span class=\"vr-sentiment__icon\" aria-hidden=\"true\">\n <img [src]=\"call.sentimentIconSrc\" alt=\"\" width=\"16\" height=\"16\" />\n </span>\n <span>{{ call.sentimentLabel }}</span>\n </span>\n </div>\n <span class=\"fs-sm whitespace-nowrap text-light\">{{ call.metaLine }}</span>\n </div>\n </div>\n\n <div class=\"hidden min-w-0 flex-1 items-center gap-xs xl:flex\">\n <span\n class=\"inline-flex size-9 shrink-0 items-center justify-center rounded-md\"\n [class.bg-success-50]=\"call.direction === 'inbound'\"\n [class.text-success]=\"call.direction === 'inbound'\"\n [class.bg-primary-50]=\"call.direction === 'outbound'\"\n [class.text-primary]=\"call.direction === 'outbound'\"\n [smartTooltip]=\"call.directionTitle\"\n >\n <ed-icon [name]=\"call.directionIcon\" [size]=\"18\" color=\"currentColor\" />\n </span>\n <div class=\"grid min-w-0 gap-2xs whitespace-nowrap\">\n <span class=\"fs-sm font-medium text-dark\">{{ call.goal }}</span>\n <span class=\"fs-xs text-light\">{{ call.statusSubtitle }}</span>\n </div>\n </div>\n\n <div class=\"grid shrink-0 justify-items-end gap-2xs self-stretch\">\n <ed-badge-2 [attr.variant]=\"call.handlingVariant\" pill uppercase>\n {{ call.handlingLabel }}\n </ed-badge-2>\n <strong\n class=\"inline-flex items-center gap-2xs fs-2xs text-primary\"\n [class.text-danger]=\"call.needsAssistance\"\n [class.text-light]=\"!call.needsAssistance\"\n >\n @if (!call.needsAssistance) {\n <eds-pulse-dot />\n }\n {{ call.started | edsElapsed }}\n </strong>\n </div>\n </button>\n </li>\n } @empty {\n @if (!liveCallsLoading()) {\n <li class=\"fs-sm text-light\">No active calls right now.</li>\n }\n }\n </ul>\n </article>\n\n <article class=\"flex flex-col gap-base overflow-hidden rounded-lg border border-light bg-white p-base\">\n <header class=\"flex shrink-0 items-center justify-between gap-sm\">\n <div class=\"flex items-center gap-sm\">\n <h4>Needs Attention</h4>\n <ed-badge-2 variant=\"warning\" pill>\n {{ attentionCount() }}\n </ed-badge-2>\n </div>\n <a\n routerLink=\"../history\"\n class=\"inline-flex items-center gap-2xs fs-sm font-medium text-primary no-underline\"\n >\n View All\n <ed-icon name=\"chevron_right\" [size]=\"16\" color=\"currentColor\" />\n </a>\n </header>\n\n <ul class=\"m-0 grid max-h-64 list-none content-start gap-xs overflow-x-hidden overflow-y-auto p-0\">\n @for (item of attentionRows(); track item.id) {\n <li>\n <div\n role=\"button\"\n tabindex=\"0\"\n class=\"flex w-full cursor-pointer flex-col gap-xs overflow-hidden rounded-md border border-light bg-white p-sm text-left transition-colors hover:bg-lighter hover:shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-primary\"\n [attr.aria-label]=\"'Open attention item for ' + item.name\"\n (click)=\"openAttention(item)\"\n (keyup.enter)=\"openAttention(item)\"\n >\n <div class=\"flex w-full min-w-0 items-center gap-xs\">\n <div class=\"flex min-w-0 flex-1 items-center gap-xs\">\n <ed-avatar\n shape=\"box\"\n size=\"base\"\n [initials]=\"item.initials\"\n [tone]=\"item.avatarTone\"\n />\n <div class=\"flex min-w-0 flex-1 flex-col gap-2xs\">\n <div class=\"flex min-w-0 items-center gap-2xs\">\n <span class=\"truncate fs-sm font-semibold text-dark\">{{ item.name }}</span>\n <!-- <span class=\"inline-flex shrink-0 text-light\">\n <ed-icon name=\"TagSimple\" [size]=\"14\" color=\"currentColor\" />\n </span> -->\n </div>\n <span class=\"truncate fs-sm text-light\">{{ item.metaLine }}</span>\n </div>\n </div>\n <ed-badge-2 class=\"shrink-0\" variant=\"light\" pill uppercase>\n {{ item.badge }}\n </ed-badge-2>\n </div>\n <div class=\"flex w-full min-w-0 items-center gap-sm\">\n <div class=\"flex min-w-0 flex-1 items-center gap-xs\">\n <span\n class=\"inline-flex size-8 shrink-0 items-center justify-center rounded-md\"\n [class.bg-success-50]=\"item.direction === 'inbound'\"\n [class.text-success]=\"item.direction === 'inbound'\"\n [class.bg-primary-50]=\"item.direction === 'outbound'\"\n [class.text-primary]=\"item.direction === 'outbound'\"\n [smartTooltip]=\"item.directionTitle\"\n >\n <ed-icon [name]=\"item.directionIcon\" [size]=\"16\" color=\"currentColor\" />\n </span>\n <span class=\"min-w-0 flex-1 truncate fs-sm text-light\">{{ item.detail }}</span>\n </div>\n <span class=\"shrink-0 whitespace-nowrap fs-xs text-light\">{{ item.timeLabel }}</span>\n </div>\n </div>\n </li>\n } @empty {\n <li class=\"fs-sm text-light\">Nothing needs attention right now.</li>\n }\n </ul>\n </article>\n </section>\n\n <article class=\"flex flex-col gap-base overflow-hidden rounded-lg border border-light bg-white p-base\">\n <header class=\"flex items-center justify-between gap-xs\">\n <div class=\"flex items-center gap-sm\">\n <h4>Recent Calls</h4>\n <ed-badge-2\n variant=\"light\"\n pill\n [attr.aria-label]=\"'Recent calls count ' + recentHistoryCount()\"\n >\n {{ recentHistoryCount() }}\n </ed-badge-2>\n </div>\n <a\n routerLink=\"../history\"\n class=\"inline-flex items-center gap-2xs fs-sm font-medium text-primary no-underline\"\n >\n View All\n <ed-icon name=\"chevron_right\" [size]=\"16\" color=\"currentColor\" />\n </a>\n </header>\n\n <div class=\"overflow-x-auto bg-white rounded-md\">\n <table class=\"table-default relative min-w-5xl w-full\" aria-label=\"Recent calls\">\n <thead>\n <tr>\n <th>Time</th>\n <th>Patient/Caller</th>\n <th class=\"w-16 text-center\" aria-label=\"Direction\">\n <span class=\"inline-flex items-center justify-center gap-2xs\">\n <ed-icon name=\"call_received\" [size]=\"12\" class=\"text-success\" color=\"currentColor\" />\n <span class=\"text-light\">/</span>\n <ed-icon name=\"call_made\" [size]=\"12\" class=\"text-primary\" color=\"currentColor\" />\n </span>\n </th>\n <th>Goal</th>\n <th>Handled By</th>\n <th>Resolution</th>\n <th>Result</th>\n <th>Duration</th>\n </tr>\n </thead>\n <tbody>\n @for (row of recentHistoryRows(); track row.id) {\n <tr\n class=\"focus-visible:outline focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-primary\"\n tabindex=\"0\"\n role=\"link\"\n [attr.aria-label]=\"'View call details for ' + row.name\"\n (click)=\"openHistoryDetail(row.id)\"\n (keyup.enter)=\"openHistoryDetail(row.id)\"\n >\n <td>\n <div class=\"flex flex-col gap-2xs whitespace-nowrap\">\n @if (row.started) {\n <span class=\"fs-xs font-medium text-light\">{{ row.started | date: 'shortTime' }}</span>\n <span class=\"fs-xs text-light\">{{ row.started | date: 'MMM d, y' }}</span>\n } @else {\n <span class=\"fs-xs font-medium text-light\">{{ row.whenLabel }}</span>\n }\n </div>\n </td>\n\n <td>\n <div class=\"flex min-w-52 items-center gap-xs\">\n <ed-avatar\n shape=\"box\"\n size=\"base\"\n [initials]=\"row.initials\"\n [tone]=\"row.avatarTone\"\n />\n <div class=\"flex min-w-0 flex-col gap-2xs\">\n <div class=\"flex min-w-0 items-center gap-2xs text-dark\">\n <span\n class=\"inline-block min-w-0 max-w-56 truncate fs-sm font-semibold\"\n [smartTooltip]=\"row.name\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ row.name }}</span>\n <!-- <span class=\"inline-flex shrink-0 text-light\">\n <ed-icon name=\"TagSimple\" [size]=\"14\" color=\"currentColor\" />\n </span> -->\n </div>\n <span\n class=\"inline-block min-w-0 max-w-64 truncate fs-xs text-light\"\n [smartTooltip]=\"row.metaLine\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ row.metaLine }}</span>\n </div>\n </div>\n </td>\n\n <td class=\"text-center\">\n <span\n class=\"inline-flex size-5 items-center justify-center rounded\"\n [class.bg-success-50]=\"row.direction === 'inbound'\"\n [class.text-success]=\"row.direction === 'inbound'\"\n [class.bg-primary-50]=\"row.direction === 'outbound'\"\n [class.text-primary]=\"row.direction === 'outbound'\"\n [smartTooltip]=\"row.directionTitle\"\n >\n <ed-icon [name]=\"row.directionIcon\" [size]=\"12\" color=\"currentColor\" />\n </span>\n </td>\n\n <td>\n <span\n class=\"inline-block min-w-0 max-w-56 truncate fs-sm font-medium text-light\"\n [smartTooltip]=\"row.reason\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ row.reason }}</span>\n </td>\n\n <td>\n <ed-badge-2 [attr.variant]=\"row.handledByVariant\" pill uppercase>\n {{ row.handledByLabel }}\n </ed-badge-2>\n </td>\n\n <td>\n @if (row.resolution) {\n <ed-badge-2 [attr.variant]=\"row.resolutionVariant\" pill uppercase>\n {{ row.resolutionLabel }}\n </ed-badge-2>\n }\n </td>\n\n <td>\n <div class=\"flex min-w-0 max-w-80 flex-wrap gap-2xs\">\n @for (chip of row.resultChips; track chip.label) {\n <span\n class=\"inline-flex h-5 max-w-48 min-w-0 items-center gap-2xs rounded bg-light px-2xs fs-xs font-medium text-dark\"\n >\n <ed-icon [name]=\"chip.icon\" [size]=\"12\" color=\"currentColor\" />\n <span\n class=\"min-w-0 truncate\"\n [smartTooltip]=\"chip.label\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ chip.label }}</span>\n </span>\n } @empty {\n <span class=\"fs-sm text-light\">—</span>\n }\n </div>\n </td>\n\n <td class=\"whitespace-nowrap tabular-nums fs-xs font-medium text-light\">\n {{ row.durationLabel }}\n </td>\n </tr>\n } @empty {\n <tr class=\"table-no-data\">\n <td colspan=\"8\" class=\"py-base text-center fs-sm text-light\">No recent calls.</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n </article>\n }\n </div>\n</div>\n"],"names":[],"mappings":"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"}
|