@edvak99/voice-receptionist-widget 1.1.2 → 1.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-analytics-page.component-CW5OKmik.mjs → edvak99-voice-receptionist-widget-analytics-page.component-Dsujn5az.mjs} +4 -4
- package/fesm2022/{edvak99-voice-receptionist-widget-analytics-page.component-CW5OKmik.mjs.map → edvak99-voice-receptionist-widget-analytics-page.component-Dsujn5az.mjs.map} +1 -1
- package/fesm2022/edvak99-voice-receptionist-widget-audit-page.component-xoLlHj8K.mjs +67 -0
- package/fesm2022/edvak99-voice-receptionist-widget-audit-page.component-xoLlHj8K.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-call-history-detail-page.component-CTwfUHUf.mjs → edvak99-voice-receptionist-widget-call-history-detail-page.component-2K9W77As.mjs} +11 -11
- package/fesm2022/{edvak99-voice-receptionist-widget-call-history-detail-page.component-CTwfUHUf.mjs.map → edvak99-voice-receptionist-widget-call-history-detail-page.component-2K9W77As.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-call-history-page.component-Cj4wxd4e.mjs → edvak99-voice-receptionist-widget-call-history-page.component-B5AnEjoh.mjs} +62 -26
- package/fesm2022/edvak99-voice-receptionist-widget-call-history-page.component-B5AnEjoh.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-call-recording-player.component-AN6GcSDq.mjs → edvak99-voice-receptionist-widget-call-recording-player.component-B8_qp7Fe.mjs} +4 -4
- package/fesm2022/{edvak99-voice-receptionist-widget-call-recording-player.component-AN6GcSDq.mjs.map → edvak99-voice-receptionist-widget-call-recording-player.component-B8_qp7Fe.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-call-review.service-Cy_Bf7AO.mjs → edvak99-voice-receptionist-widget-call-review.service-Cj2XTeK4.mjs} +2 -2
- package/fesm2022/{edvak99-voice-receptionist-widget-call-review.service-Cy_Bf7AO.mjs.map → edvak99-voice-receptionist-widget-call-review.service-Cj2XTeK4.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-call-review.util-DQLIw7xb.mjs → edvak99-voice-receptionist-widget-call-review.util-BgsBCKgZ.mjs} +2 -2
- package/fesm2022/{edvak99-voice-receptionist-widget-call-review.util-DQLIw7xb.mjs.map → edvak99-voice-receptionist-widget-call-review.util-BgsBCKgZ.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-dashboard-page.component-DzdIt2A7.mjs → edvak99-voice-receptionist-widget-dashboard-page.component-BNdnbAVM.mjs} +10 -10
- package/fesm2022/{edvak99-voice-receptionist-widget-dashboard-page.component-DzdIt2A7.mjs.map → edvak99-voice-receptionist-widget-dashboard-page.component-BNdnbAVM.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-eds-avatar.component-PCnIWeOA.mjs → edvak99-voice-receptionist-widget-eds-avatar.component-CbphhP6o.mjs} +3 -3
- package/fesm2022/{edvak99-voice-receptionist-widget-eds-avatar.component-PCnIWeOA.mjs.map → edvak99-voice-receptionist-widget-eds-avatar.component-CbphhP6o.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-eds-elapsed.pipe-ouRlPpwT.mjs → edvak99-voice-receptionist-widget-eds-elapsed.pipe-BgLsnq6A.mjs} +2 -2
- package/fesm2022/{edvak99-voice-receptionist-widget-eds-elapsed.pipe-ouRlPpwT.mjs.map → edvak99-voice-receptionist-widget-eds-elapsed.pipe-BgLsnq6A.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-CMhknpGf.mjs → edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-Dn0GrZ6_.mjs} +106 -48
- package/fesm2022/edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-Dn0GrZ6_.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-knowledge-hub.page-cZqBuull.mjs → edvak99-voice-receptionist-widget-knowledge-hub.page-BngGx_Lc.mjs} +70 -36
- package/fesm2022/edvak99-voice-receptionist-widget-knowledge-hub.page-BngGx_Lc.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-live-calls-list.service-CDtFRW8w.mjs → edvak99-voice-receptionist-widget-live-calls-list.service-0kGWO6sh.mjs} +3 -3
- package/fesm2022/{edvak99-voice-receptionist-widget-live-calls-list.service-CDtFRW8w.mjs.map → edvak99-voice-receptionist-widget-live-calls-list.service-0kGWO6sh.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-live-calls-page.component-DrYzXJQW.mjs → edvak99-voice-receptionist-widget-live-calls-page.component-DfLmK89M.mjs} +7 -7
- package/fesm2022/{edvak99-voice-receptionist-widget-live-calls-page.component-DrYzXJQW.mjs.map → edvak99-voice-receptionist-widget-live-calls-page.component-DfLmK89M.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-live-monitor-page.component-D7dlk0y2.mjs → edvak99-voice-receptionist-widget-live-monitor-page.component-DNpLFqBw.mjs} +11 -11
- package/fesm2022/{edvak99-voice-receptionist-widget-live-monitor-page.component-D7dlk0y2.mjs.map → edvak99-voice-receptionist-widget-live-monitor-page.component-DNpLFqBw.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-outbound-purposes-page.component-CJ8NEjcj.mjs → edvak99-voice-receptionist-widget-outbound-purposes-page.component-CYSZ832p.mjs} +6 -6
- package/fesm2022/{edvak99-voice-receptionist-widget-outbound-purposes-page.component-CJ8NEjcj.mjs.map → edvak99-voice-receptionist-widget-outbound-purposes-page.component-CYSZ832p.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-settings-page.component-Bo3XNK3b.mjs → edvak99-voice-receptionist-widget-settings-page.component-B9nv6wtB.mjs} +4 -4
- package/fesm2022/{edvak99-voice-receptionist-widget-settings-page.component-Bo3XNK3b.mjs.map → edvak99-voice-receptionist-widget-settings-page.component-B9nv6wtB.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-tasks-page.component-CBwl15NP.mjs → edvak99-voice-receptionist-widget-tasks-page.component-DXxjMVUv.mjs} +40 -11
- package/fesm2022/edvak99-voice-receptionist-widget-tasks-page.component-DXxjMVUv.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-wizard-page.component-CJLa5pia.mjs → edvak99-voice-receptionist-widget-wizard-page.component-C1Z6yC0q.mjs} +4 -4
- package/fesm2022/{edvak99-voice-receptionist-widget-wizard-page.component-CJLa5pia.mjs.map → edvak99-voice-receptionist-widget-wizard-page.component-C1Z6yC0q.mjs.map} +1 -1
- package/fesm2022/edvak99-voice-receptionist-widget.mjs +1 -1
- package/lib/knowledge/models/practice-faq.model.d.ts +3 -0
- package/lib/knowledge/pages/knowledge-hub.page.d.ts +8 -1
- package/lib/knowledge/services/practice-faq-api.service.d.ts +6 -2
- package/lib/models/ai-receptionist.types.d.ts +1 -0
- package/lib/models/pagination.d.ts +11 -0
- package/lib/pages/audit-page/audit-page.component.d.ts +7 -0
- package/lib/pages/call-history-page/call-history-page.component.d.ts +7 -3
- package/lib/pages/tasks-page/tasks-page.component.d.ts +6 -0
- package/lib/services/ai-receptionist-api.mock.d.ts +10 -9
- package/lib/services/ai-receptionist-api.service.d.ts +9 -9
- package/package.json +1 -1
- package/styles/_index.scss +5 -40
- package/styles/chat-ui.scss +18 -18
- package/styles/eds.scss +135 -95
- package/fesm2022/edvak99-voice-receptionist-widget-audit-page.component-DL1GfQyF.mjs +0 -35
- package/fesm2022/edvak99-voice-receptionist-widget-audit-page.component-DL1GfQyF.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-call-history-page.component-Cj4wxd4e.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-CMhknpGf.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-knowledge-hub.page-cZqBuull.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-tasks-page.component-CBwl15NP.mjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"edvak99-voice-receptionist-widget-live-monitor-page.component-D7dlk0y2.mjs","sources":["../../../projects/voice-receptionist-widget/src/lib/models/live-transcript.types.ts","../../../projects/voice-receptionist-widget/src/lib/services/live-transcript.service.ts","../../../projects/voice-receptionist-widget/src/lib/ui/eds-waveform.component.ts","../../../projects/voice-receptionist-widget/src/lib/components/live-transcript-panel/live-transcript-panel.component.ts","../../../projects/voice-receptionist-widget/src/lib/components/live-transcript-panel/live-transcript-panel.component.html","../../../projects/voice-receptionist-widget/src/lib/pages/live-monitor-page/live-monitor-page.component.ts","../../../projects/voice-receptionist-widget/src/lib/pages/live-monitor-page/live-monitor-page.component.html"],"sourcesContent":["import { ToolEvent, TranscriptLine } from './ai-receptionist.types';\nimport { resolveToolDisplayName, resolveToolKey } from '../utils/tool-labels.util';\n\n/** Socket.io `new_chunk` payload from /dashboard namespace */\nexport interface TranscriptChunk {\n role: 'user' | 'assistant';\n text: string;\n isFinal: boolean;\n timestamp: string;\n}\n\n/** Socket.io `call_event` payload — tools + lifecycle */\nexport interface CallEventStreamPayload {\n eventType: string;\n occurredAt: string;\n payload: Record<string, unknown>;\n}\n\nexport interface LiveTranscriptState {\n lines: TranscriptLine[];\n patientInterim: string | null;\n aiInterim: string | null;\n connected: boolean;\n error: string | null;\n}\n\nexport function mapChunkToLine(chunk: TranscriptChunk): TranscriptLine {\n const at = Date.parse(chunk.timestamp);\n return {\n who: chunk.role === 'assistant' ? 'ai' : 'patient',\n text: chunk.text,\n at: Number.isFinite(at) ? at : Date.now(),\n };\n}\n\nexport function formatEventTime(iso: string): string {\n return new Date(iso).toLocaleTimeString('en-US', {\n hour: 'numeric',\n minute: '2-digit',\n second: '2-digit',\n hour12: false,\n });\n}\n\nexport function mapCallEventToTool(event: CallEventStreamPayload): ToolEvent {\n const p = event.payload;\n const state = p['state'];\n const rawName = String(p['name'] ?? event.eventType.replace(/^tool_/, ''));\n const tech = String(p['tech'] ?? event.eventType);\n const key = resolveToolKey(\n p['key'] != null ? String(p['key']) : undefined,\n rawName,\n tech,\n );\n return {\n t: formatEventTime(event.occurredAt),\n key,\n name: resolveToolDisplayName(key, rawName),\n tech,\n result: String(p['result'] ?? ''),\n state:\n state === 'ok' || state === 'warn' || state === 'error' || state === 'active'\n ? state\n : 'ok',\n };\n}\n\nexport function mapLifecycleEventToTool(event: CallEventStreamPayload): ToolEvent {\n const p = event.payload;\n return {\n t: formatEventTime(event.occurredAt),\n name: event.eventType.replace(/_/g, ' '),\n tech: event.eventType,\n result: String(p['detail'] ?? p['message'] ?? p['result'] ?? ''),\n state: 'ok',\n };\n}\n\nexport function isDuplicateTranscriptLine(lines: TranscriptLine[], line: TranscriptLine): boolean {\n return lines.some((l) => l.who === line.who && l.text.trim() === line.text.trim());\n}\n","import { Injectable, inject, signal } from '@angular/core';\n\nimport { VOICE_RECEPTIONIST_CONFIG } from '../config';\nimport { ToolEvent, TranscriptLine } from '../models/ai-receptionist.types';\nimport {\n CallEventStreamPayload,\n isDuplicateTranscriptLine,\n mapCallEventToTool,\n mapChunkToLine,\n mapLifecycleEventToTool,\n TranscriptChunk,\n} from '../models/live-transcript.types';\nimport { DashboardSocketService } from './dashboard-socket.service';\n\n/**\n * Live call stream over shared Socket.io (`/dashboard` namespace).\n * REST seeds transcript/tools once; socket delivers `new_chunk` + `call_event`.\n */\n@Injectable({ providedIn: 'root' })\nexport class LiveTranscriptService {\n private readonly socket = inject(DashboardSocketService);\n private readonly config = inject(VOICE_RECEPTIONIST_CONFIG);\n\n readonly lines = signal<TranscriptLine[]>([]);\n readonly patientInterim = signal<string | null>(null);\n readonly aiInterim = signal<string | null>(null);\n readonly tools = signal<ToolEvent[]>([]);\n readonly connected = this.socket.connected;\n readonly error = signal<string | null>(null);\n readonly callEnded = signal(false);\n readonly summaryRequested = signal(false);\n\n private activeCallId: string | null = null;\n private watching = false;\n private mockTimer: ReturnType<typeof setInterval> | null = null;\n private mockIndex = 0;\n\n private readonly chunkHandler = (chunk: TranscriptChunk) => this.handleChunk(chunk);\n private readonly eventHandler = (event: CallEventStreamPayload) => this.handleCallEvent(event);\n private readonly onSocketConnect = () => {\n if (this.activeCallId) {\n this.socket.emit('watch_call', { callId: this.activeCallId });\n }\n };\n\n seed(transcript: TranscriptLine[], toolEvents: ToolEvent[]): void {\n this.lines.set(transcript.map((line) => ({ ...line })));\n this.tools.set(toolEvents.map((tool) => ({ ...tool })));\n }\n\n watch(callId: string, live = true): void {\n const id = callId.trim();\n if (!id || !live) return;\n\n const switchingCall = this.activeCallId !== id;\n if (switchingCall) {\n this.unsubscribeSocketEvents();\n this.clearInterim();\n this.callEnded.set(false);\n this.summaryRequested.set(false);\n this.activeCallId = id;\n } else if (this.watching) {\n return;\n }\n\n if (this.config.useMockApi) {\n this.watching = true;\n this.startMockStream(id);\n return;\n }\n\n if (!this.watching) {\n this.socket.acquire();\n this.socket.on('new_chunk', this.chunkHandler);\n this.socket.on('call_event', this.eventHandler);\n this.socket.onConnect(this.onSocketConnect);\n this.watching = true;\n }\n\n if (this.socket.connected()) {\n this.socket.emit('watch_call', { callId: id });\n }\n }\n\n stop(): void {\n this.activeCallId = null;\n this.unsubscribeSocketEvents();\n this.resetStreamState();\n }\n\n markCompleted(): void {\n this.callEnded.set(true);\n this.unsubscribeSocketEvents();\n this.clearInterim();\n }\n\n private unsubscribeSocketEvents(): void {\n this.stopMockStream();\n if (!this.watching) return;\n\n this.socket.off('new_chunk', this.chunkHandler);\n this.socket.off('call_event', this.eventHandler);\n this.socket.offConnect(this.onSocketConnect);\n this.socket.release();\n this.watching = false;\n }\n\n private handleChunk(chunk: TranscriptChunk): void {\n if (!chunk?.text?.trim()) return;\n\n if (chunk.role === 'user') {\n if (chunk.isFinal) {\n this.patientInterim.set(null);\n this.appendLineIfNew(mapChunkToLine(chunk));\n } else {\n this.patientInterim.set(chunk.text);\n }\n return;\n }\n\n if (chunk.isFinal) {\n this.aiInterim.set(null);\n this.appendLineIfNew(mapChunkToLine(chunk));\n } else {\n this.aiInterim.set(chunk.text);\n }\n }\n\n private handleCallEvent(event: CallEventStreamPayload): void {\n if (!event?.eventType) return;\n\n if (event.eventType.startsWith('tool_')) {\n this.tools.update((prev) => [...prev, mapCallEventToTool(event)]);\n return;\n }\n\n if (event.eventType === 'call_completed') {\n this.markCompleted();\n return;\n }\n\n if (event.eventType === 'summary_generated') {\n this.summaryRequested.set(true);\n return;\n }\n\n this.tools.update((prev) => [...prev, mapLifecycleEventToTool(event)]);\n }\n\n private appendLineIfNew(line: TranscriptLine): void {\n this.lines.update((prev) => {\n if (isDuplicateTranscriptLine(prev, line)) return prev;\n return [...prev, line];\n });\n }\n\n private startMockStream(callId: string): void {\n this.stopMockStream();\n this.mockIndex = 0;\n\n const mockChunks: TranscriptChunk[] = [\n {\n role: 'user',\n text: 'Hi, I need to schedule an appointment.',\n isFinal: false,\n timestamp: new Date().toISOString(),\n },\n {\n role: 'user',\n text: 'Hi, I need to schedule an appointment.',\n isFinal: true,\n timestamp: new Date().toISOString(),\n },\n {\n role: 'assistant',\n text: 'Of course — I can help with that. Which provider would you prefer?',\n isFinal: true,\n timestamp: new Date().toISOString(),\n },\n ];\n\n const mockEvents: CallEventStreamPayload[] = [\n {\n eventType: 'tool_check_doctor_availability',\n occurredAt: new Date().toISOString(),\n payload: {\n key: 'check_doctor_availability',\n name: 'Checked Doctor Availability',\n tech: 'tool_check_doctor_availability',\n result: 'Found 3 available time slots',\n state: 'ok',\n },\n },\n ];\n\n this.mockTimer = setInterval(() => {\n if (this.activeCallId !== callId) {\n this.stopMockStream();\n return;\n }\n if (this.mockIndex < mockChunks.length) {\n this.handleChunk(mockChunks[this.mockIndex]);\n this.mockIndex++;\n return;\n }\n if (this.mockIndex === mockChunks.length) {\n this.handleCallEvent(mockEvents[0]);\n this.mockIndex++;\n }\n }, 1500);\n }\n\n private stopMockStream(): void {\n if (this.mockTimer) {\n clearInterval(this.mockTimer);\n this.mockTimer = null;\n }\n }\n\n private clearInterim(): void {\n this.patientInterim.set(null);\n this.aiInterim.set(null);\n }\n\n private resetStreamState(): void {\n this.lines.set([]);\n this.tools.set([]);\n this.clearInterim();\n this.error.set(null);\n this.callEnded.set(false);\n this.summaryRequested.set(false);\n }\n}\n","import { ChangeDetectionStrategy, Component, input } from '@angular/core';\n\n@Component({\n selector: 'eds-waveform',\n standalone: true,\n template: `\n <div\n class=\"eds-waveform\"\n [class.eds-waveform--inactive]=\"!active()\"\n [attr.data-tone]=\"tone()\"\n aria-hidden=\"true\"\n >\n @for (i of bars; track i) {\n <span class=\"eds-waveform__bar\" [style.animation-delay.ms]=\"i * 70\"></span>\n }\n </div>\n `,\n styleUrl: './eds-waveform.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class EdsWaveformComponent {\n readonly active = input(true);\n readonly tone = input<'brand' | 'violet'>('brand');\n\n protected readonly bars = Array.from({ length: 28 }, (_, i) => i);\n}\n","import {\n AfterViewChecked,\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n ViewChild,\n effect,\n inject,\n input,\n output,\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { TranscriptWho } from '../../models/ai-receptionist.types';\nimport { LiveTranscriptService } from '../../services/live-transcript.service';\nimport { EdsIconComponent } from '../../ui/eds-icon.component';\nimport { EdsWaveformComponent } from '../../ui/eds-waveform.component';\n\n@Component({\n selector: 'eds-live-transcript-panel',\n imports: [FormsModule, EdsIconComponent, EdsWaveformComponent],\n templateUrl: './live-transcript-panel.component.html',\n styleUrl: './live-transcript-panel.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class LiveTranscriptPanelComponent implements AfterViewChecked {\n readonly live = input(true);\n readonly paused = input(false);\n readonly humanTakeover = input(false);\n readonly showStaffInput = input(false);\n readonly staffMessage = input('');\n readonly staffMessageChange = output<string>();\n readonly sendMessage = output<void>();\n\n private readonly stream = inject(LiveTranscriptService);\n\n @ViewChild('scrollHost') private scrollHost?: ElementRef<HTMLElement>;\n\n protected readonly lines = this.stream.lines;\n protected readonly patientInterim = this.stream.patientInterim;\n protected readonly aiInterim = this.stream.aiInterim;\n protected readonly connected = this.stream.connected;\n protected readonly error = this.stream.error;\n\n private shouldScroll = false;\n\n constructor() {\n effect(() => {\n this.lines();\n this.patientInterim();\n this.aiInterim();\n this.requestScroll();\n });\n }\n\n ngAfterViewChecked(): void {\n if (this.shouldScroll && this.scrollHost) {\n const el = this.scrollHost.nativeElement;\n el.scrollTop = el.scrollHeight;\n this.shouldScroll = false;\n }\n }\n\n protected waveformActive(): boolean {\n return this.live() && this.connected() && !this.paused();\n }\n\n protected waveformTone(): 'brand' | 'violet' {\n return this.humanTakeover() ? 'violet' : 'brand';\n }\n\n protected recLabel(): string {\n if (this.paused()) return 'PAUSED';\n if (this.live() && this.connected()) return 'REC';\n if (this.error()) return 'ERROR';\n return this.live() ? 'CONNECT' : 'LOG';\n }\n\n protected roleLabel(who: TranscriptWho): string {\n switch (who) {\n case 'ai':\n return 'Ava · AI';\n case 'patient':\n return 'Patient';\n case 'staff':\n return 'Staff';\n default:\n return 'System';\n }\n }\n\n protected speakerIcon(who: TranscriptWho): string {\n switch (who) {\n case 'ai':\n return 'graphic_eq';\n case 'staff':\n return 'support_agent';\n case 'patient':\n return 'person';\n default:\n return 'info';\n }\n }\n\n protected systemIcon(flag?: string): string {\n if (flag === 'verify') return 'verified_user';\n if (flag === 'fail' || flag === 'escalate') return 'bolt';\n return 'info';\n }\n\n protected systemClass(flag?: string): string {\n if (flag === 'verify') return 'live-transcript-panel__system--verify';\n if (flag === 'fail' || flag === 'escalate') return 'live-transcript-panel__system--warn';\n return 'live-transcript-panel__system--info';\n }\n\n protected msgClass(who: TranscriptWho): string {\n return `live-transcript-panel__msg--${who}`;\n }\n\n protected avatarClass(who: TranscriptWho): string {\n return `live-transcript-panel__avatar--${who}`;\n }\n\n protected onStaffInput(value: string): void {\n this.staffMessageChange.emit(value);\n }\n\n protected onSend(): void {\n this.sendMessage.emit();\n }\n\n private requestScroll(): void {\n this.shouldScroll = true;\n }\n}\n","<section class=\"live-transcript-panel\" aria-labelledby=\"live-transcript-title\">\n <header class=\"live-transcript-panel__header\">\n <h2 id=\"live-transcript-title\" class=\"live-transcript-panel__title\">Live transcript</h2>\n <div class=\"live-transcript-panel__rec\">\n <eds-waveform [active]=\"waveformActive()\" [tone]=\"waveformTone()\" />\n <span class=\"live-transcript-panel__rec-label\">{{ recLabel() }}</span>\n </div>\n </header>\n\n <div #scrollHost class=\"live-transcript-panel__scroll\" role=\"log\" aria-live=\"polite\">\n @for (line of lines(); track $index) {\n @if (line.who === 'system') {\n <div class=\"live-transcript-panel__system eds-animate-fade-up\" [class]=\"systemClass(line.flag)\">\n <eds-icon [name]=\"systemIcon(line.flag)\" [size]=\"14\" />\n <span>{{ line.text }}</span>\n </div>\n } @else {\n <article class=\"live-transcript-panel__msg eds-animate-fade-up\" [class]=\"msgClass(line.who)\">\n <div class=\"live-transcript-panel__avatar\" [class]=\"avatarClass(line.who)\">\n <eds-icon [name]=\"speakerIcon(line.who)\" [size]=\"16\" />\n </div>\n <div class=\"live-transcript-panel__content\">\n <span class=\"live-transcript-panel__label\">{{ roleLabel(line.who) }}</span>\n <div class=\"live-transcript-panel__bubble\">\n <p>{{ line.text }}</p>\n </div>\n </div>\n </article>\n }\n }\n\n @if (patientInterim(); as interim) {\n <article class=\"live-transcript-panel__msg live-transcript-panel__msg--patient eds-animate-fade-up\">\n <div class=\"live-transcript-panel__avatar live-transcript-panel__avatar--patient\">\n <eds-icon name=\"person\" [size]=\"16\" />\n </div>\n <div class=\"live-transcript-panel__content\">\n <span class=\"live-transcript-panel__label\">Patient · listening</span>\n <div class=\"live-transcript-panel__bubble live-transcript-panel__bubble--interim\">\n <p>{{ interim }}</p>\n </div>\n </div>\n </article>\n }\n\n @if (aiInterim(); as interim) {\n <article class=\"live-transcript-panel__msg live-transcript-panel__msg--ai eds-animate-fade-up\">\n <div class=\"live-transcript-panel__avatar live-transcript-panel__avatar--ai\">\n <eds-icon name=\"graphic_eq\" [size]=\"16\" />\n </div>\n <div class=\"live-transcript-panel__content\">\n <span class=\"live-transcript-panel__label\">Ava · AI</span>\n <div class=\"live-transcript-panel__bubble live-transcript-panel__bubble--interim\">\n <p>{{ interim }}<span class=\"live-transcript-panel__caret\" aria-hidden=\"true\"></span></p>\n </div>\n </div>\n </article>\n }\n\n @if (lines().length === 0 && !patientInterim() && !aiInterim()) {\n <p class=\"live-transcript-panel__empty\">Waiting for conversation…</p>\n }\n </div>\n\n @if (showStaffInput()) {\n <footer class=\"live-transcript-panel__footer\">\n <input\n type=\"text\"\n class=\"live-transcript-panel__input\"\n placeholder=\"Type to speak as staff…\"\n [ngModel]=\"staffMessage()\"\n (ngModelChange)=\"onStaffInput($event)\"\n (keyup.enter)=\"onSend()\"\n />\n <button type=\"button\" class=\"live-transcript-panel__send\" (click)=\"onSend()\">\n <eds-icon name=\"send\" [size]=\"18\" />\n Send\n </button>\n </footer>\n }\n</section>\n","import {\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n effect,\n inject,\n OnDestroy,\n OnInit,\n signal,\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { ActivatedRoute, RouterLink } from '@angular/router';\nimport { FormsModule } from '@angular/forms';\n\nimport { LiveTranscriptPanelComponent } from '../../components/live-transcript-panel/live-transcript-panel.component';\nimport { CallRecordingPlayerComponent } from '../../components/call-recording-player/call-recording-player.component';\nimport { LiveCall, Sentiment } from '../../models/ai-receptionist.types';\nimport { AiReceptionistApiService } from '../../services/ai-receptionist-api.service';\nimport { LiveTranscriptService } from '../../services/live-transcript.service';\nimport { toolEventTrackKey } from '../../utils/tool-labels.util';\nimport { EdsElapsedPipe } from '../../pipes/eds-elapsed.pipe';\nimport { EdsAvatarComponent } from '../../ui/eds-avatar.component';\nimport { EdsIconComponent } from '../../ui/eds-icon.component';\n\n@Component({\n selector: 'eds-live-monitor-page',\n imports: [\n RouterLink,\n FormsModule,\n EdsAvatarComponent,\n EdsIconComponent,\n EdsElapsedPipe,\n LiveTranscriptPanelComponent,\n CallRecordingPlayerComponent,\n ],\n templateUrl: './live-monitor-page.component.html',\n styleUrl: './live-monitor-page.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class LiveMonitorPageComponent implements OnInit, OnDestroy {\n private readonly api = inject(AiReceptionistApiService);\n private readonly route = inject(ActivatedRoute);\n private readonly stream = inject(LiveTranscriptService);\n private readonly destroyRef = inject(DestroyRef);\n\n protected readonly call = signal<LiveCall | null>(null);\n protected readonly staffMessage = signal('');\n protected readonly loading = signal(true);\n protected readonly callId = signal('');\n protected readonly summary = signal<string | null>(null);\n protected readonly summaryLoading = signal(false);\n\n protected readonly liveTools = this.stream.tools;\n protected readonly callEnded = this.stream.callEnded;\n\n private summaryLoaded = false;\n\n constructor() {\n effect(() => {\n if (this.stream.callEnded()) {\n this.loadCallMetadataOnce();\n }\n });\n\n effect(() => {\n if (this.stream.summaryRequested() && !this.summaryLoaded) {\n this.loadPostCallSummary();\n }\n });\n }\n\n ngOnInit(): void {\n this.route.paramMap.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((params) => {\n const id = params.get('id') ?? '';\n this.callId.set(id);\n this.loading.set(true);\n this.summary.set(null);\n this.summaryLoaded = false;\n this.stream.stop();\n this.loadCallMetadata();\n });\n }\n\n ngOnDestroy(): void {\n this.stream.stop();\n }\n\n protected isTakeover(): boolean {\n const c = this.call();\n return c?.status === 'takeover' || !!c?.assigned;\n }\n\n protected isPaused(): boolean {\n return !!this.call()?.aiPaused;\n }\n\n protected isLive(): boolean {\n return !!this.call() && !this.callEnded();\n }\n\n protected confidenceLevel(confidence: number): 'high' | 'low' | 'mid' {\n if (confidence >= 70) return 'high';\n if (confidence < 50) return 'low';\n return 'mid';\n }\n\n protected sentimentPercent(sentiment: Sentiment): number {\n const map: Record<Sentiment, number> = {\n calm: 85,\n neutral: 60,\n frustrated: 35,\n urgent: 15,\n };\n return map[sentiment];\n }\n\n protected toolStateClass(state: string): string {\n return `live-monitor-page__tool--${state}`;\n }\n\n protected readonly toolTrackKey = toolEventTrackKey;\n\n protected takeover(): void {\n this.api.postTakeover(this.callId()).subscribe(() => this.refreshMetadata());\n }\n\n protected resumeAi(): void {\n this.api.postResumeAi(this.callId()).subscribe(() => this.refreshMetadata());\n }\n\n protected transfer(): void {\n this.api.postTransfer(this.callId()).subscribe(() => this.refreshMetadata());\n }\n\n protected endCall(): void {\n const id = this.callId();\n this.api.postEnd(id).subscribe(() => {\n this.stream.markCompleted();\n this.loadCallMetadataOnce();\n this.loadPostCallSummary();\n });\n }\n\n protected sendMessage(): void {\n const text = this.staffMessage().trim();\n if (!text) return;\n this.api.postMessage(this.callId(), text).subscribe(() => {\n this.staffMessage.set('');\n this.refreshMetadata();\n });\n }\n\n /** Initial load — seeds transcript/tools from REST, then starts socket. */\n private loadCallMetadata(): void {\n const id = this.callId();\n if (!id) return;\n this.api.getLiveCall(id).subscribe(({ data }) => {\n this.call.set(data);\n this.loading.set(false);\n if (data) {\n this.stream.seed(data.transcript, data.tools);\n if (!this.callEnded()) {\n this.stream.watch(id, true);\n }\n }\n });\n }\n\n /** Metadata-only refresh after staff actions — does not overwrite live transcript/tools. */\n private refreshMetadata(): void {\n const id = this.callId();\n if (!id) return;\n this.api.getLiveCall(id).subscribe(({ data }) => {\n if (data) this.call.set(data);\n });\n }\n\n /** One-time metadata refresh after call ends (no socket). */\n private loadCallMetadataOnce(): void {\n const id = this.callId();\n if (!id) return;\n this.api.getLiveCall(id).subscribe(({ data }) => {\n if (data) {\n this.call.set(data);\n }\n });\n }\n\n private loadPostCallSummary(): void {\n const id = this.callId();\n if (!id || this.summaryLoaded) return;\n this.summaryLoading.set(true);\n this.api.getCallSummary(id).subscribe(({ data }) => {\n this.summaryLoading.set(false);\n this.summaryLoaded = true;\n if (!data) return;\n this.summary.set(data.summary);\n this.stream.seed(data.transcript, data.tools);\n });\n }\n}\n","<div class=\"eds-page eds-page--dark live-monitor-page\">\n @if (loading()) {\n <p class=\"live-monitor-page__loading\">Loading call…</p>\n } @else {\n @if (call(); as c) {\n <header class=\"live-monitor-page__header\">\n <a routerLink=\"../live\" class=\"live-monitor-page__back\" aria-label=\"Back to live calls\">\n <eds-icon name=\"arrow_back\" [size]=\"19\" />\n </a>\n\n <div class=\"live-monitor-page__header-main\">\n <eds-avatar\n [initials]=\"c.initials\"\n tone=\"brand\"\n [gradient]=\"c.matched\"\n [class.live-monitor-page__avatar--ring]=\"c.matched\"\n />\n\n <div class=\"live-monitor-page__caller\">\n <div class=\"live-monitor-page__name-row\">\n <h1 class=\"live-monitor-page__name\">{{ c.name }}</h1>\n <span class=\"live-monitor-page__patient-tag\" [attr.data-kind]=\"c.matched ? 'registered' : 'new'\">\n <eds-icon [name]=\"c.matched ? 'person_check' : 'person_add'\" [size]=\"14\" />\n {{ c.matched ? 'Registered' : 'New' }}\n </span>\n </div>\n <div class=\"live-monitor-page__meta-row\">\n <eds-icon [name]=\"c.direction === 'inbound' ? 'call_received' : 'call_made'\" [size]=\"14\" />\n <span>{{ c.phone }}</span>\n <span class=\"live-monitor-page__sep\">·</span>\n <span>{{ c.reason }}</span>\n </div>\n </div>\n\n <div class=\"live-monitor-page__header-right\">\n <span class=\"live-monitor-page__duration\">\n <span class=\"live-monitor-page__duration-dot\" aria-hidden=\"true\"></span>\n {{ c.started | edsElapsed }}\n </span>\n </div>\n </div>\n </header>\n\n @if (callEnded()) {\n <div class=\"live-monitor-page__completed-banner\" role=\"status\">\n <eds-icon name=\"check_circle\" [size]=\"18\" />\n Call ended\n </div>\n }\n\n <div class=\"live-monitor-page__grid\">\n <div class=\"live-monitor-page__main\">\n <eds-live-transcript-panel\n [live]=\"isLive()\"\n [paused]=\"isPaused()\"\n [humanTakeover]=\"isTakeover()\"\n [showStaffInput]=\"isTakeover() && !callEnded()\"\n [staffMessage]=\"staffMessage()\"\n (staffMessageChange)=\"staffMessage.set($event)\"\n (sendMessage)=\"sendMessage()\"\n />\n\n @if (callEnded()) {\n <section class=\"live-monitor-page__post-call\">\n <div class=\"live-monitor-page__summary\">\n <h2 class=\"live-monitor-page__section-title\">Call summary</h2>\n @if (summaryLoading()) {\n <p class=\"live-monitor-page__muted\">Generating summary…</p>\n } @else if (summary()) {\n <p>{{ summary() }}</p>\n } @else {\n <p class=\"live-monitor-page__muted\">Summary will appear when processing completes.</p>\n }\n </div>\n <eds-call-recording-player [callId]=\"callId()\" />\n </section>\n }\n </div>\n\n <aside class=\"live-monitor-page__sidebar\">\n @if (!callEnded()) {\n <div class=\"live-monitor-page__orb-wrap\" [attr.data-mode]=\"c.status === 'transferring' ? 'transfer' : 'ai'\">\n <span class=\"live-monitor-page__ring live-monitor-page__ring--1\"></span>\n <span class=\"live-monitor-page__ring live-monitor-page__ring--2\"></span>\n <span class=\"live-monitor-page__orb\">\n <eds-icon name=\"smart_toy\" [size]=\"28\" />\n </span>\n <span class=\"live-monitor-page__confidence\" [attr.data-level]=\"confidenceLevel(c.confidence)\">\n AI confidence {{ c.confidence }}%\n </span>\n </div>\n\n <section class=\"live-monitor-page__sidebar-block\">\n <h3 class=\"live-monitor-page__section-title\">Patient sentiment</h3>\n <div class=\"live-monitor-page__sentiment-bar\">\n <span\n class=\"live-monitor-page__sentiment-fill\"\n [style.width.%]=\"sentimentPercent(c.sentiment)\"\n [attr.data-sentiment]=\"c.sentiment\"\n ></span>\n </div>\n <span class=\"live-monitor-page__sentiment-label\">{{ c.sentiment }}</span>\n </section>\n }\n\n <section class=\"live-monitor-page__sidebar-block\">\n <h3 class=\"live-monitor-page__section-title\">Tools used</h3>\n <ul class=\"live-monitor-page__tools\">\n @for (tool of liveTools(); track toolTrackKey(tool, $index)) {\n <li [class]=\"toolStateClass(tool.state)\">\n <span class=\"live-monitor-page__tool-time\">{{ tool.t }}</span>\n <div class=\"live-monitor-page__tool-body\">\n <span class=\"live-monitor-page__tool-name\">{{ tool.name }}</span>\n <span class=\"live-monitor-page__tool-result\">{{ tool.result }}</span>\n </div>\n @if (tool.state === 'active') {\n <eds-icon name=\"sync\" [size]=\"16\" class=\"live-monitor-page__tool-spin\" />\n }\n </li>\n } @empty {\n <li class=\"live-monitor-page__tools-empty\">No tool activity yet.</li>\n }\n </ul>\n </section>\n\n <section class=\"live-monitor-page__sidebar-block\">\n <h3 class=\"live-monitor-page__section-title\">Goal</h3>\n <p class=\"live-monitor-page__goal\">{{ c.goal }}</p>\n </section>\n </aside>\n </div>\n\n @if (!callEnded()) {\n <footer class=\"live-monitor-page__control-bar\">\n <div class=\"live-monitor-page__control-group\">\n @if (isTakeover()) {\n <button type=\"button\" class=\"live-monitor-page__ctrl live-monitor-page__ctrl--violet\" (click)=\"resumeAi()\">\n <eds-icon name=\"smart_toy\" [size]=\"18\" /> Resume AI\n </button>\n } @else {\n <button type=\"button\" class=\"live-monitor-page__ctrl live-monitor-page__ctrl--primary\" (click)=\"takeover()\">\n <eds-icon name=\"pan_tool_alt\" [size]=\"18\" /> Take over\n </button>\n }\n <button type=\"button\" class=\"live-monitor-page__ctrl live-monitor-page__ctrl--neutral\" disabled title=\"Coming soon\">\n <eds-icon name=\"hearing\" [size]=\"18\" /> Listen\n </button>\n <button type=\"button\" class=\"live-monitor-page__ctrl live-monitor-page__ctrl--neutral\" (click)=\"transfer()\">\n <eds-icon name=\"phone_forwarded\" [size]=\"18\" /> Transfer\n </button>\n </div>\n\n <span class=\"live-monitor-page__divider\" aria-hidden=\"true\"></span>\n\n <div class=\"live-monitor-page__control-group\">\n <button type=\"button\" class=\"live-monitor-page__ctrl live-monitor-page__ctrl--neutral\" disabled title=\"Coming soon\">\n <eds-icon name=\"person_search\" [size]=\"18\" /> Open chart\n </button>\n <button type=\"button\" class=\"live-monitor-page__ctrl live-monitor-page__ctrl--neutral\" disabled title=\"Coming soon\">\n <eds-icon name=\"add_task\" [size]=\"18\" /> Create task\n </button>\n <button type=\"button\" class=\"live-monitor-page__ctrl live-monitor-page__ctrl--neutral\" disabled title=\"Coming soon\">\n <eds-icon name=\"edit_note\" [size]=\"18\" /> Add note\n </button>\n </div>\n\n <button type=\"button\" class=\"live-monitor-page__ctrl live-monitor-page__ctrl--danger\" (click)=\"endCall()\">\n <eds-icon name=\"call_end\" [size]=\"18\" /> End call\n </button>\n </footer>\n }\n } @else {\n <p class=\"live-monitor-page__loading\">Call ended or not found.</p>\n }\n }\n</div>\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"edvak99-voice-receptionist-widget-live-monitor-page.component-DNpLFqBw.mjs","sources":["../../../projects/voice-receptionist-widget/src/lib/models/live-transcript.types.ts","../../../projects/voice-receptionist-widget/src/lib/services/live-transcript.service.ts","../../../projects/voice-receptionist-widget/src/lib/ui/eds-waveform.component.ts","../../../projects/voice-receptionist-widget/src/lib/components/live-transcript-panel/live-transcript-panel.component.ts","../../../projects/voice-receptionist-widget/src/lib/components/live-transcript-panel/live-transcript-panel.component.html","../../../projects/voice-receptionist-widget/src/lib/pages/live-monitor-page/live-monitor-page.component.ts","../../../projects/voice-receptionist-widget/src/lib/pages/live-monitor-page/live-monitor-page.component.html"],"sourcesContent":["import { ToolEvent, TranscriptLine } from './ai-receptionist.types';\nimport { resolveToolDisplayName, resolveToolKey } from '../utils/tool-labels.util';\n\n/** Socket.io `new_chunk` payload from /dashboard namespace */\nexport interface TranscriptChunk {\n role: 'user' | 'assistant';\n text: string;\n isFinal: boolean;\n timestamp: string;\n}\n\n/** Socket.io `call_event` payload — tools + lifecycle */\nexport interface CallEventStreamPayload {\n eventType: string;\n occurredAt: string;\n payload: Record<string, unknown>;\n}\n\nexport interface LiveTranscriptState {\n lines: TranscriptLine[];\n patientInterim: string | null;\n aiInterim: string | null;\n connected: boolean;\n error: string | null;\n}\n\nexport function mapChunkToLine(chunk: TranscriptChunk): TranscriptLine {\n const at = Date.parse(chunk.timestamp);\n return {\n who: chunk.role === 'assistant' ? 'ai' : 'patient',\n text: chunk.text,\n at: Number.isFinite(at) ? at : Date.now(),\n };\n}\n\nexport function formatEventTime(iso: string): string {\n return new Date(iso).toLocaleTimeString('en-US', {\n hour: 'numeric',\n minute: '2-digit',\n second: '2-digit',\n hour12: false,\n });\n}\n\nexport function mapCallEventToTool(event: CallEventStreamPayload): ToolEvent {\n const p = event.payload;\n const state = p['state'];\n const rawName = String(p['name'] ?? event.eventType.replace(/^tool_/, ''));\n const tech = String(p['tech'] ?? event.eventType);\n const key = resolveToolKey(\n p['key'] != null ? String(p['key']) : undefined,\n rawName,\n tech,\n );\n return {\n t: formatEventTime(event.occurredAt),\n key,\n name: resolveToolDisplayName(key, rawName),\n tech,\n result: String(p['result'] ?? ''),\n state:\n state === 'ok' || state === 'warn' || state === 'error' || state === 'active'\n ? state\n : 'ok',\n };\n}\n\nexport function mapLifecycleEventToTool(event: CallEventStreamPayload): ToolEvent {\n const p = event.payload;\n return {\n t: formatEventTime(event.occurredAt),\n name: event.eventType.replace(/_/g, ' '),\n tech: event.eventType,\n result: String(p['detail'] ?? p['message'] ?? p['result'] ?? ''),\n state: 'ok',\n };\n}\n\nexport function isDuplicateTranscriptLine(lines: TranscriptLine[], line: TranscriptLine): boolean {\n return lines.some((l) => l.who === line.who && l.text.trim() === line.text.trim());\n}\n","import { Injectable, inject, signal } from '@angular/core';\n\nimport { VOICE_RECEPTIONIST_CONFIG } from '../config';\nimport { ToolEvent, TranscriptLine } from '../models/ai-receptionist.types';\nimport {\n CallEventStreamPayload,\n isDuplicateTranscriptLine,\n mapCallEventToTool,\n mapChunkToLine,\n mapLifecycleEventToTool,\n TranscriptChunk,\n} from '../models/live-transcript.types';\nimport { DashboardSocketService } from './dashboard-socket.service';\n\n/**\n * Live call stream over shared Socket.io (`/dashboard` namespace).\n * REST seeds transcript/tools once; socket delivers `new_chunk` + `call_event`.\n */\n@Injectable({ providedIn: 'root' })\nexport class LiveTranscriptService {\n private readonly socket = inject(DashboardSocketService);\n private readonly config = inject(VOICE_RECEPTIONIST_CONFIG);\n\n readonly lines = signal<TranscriptLine[]>([]);\n readonly patientInterim = signal<string | null>(null);\n readonly aiInterim = signal<string | null>(null);\n readonly tools = signal<ToolEvent[]>([]);\n readonly connected = this.socket.connected;\n readonly error = signal<string | null>(null);\n readonly callEnded = signal(false);\n readonly summaryRequested = signal(false);\n\n private activeCallId: string | null = null;\n private watching = false;\n private mockTimer: ReturnType<typeof setInterval> | null = null;\n private mockIndex = 0;\n\n private readonly chunkHandler = (chunk: TranscriptChunk) => this.handleChunk(chunk);\n private readonly eventHandler = (event: CallEventStreamPayload) => this.handleCallEvent(event);\n private readonly onSocketConnect = () => {\n if (this.activeCallId) {\n this.socket.emit('watch_call', { callId: this.activeCallId });\n }\n };\n\n seed(transcript: TranscriptLine[], toolEvents: ToolEvent[]): void {\n this.lines.set(transcript.map((line) => ({ ...line })));\n this.tools.set(toolEvents.map((tool) => ({ ...tool })));\n }\n\n watch(callId: string, live = true): void {\n const id = callId.trim();\n if (!id || !live) return;\n\n const switchingCall = this.activeCallId !== id;\n if (switchingCall) {\n this.unsubscribeSocketEvents();\n this.clearInterim();\n this.callEnded.set(false);\n this.summaryRequested.set(false);\n this.activeCallId = id;\n } else if (this.watching) {\n return;\n }\n\n if (this.config.useMockApi) {\n this.watching = true;\n this.startMockStream(id);\n return;\n }\n\n if (!this.watching) {\n this.socket.acquire();\n this.socket.on('new_chunk', this.chunkHandler);\n this.socket.on('call_event', this.eventHandler);\n this.socket.onConnect(this.onSocketConnect);\n this.watching = true;\n }\n\n if (this.socket.connected()) {\n this.socket.emit('watch_call', { callId: id });\n }\n }\n\n stop(): void {\n this.activeCallId = null;\n this.unsubscribeSocketEvents();\n this.resetStreamState();\n }\n\n markCompleted(): void {\n this.callEnded.set(true);\n this.unsubscribeSocketEvents();\n this.clearInterim();\n }\n\n private unsubscribeSocketEvents(): void {\n this.stopMockStream();\n if (!this.watching) return;\n\n this.socket.off('new_chunk', this.chunkHandler);\n this.socket.off('call_event', this.eventHandler);\n this.socket.offConnect(this.onSocketConnect);\n this.socket.release();\n this.watching = false;\n }\n\n private handleChunk(chunk: TranscriptChunk): void {\n if (!chunk?.text?.trim()) return;\n\n if (chunk.role === 'user') {\n if (chunk.isFinal) {\n this.patientInterim.set(null);\n this.appendLineIfNew(mapChunkToLine(chunk));\n } else {\n this.patientInterim.set(chunk.text);\n }\n return;\n }\n\n if (chunk.isFinal) {\n this.aiInterim.set(null);\n this.appendLineIfNew(mapChunkToLine(chunk));\n } else {\n this.aiInterim.set(chunk.text);\n }\n }\n\n private handleCallEvent(event: CallEventStreamPayload): void {\n if (!event?.eventType) return;\n\n if (event.eventType.startsWith('tool_')) {\n this.tools.update((prev) => [...prev, mapCallEventToTool(event)]);\n return;\n }\n\n if (event.eventType === 'call_completed') {\n this.markCompleted();\n return;\n }\n\n if (event.eventType === 'summary_generated') {\n this.summaryRequested.set(true);\n return;\n }\n\n this.tools.update((prev) => [...prev, mapLifecycleEventToTool(event)]);\n }\n\n private appendLineIfNew(line: TranscriptLine): void {\n this.lines.update((prev) => {\n if (isDuplicateTranscriptLine(prev, line)) return prev;\n return [...prev, line];\n });\n }\n\n private startMockStream(callId: string): void {\n this.stopMockStream();\n this.mockIndex = 0;\n\n const mockChunks: TranscriptChunk[] = [\n {\n role: 'user',\n text: 'Hi, I need to schedule an appointment.',\n isFinal: false,\n timestamp: new Date().toISOString(),\n },\n {\n role: 'user',\n text: 'Hi, I need to schedule an appointment.',\n isFinal: true,\n timestamp: new Date().toISOString(),\n },\n {\n role: 'assistant',\n text: 'Of course — I can help with that. Which provider would you prefer?',\n isFinal: true,\n timestamp: new Date().toISOString(),\n },\n ];\n\n const mockEvents: CallEventStreamPayload[] = [\n {\n eventType: 'tool_check_doctor_availability',\n occurredAt: new Date().toISOString(),\n payload: {\n key: 'check_doctor_availability',\n name: 'Checked Doctor Availability',\n tech: 'tool_check_doctor_availability',\n result: 'Found 3 available time slots',\n state: 'ok',\n },\n },\n ];\n\n this.mockTimer = setInterval(() => {\n if (this.activeCallId !== callId) {\n this.stopMockStream();\n return;\n }\n if (this.mockIndex < mockChunks.length) {\n this.handleChunk(mockChunks[this.mockIndex]);\n this.mockIndex++;\n return;\n }\n if (this.mockIndex === mockChunks.length) {\n this.handleCallEvent(mockEvents[0]);\n this.mockIndex++;\n }\n }, 1500);\n }\n\n private stopMockStream(): void {\n if (this.mockTimer) {\n clearInterval(this.mockTimer);\n this.mockTimer = null;\n }\n }\n\n private clearInterim(): void {\n this.patientInterim.set(null);\n this.aiInterim.set(null);\n }\n\n private resetStreamState(): void {\n this.lines.set([]);\n this.tools.set([]);\n this.clearInterim();\n this.error.set(null);\n this.callEnded.set(false);\n this.summaryRequested.set(false);\n }\n}\n","import { ChangeDetectionStrategy, Component, input } from '@angular/core';\n\n@Component({\n selector: 'eds-waveform',\n standalone: true,\n template: `\n <div\n class=\"eds-waveform\"\n [class.eds-waveform--inactive]=\"!active()\"\n [attr.data-tone]=\"tone()\"\n aria-hidden=\"true\"\n >\n @for (i of bars; track i) {\n <span class=\"eds-waveform__bar\" [style.animation-delay.ms]=\"i * 70\"></span>\n }\n </div>\n `,\n styleUrl: './eds-waveform.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class EdsWaveformComponent {\n readonly active = input(true);\n readonly tone = input<'brand' | 'violet'>('brand');\n\n protected readonly bars = Array.from({ length: 28 }, (_, i) => i);\n}\n","import {\n AfterViewChecked,\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n ViewChild,\n effect,\n inject,\n input,\n output,\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { TranscriptWho } from '../../models/ai-receptionist.types';\nimport { LiveTranscriptService } from '../../services/live-transcript.service';\nimport { EdsIconComponent } from '../../ui/eds-icon.component';\nimport { EdsWaveformComponent } from '../../ui/eds-waveform.component';\n\n@Component({\n selector: 'eds-live-transcript-panel',\n imports: [FormsModule, EdsIconComponent, EdsWaveformComponent],\n templateUrl: './live-transcript-panel.component.html',\n styleUrl: './live-transcript-panel.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class LiveTranscriptPanelComponent implements AfterViewChecked {\n readonly live = input(true);\n readonly paused = input(false);\n readonly humanTakeover = input(false);\n readonly showStaffInput = input(false);\n readonly staffMessage = input('');\n readonly staffMessageChange = output<string>();\n readonly sendMessage = output<void>();\n\n private readonly stream = inject(LiveTranscriptService);\n\n @ViewChild('scrollHost') private scrollHost?: ElementRef<HTMLElement>;\n\n protected readonly lines = this.stream.lines;\n protected readonly patientInterim = this.stream.patientInterim;\n protected readonly aiInterim = this.stream.aiInterim;\n protected readonly connected = this.stream.connected;\n protected readonly error = this.stream.error;\n\n private shouldScroll = false;\n\n constructor() {\n effect(() => {\n this.lines();\n this.patientInterim();\n this.aiInterim();\n this.requestScroll();\n });\n }\n\n ngAfterViewChecked(): void {\n if (this.shouldScroll && this.scrollHost) {\n const el = this.scrollHost.nativeElement;\n el.scrollTop = el.scrollHeight;\n this.shouldScroll = false;\n }\n }\n\n protected waveformActive(): boolean {\n return this.live() && this.connected() && !this.paused();\n }\n\n protected waveformTone(): 'brand' | 'violet' {\n return this.humanTakeover() ? 'violet' : 'brand';\n }\n\n protected recLabel(): string {\n if (this.paused()) return 'PAUSED';\n if (this.live() && this.connected()) return 'REC';\n if (this.error()) return 'ERROR';\n return this.live() ? 'CONNECT' : 'LOG';\n }\n\n protected roleLabel(who: TranscriptWho): string {\n switch (who) {\n case 'ai':\n return 'Ava · AI';\n case 'patient':\n return 'Patient';\n case 'staff':\n return 'Staff';\n default:\n return 'System';\n }\n }\n\n protected speakerIcon(who: TranscriptWho): string {\n switch (who) {\n case 'ai':\n return 'graphic_eq';\n case 'staff':\n return 'support_agent';\n case 'patient':\n return 'person';\n default:\n return 'info';\n }\n }\n\n protected systemIcon(flag?: string): string {\n if (flag === 'verify') return 'verified_user';\n if (flag === 'fail' || flag === 'escalate') return 'bolt';\n return 'info';\n }\n\n protected systemClass(flag?: string): string {\n if (flag === 'verify') return 'live-transcript-panel__system--verify';\n if (flag === 'fail' || flag === 'escalate') return 'live-transcript-panel__system--warn';\n return 'live-transcript-panel__system--info';\n }\n\n protected msgClass(who: TranscriptWho): string {\n return `live-transcript-panel__msg--${who}`;\n }\n\n protected avatarClass(who: TranscriptWho): string {\n return `live-transcript-panel__avatar--${who}`;\n }\n\n protected onStaffInput(value: string): void {\n this.staffMessageChange.emit(value);\n }\n\n protected onSend(): void {\n this.sendMessage.emit();\n }\n\n private requestScroll(): void {\n this.shouldScroll = true;\n }\n}\n","<section class=\"live-transcript-panel\" aria-labelledby=\"live-transcript-title\">\n <header class=\"live-transcript-panel__header\">\n <h2 id=\"live-transcript-title\" class=\"live-transcript-panel__title\">Live transcript</h2>\n <div class=\"live-transcript-panel__rec\">\n <eds-waveform [active]=\"waveformActive()\" [tone]=\"waveformTone()\" />\n <span class=\"live-transcript-panel__rec-label\">{{ recLabel() }}</span>\n </div>\n </header>\n\n <div #scrollHost class=\"live-transcript-panel__scroll\" role=\"log\" aria-live=\"polite\">\n @for (line of lines(); track $index) {\n @if (line.who === 'system') {\n <div class=\"live-transcript-panel__system eds-animate-fade-up\" [class]=\"systemClass(line.flag)\">\n <eds-icon [name]=\"systemIcon(line.flag)\" [size]=\"14\" />\n <span>{{ line.text }}</span>\n </div>\n } @else {\n <article class=\"live-transcript-panel__msg eds-animate-fade-up\" [class]=\"msgClass(line.who)\">\n <div class=\"live-transcript-panel__avatar\" [class]=\"avatarClass(line.who)\">\n <eds-icon [name]=\"speakerIcon(line.who)\" [size]=\"16\" />\n </div>\n <div class=\"live-transcript-panel__content\">\n <span class=\"live-transcript-panel__label\">{{ roleLabel(line.who) }}</span>\n <div class=\"live-transcript-panel__bubble\">\n <p>{{ line.text }}</p>\n </div>\n </div>\n </article>\n }\n }\n\n @if (patientInterim(); as interim) {\n <article class=\"live-transcript-panel__msg live-transcript-panel__msg--patient eds-animate-fade-up\">\n <div class=\"live-transcript-panel__avatar live-transcript-panel__avatar--patient\">\n <eds-icon name=\"person\" [size]=\"16\" />\n </div>\n <div class=\"live-transcript-panel__content\">\n <span class=\"live-transcript-panel__label\">Patient · listening</span>\n <div class=\"live-transcript-panel__bubble live-transcript-panel__bubble--interim\">\n <p>{{ interim }}</p>\n </div>\n </div>\n </article>\n }\n\n @if (aiInterim(); as interim) {\n <article class=\"live-transcript-panel__msg live-transcript-panel__msg--ai eds-animate-fade-up\">\n <div class=\"live-transcript-panel__avatar live-transcript-panel__avatar--ai\">\n <eds-icon name=\"graphic_eq\" [size]=\"16\" />\n </div>\n <div class=\"live-transcript-panel__content\">\n <span class=\"live-transcript-panel__label\">Ava · AI</span>\n <div class=\"live-transcript-panel__bubble live-transcript-panel__bubble--interim\">\n <p>{{ interim }}<span class=\"live-transcript-panel__caret\" aria-hidden=\"true\"></span></p>\n </div>\n </div>\n </article>\n }\n\n @if (lines().length === 0 && !patientInterim() && !aiInterim()) {\n <p class=\"live-transcript-panel__empty\">Waiting for conversation…</p>\n }\n </div>\n\n @if (showStaffInput()) {\n <footer class=\"live-transcript-panel__footer\">\n <input\n type=\"text\"\n class=\"live-transcript-panel__input\"\n placeholder=\"Type to speak as staff…\"\n [ngModel]=\"staffMessage()\"\n (ngModelChange)=\"onStaffInput($event)\"\n (keyup.enter)=\"onSend()\"\n />\n <button type=\"button\" class=\"live-transcript-panel__send\" (click)=\"onSend()\">\n <eds-icon name=\"send\" [size]=\"18\" />\n Send\n </button>\n </footer>\n }\n</section>\n","import {\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n effect,\n inject,\n OnDestroy,\n OnInit,\n signal,\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { ActivatedRoute, RouterLink } from '@angular/router';\nimport { FormsModule } from '@angular/forms';\n\nimport { LiveTranscriptPanelComponent } from '../../components/live-transcript-panel/live-transcript-panel.component';\nimport { CallRecordingPlayerComponent } from '../../components/call-recording-player/call-recording-player.component';\nimport { LiveCall, Sentiment } from '../../models/ai-receptionist.types';\nimport { AiReceptionistApiService } from '../../services/ai-receptionist-api.service';\nimport { LiveTranscriptService } from '../../services/live-transcript.service';\nimport { toolEventTrackKey } from '../../utils/tool-labels.util';\nimport { EdsElapsedPipe } from '../../pipes/eds-elapsed.pipe';\nimport { EdsAvatarComponent } from '../../ui/eds-avatar.component';\nimport { EdsIconComponent } from '../../ui/eds-icon.component';\n\n@Component({\n selector: 'eds-live-monitor-page',\n imports: [\n RouterLink,\n FormsModule,\n EdsAvatarComponent,\n EdsIconComponent,\n EdsElapsedPipe,\n LiveTranscriptPanelComponent,\n CallRecordingPlayerComponent,\n ],\n templateUrl: './live-monitor-page.component.html',\n styleUrl: './live-monitor-page.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class LiveMonitorPageComponent implements OnInit, OnDestroy {\n private readonly api = inject(AiReceptionistApiService);\n private readonly route = inject(ActivatedRoute);\n private readonly stream = inject(LiveTranscriptService);\n private readonly destroyRef = inject(DestroyRef);\n\n protected readonly call = signal<LiveCall | null>(null);\n protected readonly staffMessage = signal('');\n protected readonly loading = signal(true);\n protected readonly callId = signal('');\n protected readonly summary = signal<string | null>(null);\n protected readonly summaryLoading = signal(false);\n\n protected readonly liveTools = this.stream.tools;\n protected readonly callEnded = this.stream.callEnded;\n\n private summaryLoaded = false;\n\n constructor() {\n effect(() => {\n if (this.stream.callEnded()) {\n this.loadCallMetadataOnce();\n }\n });\n\n effect(() => {\n if (this.stream.summaryRequested() && !this.summaryLoaded) {\n this.loadPostCallSummary();\n }\n });\n }\n\n ngOnInit(): void {\n this.route.paramMap.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((params) => {\n const id = params.get('id') ?? '';\n this.callId.set(id);\n this.loading.set(true);\n this.summary.set(null);\n this.summaryLoaded = false;\n this.stream.stop();\n this.loadCallMetadata();\n });\n }\n\n ngOnDestroy(): void {\n this.stream.stop();\n }\n\n protected isTakeover(): boolean {\n const c = this.call();\n return c?.status === 'takeover' || !!c?.assigned;\n }\n\n protected isPaused(): boolean {\n return !!this.call()?.aiPaused;\n }\n\n protected isLive(): boolean {\n return !!this.call() && !this.callEnded();\n }\n\n protected confidenceLevel(confidence: number): 'high' | 'low' | 'mid' {\n if (confidence >= 70) return 'high';\n if (confidence < 50) return 'low';\n return 'mid';\n }\n\n protected sentimentPercent(sentiment: Sentiment): number {\n const map: Record<Sentiment, number> = {\n calm: 85,\n neutral: 60,\n frustrated: 35,\n urgent: 15,\n };\n return map[sentiment];\n }\n\n protected toolStateClass(state: string): string {\n return `live-monitor-page__tool--${state}`;\n }\n\n protected readonly toolTrackKey = toolEventTrackKey;\n\n protected takeover(): void {\n this.api.postTakeover(this.callId()).subscribe(() => this.refreshMetadata());\n }\n\n protected resumeAi(): void {\n this.api.postResumeAi(this.callId()).subscribe(() => this.refreshMetadata());\n }\n\n protected transfer(): void {\n this.api.postTransfer(this.callId()).subscribe(() => this.refreshMetadata());\n }\n\n protected endCall(): void {\n const id = this.callId();\n this.api.postEnd(id).subscribe(() => {\n this.stream.markCompleted();\n this.loadCallMetadataOnce();\n this.loadPostCallSummary();\n });\n }\n\n protected sendMessage(): void {\n const text = this.staffMessage().trim();\n if (!text) return;\n this.api.postMessage(this.callId(), text).subscribe(() => {\n this.staffMessage.set('');\n this.refreshMetadata();\n });\n }\n\n /** Initial load — seeds transcript/tools from REST, then starts socket. */\n private loadCallMetadata(): void {\n const id = this.callId();\n if (!id) return;\n this.api.getLiveCall(id).subscribe(({ data }) => {\n this.call.set(data);\n this.loading.set(false);\n if (data) {\n this.stream.seed(data.transcript, data.tools);\n if (!this.callEnded()) {\n this.stream.watch(id, true);\n }\n }\n });\n }\n\n /** Metadata-only refresh after staff actions — does not overwrite live transcript/tools. */\n private refreshMetadata(): void {\n const id = this.callId();\n if (!id) return;\n this.api.getLiveCall(id).subscribe(({ data }) => {\n if (data) this.call.set(data);\n });\n }\n\n /** One-time metadata refresh after call ends (no socket). */\n private loadCallMetadataOnce(): void {\n const id = this.callId();\n if (!id) return;\n this.api.getLiveCall(id).subscribe(({ data }) => {\n if (data) {\n this.call.set(data);\n }\n });\n }\n\n private loadPostCallSummary(): void {\n const id = this.callId();\n if (!id || this.summaryLoaded) return;\n this.summaryLoading.set(true);\n this.api.getCallSummary(id).subscribe(({ data }) => {\n this.summaryLoading.set(false);\n this.summaryLoaded = true;\n if (!data) return;\n this.summary.set(data.summary);\n this.stream.seed(data.transcript, data.tools);\n });\n }\n}\n","<div class=\"eds-page eds-page--dark live-monitor-page\">\n @if (loading()) {\n <p class=\"live-monitor-page__loading\">Loading call…</p>\n } @else {\n @if (call(); as c) {\n <header class=\"live-monitor-page__header\">\n <a routerLink=\"../live\" class=\"live-monitor-page__back\" aria-label=\"Back to live calls\">\n <eds-icon name=\"arrow_back\" [size]=\"19\" />\n </a>\n\n <div class=\"live-monitor-page__header-main\">\n <eds-avatar\n [initials]=\"c.initials\"\n tone=\"brand\"\n [gradient]=\"c.matched\"\n [class.live-monitor-page__avatar--ring]=\"c.matched\"\n />\n\n <div class=\"live-monitor-page__caller\">\n <div class=\"live-monitor-page__name-row\">\n <h1 class=\"live-monitor-page__name\">{{ c.name }}</h1>\n <span class=\"live-monitor-page__patient-tag\" [attr.data-kind]=\"c.matched ? 'registered' : 'new'\">\n <eds-icon [name]=\"c.matched ? 'person_check' : 'person_add'\" [size]=\"14\" />\n {{ c.matched ? 'Registered' : 'New' }}\n </span>\n </div>\n <div class=\"live-monitor-page__meta-row\">\n <eds-icon [name]=\"c.direction === 'inbound' ? 'call_received' : 'call_made'\" [size]=\"14\" />\n <span>{{ c.phone }}</span>\n <span class=\"live-monitor-page__sep\">·</span>\n <span>{{ c.reason }}</span>\n </div>\n </div>\n\n <div class=\"live-monitor-page__header-right\">\n <span class=\"live-monitor-page__duration\">\n <span class=\"live-monitor-page__duration-dot\" aria-hidden=\"true\"></span>\n {{ c.started | edsElapsed }}\n </span>\n </div>\n </div>\n </header>\n\n @if (callEnded()) {\n <div class=\"live-monitor-page__completed-banner\" role=\"status\">\n <eds-icon name=\"check_circle\" [size]=\"18\" />\n Call ended\n </div>\n }\n\n <div class=\"live-monitor-page__grid\">\n <div class=\"live-monitor-page__main\">\n <eds-live-transcript-panel\n [live]=\"isLive()\"\n [paused]=\"isPaused()\"\n [humanTakeover]=\"isTakeover()\"\n [showStaffInput]=\"isTakeover() && !callEnded()\"\n [staffMessage]=\"staffMessage()\"\n (staffMessageChange)=\"staffMessage.set($event)\"\n (sendMessage)=\"sendMessage()\"\n />\n\n @if (callEnded()) {\n <section class=\"live-monitor-page__post-call\">\n <div class=\"live-monitor-page__summary\">\n <h2 class=\"live-monitor-page__section-title\">Call summary</h2>\n @if (summaryLoading()) {\n <p class=\"live-monitor-page__muted\">Generating summary…</p>\n } @else if (summary()) {\n <p>{{ summary() }}</p>\n } @else {\n <p class=\"live-monitor-page__muted\">Summary will appear when processing completes.</p>\n }\n </div>\n <eds-call-recording-player [callId]=\"callId()\" />\n </section>\n }\n </div>\n\n <aside class=\"live-monitor-page__sidebar\">\n @if (!callEnded()) {\n <div class=\"live-monitor-page__orb-wrap\" [attr.data-mode]=\"c.status === 'transferring' ? 'transfer' : 'ai'\">\n <span class=\"live-monitor-page__ring live-monitor-page__ring--1\"></span>\n <span class=\"live-monitor-page__ring live-monitor-page__ring--2\"></span>\n <span class=\"live-monitor-page__orb\">\n <eds-icon name=\"smart_toy\" [size]=\"28\" />\n </span>\n <span class=\"live-monitor-page__confidence\" [attr.data-level]=\"confidenceLevel(c.confidence)\">\n AI confidence {{ c.confidence }}%\n </span>\n </div>\n\n <section class=\"live-monitor-page__sidebar-block\">\n <h3 class=\"live-monitor-page__section-title\">Patient sentiment</h3>\n <div class=\"live-monitor-page__sentiment-bar\">\n <span\n class=\"live-monitor-page__sentiment-fill\"\n [style.width.%]=\"sentimentPercent(c.sentiment)\"\n [attr.data-sentiment]=\"c.sentiment\"\n ></span>\n </div>\n <span class=\"live-monitor-page__sentiment-label\">{{ c.sentiment }}</span>\n </section>\n }\n\n <section class=\"live-monitor-page__sidebar-block\">\n <h3 class=\"live-monitor-page__section-title\">Tools used</h3>\n <ul class=\"live-monitor-page__tools\">\n @for (tool of liveTools(); track toolTrackKey(tool, $index)) {\n <li [class]=\"toolStateClass(tool.state)\">\n <span class=\"live-monitor-page__tool-time\">{{ tool.t }}</span>\n <div class=\"live-monitor-page__tool-body\">\n <span class=\"live-monitor-page__tool-name\">{{ tool.name }}</span>\n <span class=\"live-monitor-page__tool-result\">{{ tool.result }}</span>\n </div>\n @if (tool.state === 'active') {\n <eds-icon name=\"sync\" [size]=\"16\" class=\"live-monitor-page__tool-spin\" />\n }\n </li>\n } @empty {\n <li class=\"live-monitor-page__tools-empty\">No tool activity yet.</li>\n }\n </ul>\n </section>\n\n <section class=\"live-monitor-page__sidebar-block\">\n <h3 class=\"live-monitor-page__section-title\">Goal</h3>\n <p class=\"live-monitor-page__goal\">{{ c.goal }}</p>\n </section>\n </aside>\n </div>\n\n @if (!callEnded()) {\n <footer class=\"live-monitor-page__control-bar\">\n <div class=\"live-monitor-page__control-group\">\n @if (isTakeover()) {\n <button type=\"button\" class=\"live-monitor-page__ctrl live-monitor-page__ctrl--violet\" (click)=\"resumeAi()\">\n <eds-icon name=\"smart_toy\" [size]=\"18\" /> Resume AI\n </button>\n } @else {\n <button type=\"button\" class=\"live-monitor-page__ctrl live-monitor-page__ctrl--primary\" (click)=\"takeover()\">\n <eds-icon name=\"pan_tool_alt\" [size]=\"18\" /> Take over\n </button>\n }\n <button type=\"button\" class=\"live-monitor-page__ctrl live-monitor-page__ctrl--neutral\" disabled title=\"Coming soon\">\n <eds-icon name=\"hearing\" [size]=\"18\" /> Listen\n </button>\n <button type=\"button\" class=\"live-monitor-page__ctrl live-monitor-page__ctrl--neutral\" (click)=\"transfer()\">\n <eds-icon name=\"phone_forwarded\" [size]=\"18\" /> Transfer\n </button>\n </div>\n\n <span class=\"live-monitor-page__divider\" aria-hidden=\"true\"></span>\n\n <div class=\"live-monitor-page__control-group\">\n <button type=\"button\" class=\"live-monitor-page__ctrl live-monitor-page__ctrl--neutral\" disabled title=\"Coming soon\">\n <eds-icon name=\"person_search\" [size]=\"18\" /> Open chart\n </button>\n <button type=\"button\" class=\"live-monitor-page__ctrl live-monitor-page__ctrl--neutral\" disabled title=\"Coming soon\">\n <eds-icon name=\"add_task\" [size]=\"18\" /> Create task\n </button>\n <button type=\"button\" class=\"live-monitor-page__ctrl live-monitor-page__ctrl--neutral\" disabled title=\"Coming soon\">\n <eds-icon name=\"edit_note\" [size]=\"18\" /> Add note\n </button>\n </div>\n\n <button type=\"button\" class=\"live-monitor-page__ctrl live-monitor-page__ctrl--danger\" (click)=\"endCall()\">\n <eds-icon name=\"call_end\" [size]=\"18\" /> End call\n </button>\n </footer>\n }\n } @else {\n <p class=\"live-monitor-page__loading\">Call ended or not found.</p>\n }\n }\n</div>\n"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { inject, EventEmitter, signal, ViewChild, Output, Input, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
3
|
import { RouterLink } from '@angular/router';
|
|
4
|
-
import { A as AiReceptionistApiService,
|
|
4
|
+
import { A as AiReceptionistApiService, i as DEFAULT_PLACEHOLDERS, M as ModalComponent, E as EdsButtonComponent, a as EdsBadgeComponent, b as EdsIconComponent } from './edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-Dn0GrZ6_.mjs';
|
|
5
5
|
import { R as REQUIRED_FIELD_OPTIONS, a as renderOpeningPreview, f as formatRequiredFields } from './edvak99-voice-receptionist-widget-outbound-purpose.util-BQECIuJu.mjs';
|
|
6
6
|
import * as i1 from '@angular/forms';
|
|
7
7
|
import { FormsModule } from '@angular/forms';
|
|
@@ -164,11 +164,11 @@ class OutboundPurposeFormModalComponent {
|
|
|
164
164
|
}
|
|
165
165
|
}
|
|
166
166
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: OutboundPurposeFormModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
167
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: OutboundPurposeFormModalComponent, isStandalone: true, selector: "eds-outbound-purpose-form-modal", inputs: { open: "open", purpose: "purpose" }, outputs: { closed: "closed", saved: "saved" }, viewQueries: [{ propertyName: "templateInput", first: true, predicate: ["templateInput"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "@if (open) {\n <app-modal\n [title]=\"isEdit ? 'Edit outbound purpose' : 'New outbound purpose'\"\n subtitle=\"Configure dialer fields and AI opening script\"\n maxWidth=\"720px\"\n (closed)=\"close()\"\n >\n <form class=\"purpose-form\" (ngSubmit)=\"submit()\" novalidate>\n <div class=\"purpose-form__grid\">\n <label class=\"purpose-form__field purpose-form__field--full\">\n <span class=\"eds-label\">Label <span class=\"purpose-form__req\">*</span></span>\n <input type=\"text\" class=\"purpose-form__input\" [(ngModel)]=\"label\" name=\"label\" required />\n </label>\n\n <label class=\"purpose-form__field purpose-form__field--full\">\n <span class=\"eds-label\">Description</span>\n <input type=\"text\" class=\"purpose-form__input\" [(ngModel)]=\"description\" name=\"description\" />\n </label>\n\n <label class=\"purpose-form__field purpose-form__field--full\">\n <span class=\"eds-label\">Sample opening (plain preview, max 500)</span>\n <textarea\n class=\"purpose-form__textarea\"\n rows=\"3\"\n maxlength=\"500\"\n [(ngModel)]=\"sampleOpening\"\n name=\"sampleOpening\"\n ></textarea>\n <span class=\"purpose-form__hint\">{{ sampleOpening.length }}/500</span>\n </label>\n\n <div class=\"purpose-form__field purpose-form__field--full\">\n <span class=\"eds-label\">Opening template <span class=\"purpose-form__req\">*</span></span>\n <div class=\"purpose-form__chips\">\n @for (chip of placeholders; track chip.token) {\n <button type=\"button\" class=\"purpose-form__chip\" (click)=\"insertPlaceholder(chip.token)\">\n {{ chip.label }}\n </button>\n }\n </div>\n <textarea\n #templateInput\n class=\"purpose-form__textarea\"\n rows=\"4\"\n [(ngModel)]=\"openingTemplate\"\n name=\"openingTemplate\"\n required\n ></textarea>\n </div>\n\n <label class=\"purpose-form__field purpose-form__field--full\">\n <span class=\"eds-label\">Agent context hint</span>\n <textarea\n class=\"purpose-form__textarea\"\n rows=\"2\"\n [(ngModel)]=\"agentContextHint\"\n name=\"agentContextHint\"\n placeholder=\"Optional guidance for the AI after the opening\"\n ></textarea>\n </label>\n\n <fieldset class=\"purpose-form__field purpose-form__field--full\">\n <legend class=\"eds-label\">Required fields</legend>\n <div class=\"purpose-form__checks\">\n @for (opt of fieldOptions; track opt.value) {\n <label class=\"purpose-form__check\">\n <input\n type=\"checkbox\"\n [checked]=\"isRequiredSelected(opt.value)\"\n (change)=\"toggleRequired(opt.value)\"\n />\n {{ opt.label }}\n </label>\n }\n </div>\n </fieldset>\n\n <label class=\"purpose-form__check purpose-form__field--full\">\n <input type=\"checkbox\" [(ngModel)]=\"allowsCustomScript\" name=\"allowsCustomScript\" />\n Allows custom script (dialer shows free-text script field)\n </label>\n\n <label class=\"purpose-form__field\">\n <span class=\"eds-label\">Sort order</span>\n <input type=\"number\" class=\"purpose-form__input\" [(ngModel)]=\"sortOrder\" name=\"sortOrder\" min=\"0\" />\n </label>\n\n @if (isEdit) {\n <label class=\"purpose-form__check\">\n <input type=\"checkbox\" [(ngModel)]=\"isActive\" name=\"isActive\" />\n Active\n </label>\n }\n </div>\n\n <section class=\"purpose-form__preview eds-card\">\n <h3 class=\"eds-label\">Live preview</h3>\n <p class=\"purpose-form__preview-text\">{{ previewText }}</p>\n </section>\n\n @if (error()) {\n <p class=\"purpose-form__error\" role=\"alert\">{{ error() }}</p>\n }\n\n <footer class=\"purpose-form__footer\">\n <eds-button variant=\"secondary\" type=\"button\" (click)=\"close()\" [disabled]=\"saving()\">\n Cancel\n </eds-button>\n <eds-button variant=\"primary\" type=\"submit\" [disabled]=\"saving()\">\n {{ saving() ? 'Saving\u2026' : isEdit ? 'Save changes' : 'Create purpose' }}\n </eds-button>\n </footer>\n </form>\n </app-modal>\n}\n", styles: [".purpose-form{display:flex;flex-direction:column;gap:16px}.purpose-form__grid{display:grid;grid-template-columns:1fr 1fr;gap:12px}.purpose-form__field{display:flex;flex-direction:column;gap:6px}.purpose-form__field--full{grid-column:1/-1}.purpose-form__input,.purpose-form__textarea{padding:8px 10px;border:1px solid var(--border-subtle, #e4e4e7);border-radius:8px;font:inherit}.purpose-form__textarea{resize:vertical;min-height:72px}.purpose-form__hint{font-size:12px;color:var(--text-secondary)}.purpose-form__req{color:#dc2626}.purpose-form__chips{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:6px}.purpose-form__chip{border:1px solid var(--border-subtle, #e4e4e7);background:var(--surface-muted, #f4f4f5);border-radius:999px;padding:4px 10px;font-size:12px;cursor:pointer}.purpose-form__chip:hover{border-color:var(--eds-brand, #6366f1)}.purpose-form__checks{display:grid;grid-template-columns:1fr 1fr;gap:8px}.purpose-form__check{display:flex;align-items:center;gap:8px;font-size:13px}.purpose-form__preview{padding:12px;background:var(--surface-muted, #f8fafc)}.purpose-form__preview-text{margin:8px 0 0;font-size:14px;line-height:1.5;white-space:pre-wrap}.purpose-form__error{color:#b91c1c;font-size:13px;margin:0}.purpose-form__footer{display:flex;justify-content:flex-end;gap:8px}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: ModalComponent, selector: "app-modal", inputs: ["title", "subtitle", "maxWidth"], outputs: ["closed"] }, { kind: "component", type: EdsButtonComponent, selector: "eds-button", inputs: ["variant", "type", "disabled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
167
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: OutboundPurposeFormModalComponent, isStandalone: true, selector: "eds-outbound-purpose-form-modal", inputs: { open: "open", purpose: "purpose" }, outputs: { closed: "closed", saved: "saved" }, viewQueries: [{ propertyName: "templateInput", first: true, predicate: ["templateInput"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "@if (open) {\n <app-modal\n [title]=\"isEdit ? 'Edit outbound purpose' : 'New outbound purpose'\"\n subtitle=\"Configure dialer fields and AI opening script\"\n maxWidth=\"720px\"\n (closed)=\"close()\"\n >\n <form class=\"purpose-form\" (ngSubmit)=\"submit()\" novalidate>\n <div class=\"purpose-form__grid\">\n <label class=\"purpose-form__field purpose-form__field--full\">\n <span class=\"eds-label\">Label <span class=\"purpose-form__req\">*</span></span>\n <input type=\"text\" class=\"purpose-form__input\" [(ngModel)]=\"label\" name=\"label\" required />\n </label>\n\n <label class=\"purpose-form__field purpose-form__field--full\">\n <span class=\"eds-label\">Description</span>\n <input type=\"text\" class=\"purpose-form__input\" [(ngModel)]=\"description\" name=\"description\" />\n </label>\n\n <label class=\"purpose-form__field purpose-form__field--full\">\n <span class=\"eds-label\">Sample opening (plain preview, max 500)</span>\n <textarea\n class=\"purpose-form__textarea\"\n rows=\"3\"\n maxlength=\"500\"\n [(ngModel)]=\"sampleOpening\"\n name=\"sampleOpening\"\n ></textarea>\n <span class=\"purpose-form__hint\">{{ sampleOpening.length }}/500</span>\n </label>\n\n <div class=\"purpose-form__field purpose-form__field--full\">\n <span class=\"eds-label\">Opening template <span class=\"purpose-form__req\">*</span></span>\n <div class=\"purpose-form__chips\">\n @for (chip of placeholders; track chip.token) {\n <button type=\"button\" class=\"purpose-form__chip\" (click)=\"insertPlaceholder(chip.token)\">\n {{ chip.label }}\n </button>\n }\n </div>\n <textarea\n #templateInput\n class=\"purpose-form__textarea\"\n rows=\"4\"\n [(ngModel)]=\"openingTemplate\"\n name=\"openingTemplate\"\n required\n ></textarea>\n </div>\n\n <label class=\"purpose-form__field purpose-form__field--full\">\n <span class=\"eds-label\">Agent context hint</span>\n <textarea\n class=\"purpose-form__textarea\"\n rows=\"2\"\n [(ngModel)]=\"agentContextHint\"\n name=\"agentContextHint\"\n placeholder=\"Optional guidance for the AI after the opening\"\n ></textarea>\n </label>\n\n <fieldset class=\"purpose-form__field purpose-form__field--full\">\n <legend class=\"eds-label\">Required fields</legend>\n <div class=\"purpose-form__checks\">\n @for (opt of fieldOptions; track opt.value) {\n <label class=\"purpose-form__check\">\n <input\n type=\"checkbox\"\n [checked]=\"isRequiredSelected(opt.value)\"\n (change)=\"toggleRequired(opt.value)\"\n />\n {{ opt.label }}\n </label>\n }\n </div>\n </fieldset>\n\n <label class=\"purpose-form__check purpose-form__field--full\">\n <input type=\"checkbox\" [(ngModel)]=\"allowsCustomScript\" name=\"allowsCustomScript\" />\n Allows custom script (dialer shows free-text script field)\n </label>\n\n <label class=\"purpose-form__field\">\n <span class=\"eds-label\">Sort order</span>\n <input type=\"number\" class=\"purpose-form__input\" [(ngModel)]=\"sortOrder\" name=\"sortOrder\" min=\"0\" />\n </label>\n\n @if (isEdit) {\n <label class=\"purpose-form__check\">\n <input type=\"checkbox\" [(ngModel)]=\"isActive\" name=\"isActive\" />\n Active\n </label>\n }\n </div>\n\n <section class=\"purpose-form__preview eds-card\">\n <h3 class=\"eds-label\">Live preview</h3>\n <p class=\"purpose-form__preview-text\">{{ previewText }}</p>\n </section>\n\n @if (error()) {\n <p class=\"purpose-form__error\" role=\"alert\">{{ error() }}</p>\n }\n\n <footer class=\"purpose-form__footer\">\n <eds-button variant=\"secondary\" type=\"button\" (click)=\"close()\" [disabled]=\"saving()\">\n Cancel\n </eds-button>\n <eds-button variant=\"primary\" type=\"submit\" [disabled]=\"saving()\">\n {{ saving() ? 'Saving\u2026' : isEdit ? 'Save changes' : 'Create purpose' }}\n </eds-button>\n </footer>\n </form>\n </app-modal>\n}\n", styles: [".purpose-form{display:flex;flex-direction:column;gap:16px}.purpose-form__grid{display:grid;grid-template-columns:1fr 1fr;gap:12px}.purpose-form__field{display:flex;flex-direction:column;gap:6px}.purpose-form__field--full{grid-column:1/-1}.purpose-form__input,.purpose-form__textarea{padding:8px 10px;border:1px solid var(--eds-border-subtle, #e4e4e7);border-radius:8px;font:inherit}.purpose-form__textarea{resize:vertical;min-height:72px}.purpose-form__hint{font-size:12px;color:var(--eds-text-secondary)}.purpose-form__req{color:#dc2626}.purpose-form__chips{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:6px}.purpose-form__chip{border:1px solid var(--eds-border-subtle, #e4e4e7);background:var(--eds-surface-muted, #f4f4f5);border-radius:999px;padding:4px 10px;font-size:12px;cursor:pointer}.purpose-form__chip:hover{border-color:var(--eds-brand, #6366f1)}.purpose-form__checks{display:grid;grid-template-columns:1fr 1fr;gap:8px}.purpose-form__check{display:flex;align-items:center;gap:8px;font-size:13px}.purpose-form__preview{padding:12px;background:var(--eds-surface-muted, #f8fafc)}.purpose-form__preview-text{margin:8px 0 0;font-size:14px;line-height:1.5;white-space:pre-wrap}.purpose-form__error{color:#b91c1c;font-size:13px;margin:0}.purpose-form__footer{display:flex;justify-content:flex-end;gap:8px}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: ModalComponent, selector: "app-modal", inputs: ["title", "subtitle", "maxWidth"], outputs: ["closed"] }, { kind: "component", type: EdsButtonComponent, selector: "eds-button", inputs: ["variant", "type", "disabled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
168
168
|
}
|
|
169
169
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: OutboundPurposeFormModalComponent, decorators: [{
|
|
170
170
|
type: Component,
|
|
171
|
-
args: [{ selector: 'eds-outbound-purpose-form-modal', imports: [FormsModule, ModalComponent, EdsButtonComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (open) {\n <app-modal\n [title]=\"isEdit ? 'Edit outbound purpose' : 'New outbound purpose'\"\n subtitle=\"Configure dialer fields and AI opening script\"\n maxWidth=\"720px\"\n (closed)=\"close()\"\n >\n <form class=\"purpose-form\" (ngSubmit)=\"submit()\" novalidate>\n <div class=\"purpose-form__grid\">\n <label class=\"purpose-form__field purpose-form__field--full\">\n <span class=\"eds-label\">Label <span class=\"purpose-form__req\">*</span></span>\n <input type=\"text\" class=\"purpose-form__input\" [(ngModel)]=\"label\" name=\"label\" required />\n </label>\n\n <label class=\"purpose-form__field purpose-form__field--full\">\n <span class=\"eds-label\">Description</span>\n <input type=\"text\" class=\"purpose-form__input\" [(ngModel)]=\"description\" name=\"description\" />\n </label>\n\n <label class=\"purpose-form__field purpose-form__field--full\">\n <span class=\"eds-label\">Sample opening (plain preview, max 500)</span>\n <textarea\n class=\"purpose-form__textarea\"\n rows=\"3\"\n maxlength=\"500\"\n [(ngModel)]=\"sampleOpening\"\n name=\"sampleOpening\"\n ></textarea>\n <span class=\"purpose-form__hint\">{{ sampleOpening.length }}/500</span>\n </label>\n\n <div class=\"purpose-form__field purpose-form__field--full\">\n <span class=\"eds-label\">Opening template <span class=\"purpose-form__req\">*</span></span>\n <div class=\"purpose-form__chips\">\n @for (chip of placeholders; track chip.token) {\n <button type=\"button\" class=\"purpose-form__chip\" (click)=\"insertPlaceholder(chip.token)\">\n {{ chip.label }}\n </button>\n }\n </div>\n <textarea\n #templateInput\n class=\"purpose-form__textarea\"\n rows=\"4\"\n [(ngModel)]=\"openingTemplate\"\n name=\"openingTemplate\"\n required\n ></textarea>\n </div>\n\n <label class=\"purpose-form__field purpose-form__field--full\">\n <span class=\"eds-label\">Agent context hint</span>\n <textarea\n class=\"purpose-form__textarea\"\n rows=\"2\"\n [(ngModel)]=\"agentContextHint\"\n name=\"agentContextHint\"\n placeholder=\"Optional guidance for the AI after the opening\"\n ></textarea>\n </label>\n\n <fieldset class=\"purpose-form__field purpose-form__field--full\">\n <legend class=\"eds-label\">Required fields</legend>\n <div class=\"purpose-form__checks\">\n @for (opt of fieldOptions; track opt.value) {\n <label class=\"purpose-form__check\">\n <input\n type=\"checkbox\"\n [checked]=\"isRequiredSelected(opt.value)\"\n (change)=\"toggleRequired(opt.value)\"\n />\n {{ opt.label }}\n </label>\n }\n </div>\n </fieldset>\n\n <label class=\"purpose-form__check purpose-form__field--full\">\n <input type=\"checkbox\" [(ngModel)]=\"allowsCustomScript\" name=\"allowsCustomScript\" />\n Allows custom script (dialer shows free-text script field)\n </label>\n\n <label class=\"purpose-form__field\">\n <span class=\"eds-label\">Sort order</span>\n <input type=\"number\" class=\"purpose-form__input\" [(ngModel)]=\"sortOrder\" name=\"sortOrder\" min=\"0\" />\n </label>\n\n @if (isEdit) {\n <label class=\"purpose-form__check\">\n <input type=\"checkbox\" [(ngModel)]=\"isActive\" name=\"isActive\" />\n Active\n </label>\n }\n </div>\n\n <section class=\"purpose-form__preview eds-card\">\n <h3 class=\"eds-label\">Live preview</h3>\n <p class=\"purpose-form__preview-text\">{{ previewText }}</p>\n </section>\n\n @if (error()) {\n <p class=\"purpose-form__error\" role=\"alert\">{{ error() }}</p>\n }\n\n <footer class=\"purpose-form__footer\">\n <eds-button variant=\"secondary\" type=\"button\" (click)=\"close()\" [disabled]=\"saving()\">\n Cancel\n </eds-button>\n <eds-button variant=\"primary\" type=\"submit\" [disabled]=\"saving()\">\n {{ saving() ? 'Saving\u2026' : isEdit ? 'Save changes' : 'Create purpose' }}\n </eds-button>\n </footer>\n </form>\n </app-modal>\n}\n", styles: [".purpose-form{display:flex;flex-direction:column;gap:16px}.purpose-form__grid{display:grid;grid-template-columns:1fr 1fr;gap:12px}.purpose-form__field{display:flex;flex-direction:column;gap:6px}.purpose-form__field--full{grid-column:1/-1}.purpose-form__input,.purpose-form__textarea{padding:8px 10px;border:1px solid var(--border-subtle, #e4e4e7);border-radius:8px;font:inherit}.purpose-form__textarea{resize:vertical;min-height:72px}.purpose-form__hint{font-size:12px;color:var(--text-secondary)}.purpose-form__req{color:#dc2626}.purpose-form__chips{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:6px}.purpose-form__chip{border:1px solid var(--border-subtle, #e4e4e7);background:var(--surface-muted, #f4f4f5);border-radius:999px;padding:4px 10px;font-size:12px;cursor:pointer}.purpose-form__chip:hover{border-color:var(--eds-brand, #6366f1)}.purpose-form__checks{display:grid;grid-template-columns:1fr 1fr;gap:8px}.purpose-form__check{display:flex;align-items:center;gap:8px;font-size:13px}.purpose-form__preview{padding:12px;background:var(--surface-muted, #f8fafc)}.purpose-form__preview-text{margin:8px 0 0;font-size:14px;line-height:1.5;white-space:pre-wrap}.purpose-form__error{color:#b91c1c;font-size:13px;margin:0}.purpose-form__footer{display:flex;justify-content:flex-end;gap:8px}\n"] }]
|
|
171
|
+
args: [{ selector: 'eds-outbound-purpose-form-modal', imports: [FormsModule, ModalComponent, EdsButtonComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (open) {\n <app-modal\n [title]=\"isEdit ? 'Edit outbound purpose' : 'New outbound purpose'\"\n subtitle=\"Configure dialer fields and AI opening script\"\n maxWidth=\"720px\"\n (closed)=\"close()\"\n >\n <form class=\"purpose-form\" (ngSubmit)=\"submit()\" novalidate>\n <div class=\"purpose-form__grid\">\n <label class=\"purpose-form__field purpose-form__field--full\">\n <span class=\"eds-label\">Label <span class=\"purpose-form__req\">*</span></span>\n <input type=\"text\" class=\"purpose-form__input\" [(ngModel)]=\"label\" name=\"label\" required />\n </label>\n\n <label class=\"purpose-form__field purpose-form__field--full\">\n <span class=\"eds-label\">Description</span>\n <input type=\"text\" class=\"purpose-form__input\" [(ngModel)]=\"description\" name=\"description\" />\n </label>\n\n <label class=\"purpose-form__field purpose-form__field--full\">\n <span class=\"eds-label\">Sample opening (plain preview, max 500)</span>\n <textarea\n class=\"purpose-form__textarea\"\n rows=\"3\"\n maxlength=\"500\"\n [(ngModel)]=\"sampleOpening\"\n name=\"sampleOpening\"\n ></textarea>\n <span class=\"purpose-form__hint\">{{ sampleOpening.length }}/500</span>\n </label>\n\n <div class=\"purpose-form__field purpose-form__field--full\">\n <span class=\"eds-label\">Opening template <span class=\"purpose-form__req\">*</span></span>\n <div class=\"purpose-form__chips\">\n @for (chip of placeholders; track chip.token) {\n <button type=\"button\" class=\"purpose-form__chip\" (click)=\"insertPlaceholder(chip.token)\">\n {{ chip.label }}\n </button>\n }\n </div>\n <textarea\n #templateInput\n class=\"purpose-form__textarea\"\n rows=\"4\"\n [(ngModel)]=\"openingTemplate\"\n name=\"openingTemplate\"\n required\n ></textarea>\n </div>\n\n <label class=\"purpose-form__field purpose-form__field--full\">\n <span class=\"eds-label\">Agent context hint</span>\n <textarea\n class=\"purpose-form__textarea\"\n rows=\"2\"\n [(ngModel)]=\"agentContextHint\"\n name=\"agentContextHint\"\n placeholder=\"Optional guidance for the AI after the opening\"\n ></textarea>\n </label>\n\n <fieldset class=\"purpose-form__field purpose-form__field--full\">\n <legend class=\"eds-label\">Required fields</legend>\n <div class=\"purpose-form__checks\">\n @for (opt of fieldOptions; track opt.value) {\n <label class=\"purpose-form__check\">\n <input\n type=\"checkbox\"\n [checked]=\"isRequiredSelected(opt.value)\"\n (change)=\"toggleRequired(opt.value)\"\n />\n {{ opt.label }}\n </label>\n }\n </div>\n </fieldset>\n\n <label class=\"purpose-form__check purpose-form__field--full\">\n <input type=\"checkbox\" [(ngModel)]=\"allowsCustomScript\" name=\"allowsCustomScript\" />\n Allows custom script (dialer shows free-text script field)\n </label>\n\n <label class=\"purpose-form__field\">\n <span class=\"eds-label\">Sort order</span>\n <input type=\"number\" class=\"purpose-form__input\" [(ngModel)]=\"sortOrder\" name=\"sortOrder\" min=\"0\" />\n </label>\n\n @if (isEdit) {\n <label class=\"purpose-form__check\">\n <input type=\"checkbox\" [(ngModel)]=\"isActive\" name=\"isActive\" />\n Active\n </label>\n }\n </div>\n\n <section class=\"purpose-form__preview eds-card\">\n <h3 class=\"eds-label\">Live preview</h3>\n <p class=\"purpose-form__preview-text\">{{ previewText }}</p>\n </section>\n\n @if (error()) {\n <p class=\"purpose-form__error\" role=\"alert\">{{ error() }}</p>\n }\n\n <footer class=\"purpose-form__footer\">\n <eds-button variant=\"secondary\" type=\"button\" (click)=\"close()\" [disabled]=\"saving()\">\n Cancel\n </eds-button>\n <eds-button variant=\"primary\" type=\"submit\" [disabled]=\"saving()\">\n {{ saving() ? 'Saving\u2026' : isEdit ? 'Save changes' : 'Create purpose' }}\n </eds-button>\n </footer>\n </form>\n </app-modal>\n}\n", styles: [".purpose-form{display:flex;flex-direction:column;gap:16px}.purpose-form__grid{display:grid;grid-template-columns:1fr 1fr;gap:12px}.purpose-form__field{display:flex;flex-direction:column;gap:6px}.purpose-form__field--full{grid-column:1/-1}.purpose-form__input,.purpose-form__textarea{padding:8px 10px;border:1px solid var(--eds-border-subtle, #e4e4e7);border-radius:8px;font:inherit}.purpose-form__textarea{resize:vertical;min-height:72px}.purpose-form__hint{font-size:12px;color:var(--eds-text-secondary)}.purpose-form__req{color:#dc2626}.purpose-form__chips{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:6px}.purpose-form__chip{border:1px solid var(--eds-border-subtle, #e4e4e7);background:var(--eds-surface-muted, #f4f4f5);border-radius:999px;padding:4px 10px;font-size:12px;cursor:pointer}.purpose-form__chip:hover{border-color:var(--eds-brand, #6366f1)}.purpose-form__checks{display:grid;grid-template-columns:1fr 1fr;gap:8px}.purpose-form__check{display:flex;align-items:center;gap:8px;font-size:13px}.purpose-form__preview{padding:12px;background:var(--eds-surface-muted, #f8fafc)}.purpose-form__preview-text{margin:8px 0 0;font-size:14px;line-height:1.5;white-space:pre-wrap}.purpose-form__error{color:#b91c1c;font-size:13px;margin:0}.purpose-form__footer{display:flex;justify-content:flex-end;gap:8px}\n"] }]
|
|
172
172
|
}], propDecorators: { open: [{
|
|
173
173
|
type: Input
|
|
174
174
|
}], purpose: [{
|
|
@@ -248,7 +248,7 @@ class OutboundPurposesPageComponent {
|
|
|
248
248
|
return purpose.isSystem ? 'Deactivate' : 'Delete';
|
|
249
249
|
}
|
|
250
250
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: OutboundPurposesPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
251
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: OutboundPurposesPageComponent, isStandalone: true, selector: "eds-outbound-purposes-page", ngImport: i0, template: "<div class=\"eds-page outbound-purposes-page\">\n <header class=\"outbound-purposes-page__header\">\n <div>\n <a routerLink=\"../settings\" class=\"outbound-purposes-page__back eds-body-sm\">\n <eds-icon name=\"arrow_back\" [size]=\"16\" /> Settings\n </a>\n <h1 class=\"eds-h1\">Outbound Call Purposes</h1>\n <p class=\"eds-body-sm\">Templates that drive outbound dialer fields and AI opening scripts</p>\n </div>\n <eds-button variant=\"primary\" (click)=\"openCreate()\">\n <eds-icon name=\"add\" [size]=\"18\" /> New purpose\n </eds-button>\n </header>\n\n @if (loading()) {\n <p class=\"eds-body-sm\">Loading purposes\u2026</p>\n } @else if (error()) {\n <p class=\"outbound-purposes-page__error eds-body-sm\" role=\"alert\">{{ error() }}</p>\n } @else {\n <article class=\"eds-card outbound-purposes-page__table-card\">\n <table class=\"eds-table\">\n <thead>\n <tr>\n <th>Label</th>\n <th>Description</th>\n <th>Required fields</th>\n <th>System</th>\n <th>Active</th>\n <th>Sort</th>\n <th>Actions</th>\n </tr>\n </thead>\n <tbody>\n @for (p of purposes(); track p.purposeId) {\n <tr>\n <td class=\"eds-body-sm-bold\">{{ p.label }}</td>\n <td class=\"eds-body-sm\">{{ p.description || '\u2014' }}</td>\n <td class=\"eds-body-sm\">{{ formatRequiredFields(p.requiredFields) }}</td>\n <td>\n @if (p.isSystem) {\n <eds-badge tone=\"brand\">System</eds-badge>\n } @else {\n <span class=\"eds-body-sm\">\u2014</span>\n }\n </td>\n <td>\n <label class=\"outbound-purposes-page__toggle\">\n <input\n type=\"checkbox\"\n [checked]=\"p.isActive\"\n (change)=\"toggleActive(p, $any($event.target).checked)\"\n />\n </label>\n </td>\n <td class=\"eds-mono-sm\">{{ p.sortOrder }}</td>\n <td class=\"outbound-purposes-page__actions\">\n <button type=\"button\" class=\"outbound-purposes-page__link\" (click)=\"openEdit(p)\">\n Edit\n </button>\n <button type=\"button\" class=\"outbound-purposes-page__link\" (click)=\"deletePurpose(p)\">\n {{ actionLabel(p) }}\n </button>\n </td>\n </tr>\n } @empty {\n <tr>\n <td colspan=\"7\" class=\"eds-body-sm\">No outbound purposes configured.</td>\n </tr>\n }\n </tbody>\n </table>\n </article>\n }\n\n <eds-outbound-purpose-form-modal\n [open]=\"modalOpen()\"\n [purpose]=\"editing()\"\n (closed)=\"closeModal()\"\n (saved)=\"onSaved()\"\n />\n</div>\n", styles: [".outbound-purposes-page__header{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;margin-bottom:20px}.outbound-purposes-page__back{display:inline-flex;align-items:center;gap:4px;margin-bottom:8px;text-decoration:none;color:var(--text-secondary)}.outbound-purposes-page__table-card{padding:16px;overflow-x:auto}.outbound-purposes-page__toggle input{width:16px;height:16px}.outbound-purposes-page__actions{display:flex;gap:10px;white-space:nowrap}.outbound-purposes-page__link{border:none;background:none;color:var(--eds-brand, #6366f1);font-size:13px;cursor:pointer;padding:0}.outbound-purposes-page__error{color:#b91c1c}\n"], dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: EdsBadgeComponent, selector: "eds-badge", inputs: ["tone"] }, { kind: "component", type: EdsButtonComponent, selector: "eds-button", inputs: ["variant", "type", "disabled"] }, { kind: "component", type: EdsIconComponent, selector: "eds-icon", inputs: ["name", "size", "fill", "weight"] }, { kind: "component", type: OutboundPurposeFormModalComponent, selector: "eds-outbound-purpose-form-modal", inputs: ["open", "purpose"], outputs: ["closed", "saved"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
251
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: OutboundPurposesPageComponent, isStandalone: true, selector: "eds-outbound-purposes-page", ngImport: i0, template: "<div class=\"eds-page outbound-purposes-page\">\n <header class=\"outbound-purposes-page__header\">\n <div>\n <a routerLink=\"../settings\" class=\"outbound-purposes-page__back eds-body-sm\">\n <eds-icon name=\"arrow_back\" [size]=\"16\" /> Settings\n </a>\n <h1 class=\"eds-h1\">Outbound Call Purposes</h1>\n <p class=\"eds-body-sm\">Templates that drive outbound dialer fields and AI opening scripts</p>\n </div>\n <eds-button variant=\"primary\" (click)=\"openCreate()\">\n <eds-icon name=\"add\" [size]=\"18\" /> New purpose\n </eds-button>\n </header>\n\n @if (loading()) {\n <p class=\"eds-body-sm\">Loading purposes\u2026</p>\n } @else if (error()) {\n <p class=\"outbound-purposes-page__error eds-body-sm\" role=\"alert\">{{ error() }}</p>\n } @else {\n <article class=\"eds-card outbound-purposes-page__table-card\">\n <table class=\"eds-table\">\n <thead>\n <tr>\n <th>Label</th>\n <th>Description</th>\n <th>Required fields</th>\n <th>System</th>\n <th>Active</th>\n <th>Sort</th>\n <th>Actions</th>\n </tr>\n </thead>\n <tbody>\n @for (p of purposes(); track p.purposeId) {\n <tr>\n <td class=\"eds-body-sm-bold\">{{ p.label }}</td>\n <td class=\"eds-body-sm\">{{ p.description || '\u2014' }}</td>\n <td class=\"eds-body-sm\">{{ formatRequiredFields(p.requiredFields) }}</td>\n <td>\n @if (p.isSystem) {\n <eds-badge tone=\"brand\">System</eds-badge>\n } @else {\n <span class=\"eds-body-sm\">\u2014</span>\n }\n </td>\n <td>\n <label class=\"outbound-purposes-page__toggle\">\n <input\n type=\"checkbox\"\n [checked]=\"p.isActive\"\n (change)=\"toggleActive(p, $any($event.target).checked)\"\n />\n </label>\n </td>\n <td class=\"eds-mono-sm\">{{ p.sortOrder }}</td>\n <td class=\"outbound-purposes-page__actions\">\n <button type=\"button\" class=\"outbound-purposes-page__link\" (click)=\"openEdit(p)\">\n Edit\n </button>\n <button type=\"button\" class=\"outbound-purposes-page__link\" (click)=\"deletePurpose(p)\">\n {{ actionLabel(p) }}\n </button>\n </td>\n </tr>\n } @empty {\n <tr>\n <td colspan=\"7\" class=\"eds-body-sm\">No outbound purposes configured.</td>\n </tr>\n }\n </tbody>\n </table>\n </article>\n }\n\n <eds-outbound-purpose-form-modal\n [open]=\"modalOpen()\"\n [purpose]=\"editing()\"\n (closed)=\"closeModal()\"\n (saved)=\"onSaved()\"\n />\n</div>\n", styles: [".outbound-purposes-page__header{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;margin-bottom:20px}.outbound-purposes-page__back{display:inline-flex;align-items:center;gap:4px;margin-bottom:8px;text-decoration:none;color:var(--eds-text-secondary)}.outbound-purposes-page__table-card{padding:16px;overflow-x:auto}.outbound-purposes-page__toggle input{width:16px;height:16px}.outbound-purposes-page__actions{display:flex;gap:10px;white-space:nowrap}.outbound-purposes-page__link{border:none;background:none;color:var(--eds-brand, #6366f1);font-size:13px;cursor:pointer;padding:0}.outbound-purposes-page__error{color:#b91c1c}\n"], dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: EdsBadgeComponent, selector: "eds-badge", inputs: ["tone"] }, { kind: "component", type: EdsButtonComponent, selector: "eds-button", inputs: ["variant", "type", "disabled"] }, { kind: "component", type: EdsIconComponent, selector: "eds-icon", inputs: ["name", "size", "fill", "weight"] }, { kind: "component", type: OutboundPurposeFormModalComponent, selector: "eds-outbound-purpose-form-modal", inputs: ["open", "purpose"], outputs: ["closed", "saved"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
252
252
|
}
|
|
253
253
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: OutboundPurposesPageComponent, decorators: [{
|
|
254
254
|
type: Component,
|
|
@@ -258,8 +258,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
258
258
|
EdsButtonComponent,
|
|
259
259
|
EdsIconComponent,
|
|
260
260
|
OutboundPurposeFormModalComponent,
|
|
261
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"eds-page outbound-purposes-page\">\n <header class=\"outbound-purposes-page__header\">\n <div>\n <a routerLink=\"../settings\" class=\"outbound-purposes-page__back eds-body-sm\">\n <eds-icon name=\"arrow_back\" [size]=\"16\" /> Settings\n </a>\n <h1 class=\"eds-h1\">Outbound Call Purposes</h1>\n <p class=\"eds-body-sm\">Templates that drive outbound dialer fields and AI opening scripts</p>\n </div>\n <eds-button variant=\"primary\" (click)=\"openCreate()\">\n <eds-icon name=\"add\" [size]=\"18\" /> New purpose\n </eds-button>\n </header>\n\n @if (loading()) {\n <p class=\"eds-body-sm\">Loading purposes\u2026</p>\n } @else if (error()) {\n <p class=\"outbound-purposes-page__error eds-body-sm\" role=\"alert\">{{ error() }}</p>\n } @else {\n <article class=\"eds-card outbound-purposes-page__table-card\">\n <table class=\"eds-table\">\n <thead>\n <tr>\n <th>Label</th>\n <th>Description</th>\n <th>Required fields</th>\n <th>System</th>\n <th>Active</th>\n <th>Sort</th>\n <th>Actions</th>\n </tr>\n </thead>\n <tbody>\n @for (p of purposes(); track p.purposeId) {\n <tr>\n <td class=\"eds-body-sm-bold\">{{ p.label }}</td>\n <td class=\"eds-body-sm\">{{ p.description || '\u2014' }}</td>\n <td class=\"eds-body-sm\">{{ formatRequiredFields(p.requiredFields) }}</td>\n <td>\n @if (p.isSystem) {\n <eds-badge tone=\"brand\">System</eds-badge>\n } @else {\n <span class=\"eds-body-sm\">\u2014</span>\n }\n </td>\n <td>\n <label class=\"outbound-purposes-page__toggle\">\n <input\n type=\"checkbox\"\n [checked]=\"p.isActive\"\n (change)=\"toggleActive(p, $any($event.target).checked)\"\n />\n </label>\n </td>\n <td class=\"eds-mono-sm\">{{ p.sortOrder }}</td>\n <td class=\"outbound-purposes-page__actions\">\n <button type=\"button\" class=\"outbound-purposes-page__link\" (click)=\"openEdit(p)\">\n Edit\n </button>\n <button type=\"button\" class=\"outbound-purposes-page__link\" (click)=\"deletePurpose(p)\">\n {{ actionLabel(p) }}\n </button>\n </td>\n </tr>\n } @empty {\n <tr>\n <td colspan=\"7\" class=\"eds-body-sm\">No outbound purposes configured.</td>\n </tr>\n }\n </tbody>\n </table>\n </article>\n }\n\n <eds-outbound-purpose-form-modal\n [open]=\"modalOpen()\"\n [purpose]=\"editing()\"\n (closed)=\"closeModal()\"\n (saved)=\"onSaved()\"\n />\n</div>\n", styles: [".outbound-purposes-page__header{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;margin-bottom:20px}.outbound-purposes-page__back{display:inline-flex;align-items:center;gap:4px;margin-bottom:8px;text-decoration:none;color:var(--text-secondary)}.outbound-purposes-page__table-card{padding:16px;overflow-x:auto}.outbound-purposes-page__toggle input{width:16px;height:16px}.outbound-purposes-page__actions{display:flex;gap:10px;white-space:nowrap}.outbound-purposes-page__link{border:none;background:none;color:var(--eds-brand, #6366f1);font-size:13px;cursor:pointer;padding:0}.outbound-purposes-page__error{color:#b91c1c}\n"] }]
|
|
261
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"eds-page outbound-purposes-page\">\n <header class=\"outbound-purposes-page__header\">\n <div>\n <a routerLink=\"../settings\" class=\"outbound-purposes-page__back eds-body-sm\">\n <eds-icon name=\"arrow_back\" [size]=\"16\" /> Settings\n </a>\n <h1 class=\"eds-h1\">Outbound Call Purposes</h1>\n <p class=\"eds-body-sm\">Templates that drive outbound dialer fields and AI opening scripts</p>\n </div>\n <eds-button variant=\"primary\" (click)=\"openCreate()\">\n <eds-icon name=\"add\" [size]=\"18\" /> New purpose\n </eds-button>\n </header>\n\n @if (loading()) {\n <p class=\"eds-body-sm\">Loading purposes\u2026</p>\n } @else if (error()) {\n <p class=\"outbound-purposes-page__error eds-body-sm\" role=\"alert\">{{ error() }}</p>\n } @else {\n <article class=\"eds-card outbound-purposes-page__table-card\">\n <table class=\"eds-table\">\n <thead>\n <tr>\n <th>Label</th>\n <th>Description</th>\n <th>Required fields</th>\n <th>System</th>\n <th>Active</th>\n <th>Sort</th>\n <th>Actions</th>\n </tr>\n </thead>\n <tbody>\n @for (p of purposes(); track p.purposeId) {\n <tr>\n <td class=\"eds-body-sm-bold\">{{ p.label }}</td>\n <td class=\"eds-body-sm\">{{ p.description || '\u2014' }}</td>\n <td class=\"eds-body-sm\">{{ formatRequiredFields(p.requiredFields) }}</td>\n <td>\n @if (p.isSystem) {\n <eds-badge tone=\"brand\">System</eds-badge>\n } @else {\n <span class=\"eds-body-sm\">\u2014</span>\n }\n </td>\n <td>\n <label class=\"outbound-purposes-page__toggle\">\n <input\n type=\"checkbox\"\n [checked]=\"p.isActive\"\n (change)=\"toggleActive(p, $any($event.target).checked)\"\n />\n </label>\n </td>\n <td class=\"eds-mono-sm\">{{ p.sortOrder }}</td>\n <td class=\"outbound-purposes-page__actions\">\n <button type=\"button\" class=\"outbound-purposes-page__link\" (click)=\"openEdit(p)\">\n Edit\n </button>\n <button type=\"button\" class=\"outbound-purposes-page__link\" (click)=\"deletePurpose(p)\">\n {{ actionLabel(p) }}\n </button>\n </td>\n </tr>\n } @empty {\n <tr>\n <td colspan=\"7\" class=\"eds-body-sm\">No outbound purposes configured.</td>\n </tr>\n }\n </tbody>\n </table>\n </article>\n }\n\n <eds-outbound-purpose-form-modal\n [open]=\"modalOpen()\"\n [purpose]=\"editing()\"\n (closed)=\"closeModal()\"\n (saved)=\"onSaved()\"\n />\n</div>\n", styles: [".outbound-purposes-page__header{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;margin-bottom:20px}.outbound-purposes-page__back{display:inline-flex;align-items:center;gap:4px;margin-bottom:8px;text-decoration:none;color:var(--eds-text-secondary)}.outbound-purposes-page__table-card{padding:16px;overflow-x:auto}.outbound-purposes-page__toggle input{width:16px;height:16px}.outbound-purposes-page__actions{display:flex;gap:10px;white-space:nowrap}.outbound-purposes-page__link{border:none;background:none;color:var(--eds-brand, #6366f1);font-size:13px;cursor:pointer;padding:0}.outbound-purposes-page__error{color:#b91c1c}\n"] }]
|
|
262
262
|
}] });
|
|
263
263
|
|
|
264
264
|
export { OutboundPurposesPageComponent };
|
|
265
|
-
//# sourceMappingURL=edvak99-voice-receptionist-widget-outbound-purposes-page.component-
|
|
265
|
+
//# sourceMappingURL=edvak99-voice-receptionist-widget-outbound-purposes-page.component-CYSZ832p.mjs.map
|