@edvak99/voice-receptionist-widget 1.1.8 → 1.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (21) hide show
  1. package/fesm2022/edvak99-voice-receptionist-widget-activities-page.component-DTSc452x.mjs +388 -0
  2. package/fesm2022/edvak99-voice-receptionist-widget-activities-page.component-DTSc452x.mjs.map +1 -0
  3. package/fesm2022/{edvak99-voice-receptionist-widget-call-history-detail-page.component-BuNyPmhn.mjs → edvak99-voice-receptionist-widget-call-history-detail-page.component-BkT3Qfsk.mjs} +3 -3
  4. package/fesm2022/{edvak99-voice-receptionist-widget-call-history-detail-page.component-BuNyPmhn.mjs.map → edvak99-voice-receptionist-widget-call-history-detail-page.component-BkT3Qfsk.mjs.map} +1 -1
  5. package/fesm2022/edvak99-voice-receptionist-widget-settings-page.component-9qSZL9mc.mjs +1059 -0
  6. package/fesm2022/edvak99-voice-receptionist-widget-settings-page.component-9qSZL9mc.mjs.map +1 -0
  7. package/fesm2022/edvak99-voice-receptionist-widget-task-detail-drawer.component-B3KmFJNH.mjs +194 -0
  8. package/fesm2022/edvak99-voice-receptionist-widget-task-detail-drawer.component-B3KmFJNH.mjs.map +1 -0
  9. package/fesm2022/{edvak99-voice-receptionist-widget-tasks-page.component-Dfz-_0Jz.mjs → edvak99-voice-receptionist-widget-tasks-page.component-D4bWKglj.mjs} +5 -181
  10. package/fesm2022/edvak99-voice-receptionist-widget-tasks-page.component-D4bWKglj.mjs.map +1 -0
  11. package/fesm2022/edvak99-voice-receptionist-widget.mjs +5 -5
  12. package/lib/components/task-detail-drawer/task-detail-drawer.component.d.ts +1 -0
  13. package/lib/pages/activities-page/activities-page.component.d.ts +6 -0
  14. package/lib/pages/settings-page/settings-page.component.d.ts +11 -2
  15. package/lib/pages/settings-page/tts-voice-presets.d.ts +2 -0
  16. package/package.json +1 -1
  17. package/fesm2022/edvak99-voice-receptionist-widget-activities-page.component-CtaPoY1k.mjs +0 -344
  18. package/fesm2022/edvak99-voice-receptionist-widget-activities-page.component-CtaPoY1k.mjs.map +0 -1
  19. package/fesm2022/edvak99-voice-receptionist-widget-settings-page.component-CspheAr8.mjs +0 -992
  20. package/fesm2022/edvak99-voice-receptionist-widget-settings-page.component-CspheAr8.mjs.map +0 -1
  21. package/fesm2022/edvak99-voice-receptionist-widget-tasks-page.component-Dfz-_0Jz.mjs.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edvak99-voice-receptionist-widget-settings-page.component-9qSZL9mc.mjs","sources":["../../../projects/voice-receptionist-widget/src/lib/components/knowledge-test-modal/knowledge-test-modal.component.ts","../../../projects/voice-receptionist-widget/src/lib/components/knowledge-test-modal/knowledge-test-modal.component.html","../../../projects/voice-receptionist-widget/src/lib/services/agent-online.service.ts","../../../projects/voice-receptionist-widget/src/lib/pages/settings-page/tts-voice-presets.ts","../../../projects/voice-receptionist-widget/src/lib/pages/settings-page/settings-fields.config.ts","../../../projects/voice-receptionist-widget/src/lib/pages/settings-page/settings-page.component.ts","../../../projects/voice-receptionist-widget/src/lib/pages/settings-page/settings-page.component.html"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n EventEmitter,\n Input,\n OnChanges,\n OnDestroy,\n Output,\n SimpleChanges,\n inject,\n signal,\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { AiReceptionistApiService } from '../../services/ai-receptionist-api.service';\nimport { EdsButtonComponent } from '../../ui/eds-button.component';\nimport { EdsIconComponent } from '../../ui/eds-icon.component';\nimport { ModalComponent } from '../../shared/modal.component';\nimport { ToastService } from '../../shared/toast.service';\n\nconst QUESTION_MAX = 500;\n\n@Component({\n selector: 'eds-knowledge-test-modal',\n imports: [FormsModule, ModalComponent, EdsButtonComponent, EdsIconComponent],\n templateUrl: './knowledge-test-modal.component.html',\n styleUrl: './knowledge-test-modal.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class KnowledgeTestModalComponent implements OnChanges, OnDestroy {\n private readonly api = inject(AiReceptionistApiService);\n private readonly toast = inject(ToastService);\n\n @Input({ required: true }) open = false;\n @Input() whatToSay = '';\n @Input() whatNotToSay = '';\n @Input() voiceId = '';\n @Output() readonly closed = new EventEmitter<void>();\n\n protected readonly questionMax = QUESTION_MAX;\n protected readonly question = signal('');\n protected readonly testing = signal(false);\n protected readonly answer = signal<string | null>(null);\n protected readonly playing = signal(false);\n\n private audio: HTMLAudioElement | null = null;\n private objectUrl: string | null = null;\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes['open'] && this.open) {\n this.question.set('');\n this.answer.set(null);\n this.stopAudio();\n }\n if (changes['open'] && !this.open) {\n this.stopAudio();\n }\n }\n\n ngOnDestroy(): void {\n this.stopAudio();\n }\n\n protected close(): void {\n this.stopAudio();\n this.closed.emit();\n }\n\n protected onQuestionChange(value: string): void {\n this.question.set(value.slice(0, QUESTION_MAX));\n }\n\n protected runTest(): void {\n const q = this.question().trim();\n if (!q || this.testing()) return;\n\n const whatToSay = this.whatToSay.trim();\n const whatNotToSay = this.whatNotToSay.trim();\n if (!whatToSay || !whatNotToSay) {\n this.toast.show(\n 'Fill in both “What to say” and “What not to say” before testing.',\n 'error',\n );\n return;\n }\n\n this.testing.set(true);\n this.answer.set(null);\n this.stopAudio();\n\n this.api\n .testKnowledgeAnswer({\n question: q,\n whatToSay,\n whatNotToSay,\n voiceId: this.voiceId.trim() || undefined,\n })\n .subscribe({\n next: (result) => {\n this.testing.set(false);\n this.answer.set(result.answer);\n this.playAudio(result.audioBlob);\n },\n error: (err: unknown) => {\n this.testing.set(false);\n const message =\n err instanceof Error && err.message.trim()\n ? err.message\n : 'Could not generate a test answer.';\n this.toast.show(message, 'error');\n },\n });\n }\n\n protected replay(): void {\n if (!this.audio) return;\n this.audio.currentTime = 0;\n this.playing.set(true);\n void this.audio.play().catch(() => {\n this.playing.set(false);\n this.toast.show('Could not play audio in this browser.', 'error');\n });\n }\n\n private playAudio(blob: Blob): void {\n this.stopAudio();\n this.objectUrl = URL.createObjectURL(blob);\n const audio = new Audio(this.objectUrl);\n this.audio = audio;\n this.playing.set(true);\n audio.onended = () => this.playing.set(false);\n audio.onerror = () => {\n this.playing.set(false);\n this.toast.show('Could not play audio in this browser.', 'error');\n };\n void audio.play().catch(() => {\n this.playing.set(false);\n this.toast.show('Could not play audio in this browser.', 'error');\n });\n }\n\n private stopAudio(): void {\n if (this.audio) {\n this.audio.pause();\n this.audio.onended = null;\n this.audio.onerror = null;\n this.audio = null;\n }\n if (this.objectUrl) {\n URL.revokeObjectURL(this.objectUrl);\n this.objectUrl = null;\n }\n this.playing.set(false);\n }\n}\n","@if (open) {\n <app-modal\n title=\"Test Knowledge Base\"\n subtitle=\"Ask a sample caller question — hear how the agent answers with your guidance and voice\"\n maxWidth=\"560px\"\n (closed)=\"close()\"\n >\n <form class=\"flex flex-col gap-4\" (ngSubmit)=\"runTest()\" novalidate autocomplete=\"off\">\n <label class=\"flex flex-col gap-2\">\n <span class=\"kb-test__label text-[13px] font-semibold\">\n What might a caller ask? <span class=\"text-[#dc2626]\">*</span>\n </span>\n <textarea\n class=\"kb-test__textarea box-border min-h-[84px] w-full resize-y rounded-lg border px-3 py-3 text-sm leading-[1.45]\"\n rows=\"3\"\n [maxlength]=\"questionMax\"\n [ngModel]=\"question()\"\n (ngModelChange)=\"onQuestionChange($event)\"\n name=\"question\"\n placeholder=\"e.g. What are your Saturday hours? Is parking free?\"\n [disabled]=\"testing()\"\n autocomplete=\"off\"\n ></textarea>\n <span class=\"kb-test__hint self-end text-xs\">{{ question().length }}/{{ questionMax }}</span>\n </label>\n\n @if (answer(); as spoken) {\n <div class=\"kb-test__answer rounded-lg border px-4 py-3\" role=\"status\">\n <div class=\"mb-2 flex items-center gap-2 text-xs font-semibold uppercase tracking-wide\">\n <eds-icon name=\"graphic_eq\" [size]=\"18\" />\n <span>Agent reply</span>\n @if (playing()) {\n <span class=\"kb-test__playing ml-auto font-medium normal-case tracking-normal\">Playing…</span>\n } @else {\n <button type=\"button\" class=\"kb-test__replay ml-auto cursor-pointer border-none bg-transparent px-1 py-1 text-[13px] font-semibold normal-case tracking-normal\" (click)=\"replay()\">\n Replay\n </button>\n }\n </div>\n <p class=\"m-0 text-sm leading-[1.55]\">{{ spoken }}</p>\n </div>\n }\n\n <footer class=\"flex justify-end gap-3 pt-1\">\n <eds-button type=\"button\" variant=\"secondary\" (click)=\"close()\" [disabled]=\"testing()\">\n Close\n </eds-button>\n <eds-button type=\"submit\" variant=\"primary\" [disabled]=\"testing() || !question().trim()\">\n @if (testing()) {\n Generating…\n } @else {\n <eds-icon name=\"play_arrow\" [size]=\"18\" />\n Test\n }\n </eds-button>\n </footer>\n </form>\n </app-modal>\n}\n","import { Injectable, inject, signal } from '@angular/core';\nimport { catchError, finalize, of, switchMap, tap, throwError } from 'rxjs';\n\nimport { AiReceptionistApiService } from './ai-receptionist-api.service';\n\nexport type AgentOnlineKnownState = boolean | null;\n\n/**\n * Shared source of truth for Ava online/offline across topbar + module nav.\n * Always re-fetches GET /status after mutations.\n */\n@Injectable({ providedIn: 'root' })\nexport class AgentOnlineService {\n private readonly api = inject(AiReceptionistApiService);\n\n /** true = online, false = offline, null = unknown / not loaded */\n private readonly _online = signal<AgentOnlineKnownState>(null);\n private readonly _loading = signal(false);\n private readonly _toggling = signal(false);\n private readonly _error = signal<string | null>(null);\n private readonly _readiness = signal<number | null>(null);\n\n readonly online = this._online.asReadonly();\n readonly loading = this._loading.asReadonly();\n readonly toggling = this._toggling.asReadonly();\n readonly error = this._error.asReadonly();\n readonly readiness = this._readiness.asReadonly();\n\n refresh(): void {\n this._loading.set(true);\n this._error.set(null);\n this.api.getStatus().subscribe({\n next: ({ data }) => {\n this._online.set(data.agentOn);\n this._readiness.set(data.readiness);\n this._loading.set(false);\n },\n error: (err: { message?: string }) => {\n this._online.set(null);\n this._error.set(err.message ?? 'Could not load agent status.');\n this._loading.set(false);\n },\n });\n }\n\n /**\n * PUT /agent-online then re-fetch GET /status.\n */\n setOnline(enabled: boolean) {\n this._toggling.set(true);\n this._error.set(null);\n\n return this.api.setAgentOnline(enabled).pipe(\n switchMap(() =>\n this.api.getStatus().pipe(\n catchError((err: { message?: string }) => {\n this._error.set(err.message ?? 'Status refresh failed after toggle.');\n return of(null);\n }),\n ),\n ),\n tap((result) => {\n if (result) {\n this._online.set(result.data.agentOn);\n this._readiness.set(result.data.readiness);\n } else {\n // Toggle likely succeeded; use requested value until refresh works.\n this._online.set(enabled);\n }\n }),\n catchError((err: { message?: string }) => {\n this._error.set(err.message ?? 'Failed to update agent online status.');\n return throwError(() => err);\n }),\n finalize(() => this._toggling.set(false)),\n );\n }\n}\n","/** Curated ElevenLabs voices — keep in sync with backend `tts-voice-presets.ts`. */\n\nexport interface TtsVoicePreset {\n id: string;\n label: string;\n /** Display gender hint next to the voice name. */\n gender: 'M' | 'F';\n}\n\nexport const DEFAULT_TTS_VOICE_ID = '7EzWGsX10sAS4c9m9cPf';\n\nexport const TTS_VOICE_PRESETS: readonly TtsVoicePreset[] = [\n {\n id: '7EzWGsX10sAS4c9m9cPf',\n label: 'Jack John – Conversational and Upbeat',\n gender: 'M',\n },\n {\n id: 'NUjosfEayZAdRcDmcHM8',\n label: 'Madison – Cool, Calm & Conversational',\n gender: 'F',\n },\n {\n id: 'gE0owC0H9C8SzfDyIUtB',\n label: 'Ivanna – Sassy, Condescending and Clear',\n gender: 'F',\n },\n {\n id: 'Uc7anshoV8mdBhDnEZEX',\n label: 'Cecily – Clear and Warm',\n gender: 'F',\n },\n] as const;\n","import { AgentSettings } from '../../models/ai-receptionist.types';\nimport { TTS_VOICE_PRESETS } from './tts-voice-presets';\n\nexport type SettingsSection = Exclude<keyof AgentSettings, 'safety' | 'effectiveWelcomeMessage'>;\n\nexport interface SettingsFieldOption {\n value: string;\n label: string;\n}\n\nexport interface SettingsFieldMeta {\n key: string;\n label: string;\n description: string;\n type: 'text' | 'number' | 'boolean' | 'select';\n options?: SettingsFieldOption[];\n readOnly?: boolean;\n}\n\nexport interface SettingsSectionMeta {\n title: string;\n description: string;\n}\n\nexport const AGENT_TONE_OPTIONS: SettingsFieldOption[] = [\n { value: 'warm_friendly', label: 'Warm & friendly' },\n { value: 'professional', label: 'Professional' },\n { value: 'efficient_brief', label: 'Efficient & brief' },\n { value: 'casual_friendly', label: 'Casual & friendly' },\n];\n\nexport const LANGUAGE_OPTIONS: SettingsFieldOption[] = [\n { value: 'English', label: 'English' },\n { value: 'Spanish', label: 'Spanish' },\n { value: 'Chinese', label: 'Chinese' },\n { value: 'Hindi', label: 'Hindi' },\n { value: 'French', label: 'French' },\n { value: 'German', label: 'German' },\n { value: 'Portuguese', label: 'Portuguese' },\n { value: 'Arabic', label: 'Arabic' },\n { value: 'Korean', label: 'Korean' },\n { value: 'Japanese', label: 'Japanese' },\n];\n\nexport const GREETING_VARIABLES: { key: string; label: string; token: string }[] = [\n { key: 'practiceName', label: 'Practice Name', token: '{{practiceName}}' },\n { key: 'agentName', label: 'Agent Name', token: '{{agentName}}' },\n { key: 'locationName', label: 'Location Name', token: '{{locationName}}' },\n { key: 'businessHours', label: 'Business Hours', token: '{{businessHours}}' },\n];\n\nexport const RETENTION_DAY_OPTIONS: SettingsFieldOption[] = [\n { value: '7', label: '7 days' },\n { value: '14', label: '14 days' },\n { value: '30', label: '30 days' },\n { value: '60', label: '60 days' },\n { value: '90', label: '90 days' },\n { value: '180', label: '180 days' },\n { value: '365', label: '1 year' },\n];\n\nexport const RING_TIMEOUT_OPTIONS: SettingsFieldOption[] = [\n { value: '10', label: '10 sec' },\n { value: '15', label: '15 sec' },\n { value: '20', label: '20 sec' },\n { value: '30', label: '30 sec' },\n { value: '45', label: '45 sec' },\n { value: '60', label: '60 sec' },\n];\n\nexport const MAX_CALL_DURATION_OPTIONS: SettingsFieldOption[] = [\n { value: '3', label: '3 min' },\n { value: '5', label: '5 min' },\n { value: '10', label: '10 min' },\n { value: '15', label: '15 min' },\n { value: '20', label: '20 min' },\n { value: '30', label: '30 min' },\n];\n\nexport const SILENCE_TIMEOUT_OPTIONS: SettingsFieldOption[] = [\n { value: '10', label: '10 seconds' },\n { value: '15', label: '15 seconds' },\n { value: '20', label: '20 seconds' },\n { value: '30', label: '30 seconds' },\n { value: '45', label: '45 seconds' },\n { value: '60', label: '60 seconds' },\n];\n\nexport const AI_ANSWER_MODE_OPTIONS: SettingsFieldOption[] = [\n { value: 'always_first', label: 'Always first' },\n { value: 'ring_then_ai', label: 'Ring staff, then AI' },\n { value: 'ai_backup', label: 'AI as backup only' },\n];\n\nexport const AFTER_HOURS_OPTIONS: SettingsFieldOption[] = [\n { value: 'ai_answers', label: 'AI answers' },\n { value: 'voicemail', label: 'Voicemail' },\n { value: 'transfer', label: 'Transfer to after-hours number' },\n];\n\nexport const DEFAULT_DISCLOSURE_WARNING =\n 'This call may be handled by an automated assistant and could be recorded for quality and training. You can ask to speak with a staff member at any time.';\n\nexport const SETTINGS_SECTION_META: Record<SettingsSection, SettingsSectionMeta> = {\n general: {\n title: 'AI Identity',\n description: 'Name, voice, languages, tone, and inbound greeting.',\n },\n phone: {\n title: 'Phone & Availability',\n description: 'Inbound routing, ring timing, locations, and after-hours behavior.',\n },\n tasks: {\n title: 'Task Rules',\n description: 'When the AI should create staff tasks after a call.',\n },\n scheduling: {\n title: 'Scheduling Rules',\n description: 'Rules for booking and rescheduling appointments.',\n },\n refill: {\n title: 'Medication refills',\n description: 'Refill approval windows and staff review requirements.',\n },\n verify: {\n title: 'Patient Verification',\n description: 'Identity checks before accessing chart or scheduling data.',\n },\n escalation: {\n title: 'Safety Escalation',\n description: 'When to offer a human or transfer to reception.',\n },\n outbound: {\n title: 'Outbound Purpose',\n description: 'Outbound dialer defaults. Purpose templates are managed separately.',\n },\n knowledge: {\n title: 'Knowledge Base',\n description: 'Practice information the AI should share — and topics it must avoid.',\n },\n transcripts: {\n title: 'Data & Compliance',\n description: 'Recording retention, transcripts, and disclosure warnings.',\n },\n advanced: {\n title: 'Advanced',\n description: 'Agent online status and model options.',\n },\n};\n\n/** Entire sections where every field is read-only (including unknown API fields). */\nexport const READ_ONLY_SECTIONS = new Set<SettingsSection>(['verify']);\n\n/** Settings tabs that stay visible but cannot be selected/edited. */\nexport const DISABLED_SETTINGS_TABS = new Set<SettingsSection>(['verify', 'escalation']);\n\n/** Individual fields locked for compliance, telephony, or core agent identity. */\nexport const READ_ONLY_FIELD_KEYS: ReadonlyArray<{ section: SettingsSection; key: string; reason: string }> = [\n { section: 'general', key: 'timezone', reason: 'Practice timezone' },\n { section: 'phone', key: 'mainNumber', reason: 'AI phone number' },\n { section: 'phone', key: 'transferNumber', reason: 'Transfer number' },\n { section: 'tasks', key: 'defaultAssignee', reason: 'Default task assignee' },\n { section: 'outbound', key: 'callerId', reason: 'Outbound caller ID' },\n { section: 'advanced', key: 'modelVersion', reason: 'Voice AI model profile' },\n { section: 'advanced', key: 'debugMode', reason: 'Debug logging' },\n];\n\nconst READ_ONLY_LOOKUP = new Set(\n READ_ONLY_FIELD_KEYS.map(({ section, key }) => `${section}.${key}`),\n);\n\nexport function isFieldReadOnly(section: SettingsSection, key: string): boolean {\n if (READ_ONLY_SECTIONS.has(section)) return true;\n return READ_ONLY_LOOKUP.has(`${section}.${key}`);\n}\n\nexport function readOnlyFieldReason(section: SettingsSection, key: string): string | undefined {\n return READ_ONLY_FIELD_KEYS.find((f) => f.section === section && f.key === key)?.reason;\n}\n\nexport const SETTINGS_FIELDS: Record<SettingsSection, SettingsFieldMeta[]> = {\n general: [\n {\n key: 'agentName',\n label: 'Name',\n description: 'How the assistant introduces itself.',\n type: 'text',\n },\n {\n key: 'ttsVoiceId',\n label: 'Voice',\n description: 'Spoken voice used on phone calls.',\n type: 'select',\n options: TTS_VOICE_PRESETS.map((p) => ({\n value: p.id,\n label: `${p.gender} · ${p.label}`,\n })),\n },\n {\n key: 'languages',\n label: 'Language',\n description: 'Languages the AI can speak on calls.',\n type: 'text',\n },\n {\n key: 'tone',\n label: 'Tone',\n description: 'Conversational style for the AI.',\n type: 'select',\n options: AGENT_TONE_OPTIONS,\n },\n {\n key: 'welcomeMessage',\n label: 'Inbound Greetings',\n description: 'Spoken when a caller connects.',\n type: 'text',\n },\n ],\n phone: [\n {\n key: 'answerMode',\n label: 'AI Answer Mode',\n description: 'When the AI picks up inbound calls.',\n type: 'select',\n options: AI_ANSWER_MODE_OPTIONS,\n },\n {\n key: 'mainNumber',\n label: 'AI Phone Number',\n description: 'Number patients dial for the AI receptionist.',\n type: 'text',\n },\n {\n key: 'transferNumber',\n label: 'Transfer Number',\n description: 'Staff / front-desk number for handoff.',\n type: 'text',\n },\n {\n key: 'ringTimeout',\n label: 'Ringing Time Wait',\n description: 'How long to ring before the AI answers.',\n type: 'select',\n options: RING_TIMEOUT_OPTIONS,\n },\n {\n key: 'createFollowUpTask',\n label: 'Create Follow-up Task',\n description: 'If no one answers in time, the agent auto-creates a high priority task.',\n type: 'boolean',\n },\n {\n key: 'locationIds',\n label: 'Location Handled',\n description: 'Locations this AI receptionist covers.',\n type: 'text',\n },\n {\n key: 'maxCallDurationMin',\n label: 'Max AI Call Duration',\n description: 'Longest call the AI will stay on before wrapping up.',\n type: 'select',\n options: MAX_CALL_DURATION_OPTIONS,\n },\n {\n key: 'silenceTimeoutSec',\n label: 'Silence Timeout',\n description: 'How long silence lasts before the AI prompts or ends.',\n type: 'select',\n options: SILENCE_TIMEOUT_OPTIONS,\n },\n {\n key: 'afterHoursBehavior',\n label: 'After-Hours Behaviour',\n description: 'What happens outside business hours.',\n type: 'select',\n options: AFTER_HOURS_OPTIONS,\n },\n ],\n tasks: [\n {\n key: 'autoCreate',\n label: 'Auto-create tasks',\n description: 'Create a staff task when the AI cannot fully resolve a request.',\n type: 'boolean',\n },\n {\n key: 'defaultAssignee',\n label: 'Default assignee',\n description: 'Team or role new tasks are routed to.',\n type: 'text',\n },\n ],\n scheduling: [\n {\n key: 'leadTimeHours',\n label: 'Minimum lead time (hours)',\n description: 'Earliest bookable slot from now.',\n type: 'number',\n },\n {\n key: 'allowSameDay',\n label: 'Allow same-day booking',\n description: 'Let patients book appointments later today.',\n type: 'boolean',\n },\n ],\n refill: [\n {\n key: 'autoApproveDays',\n label: 'Auto-approve within (days)',\n description: 'Refills due within this window may be auto-approved.',\n type: 'number',\n },\n {\n key: 'requireStaffReview',\n label: 'Require staff review',\n description: 'All refill requests need staff approval before sending to pharmacy.',\n type: 'boolean',\n },\n ],\n verify: [\n {\n key: 'requireDob',\n label: 'Require date of birth',\n description: 'Ask for DOB before lookup or scheduling.',\n type: 'boolean',\n },\n {\n key: 'requireName',\n label: 'Require full name',\n description: 'Ask for patient name during verification.',\n type: 'boolean',\n },\n {\n key: 'maxAttempts',\n label: 'Max verification attempts',\n description: 'After this many failures, offer transfer to staff.',\n type: 'number',\n },\n ],\n escalation: [\n {\n key: 'sentimentThreshold',\n label: 'Sentiment threshold',\n description: 'Escalate when caller sentiment reaches this level (e.g. frustrated).',\n type: 'text',\n },\n {\n key: 'urgentKeywords',\n label: 'Urgent keywords',\n description: 'Comma-separated phrases that trigger immediate escalation.',\n type: 'text',\n },\n ],\n outbound: [\n {\n key: 'enabled',\n label: 'Outbound calls enabled',\n description: 'Allow staff to place outbound calls from the dashboard.',\n type: 'boolean',\n },\n {\n key: 'callerId',\n label: 'Outbound caller ID',\n description: 'Number shown to patients on outbound calls.',\n type: 'text',\n },\n ],\n knowledge: [\n {\n key: 'whatToSay',\n label: 'What to say',\n description: 'Facts and guidance the AI may share with callers.',\n type: 'text',\n },\n {\n key: 'whatNotToSay',\n label: 'What not to say',\n description: 'Topics the AI must refuse or escalate.',\n type: 'text',\n },\n ],\n transcripts: [\n {\n key: 'recordingRetainDays',\n label: 'Keep Call Recordings',\n description: 'How long call recordings are retained.',\n type: 'select',\n options: RETENTION_DAY_OPTIONS,\n },\n {\n key: 'transcriptRetainDays',\n label: 'Keep Transcripts',\n description: 'How long call transcripts are retained.',\n type: 'select',\n options: RETENTION_DAY_OPTIONS,\n },\n {\n key: 'disclosureWarningEnabled',\n label: 'Disclosure Warning',\n description: 'Play or show a disclosure when the AI answers.',\n type: 'boolean',\n },\n {\n key: 'disclosureWarningText',\n label: 'Disclosure text',\n description: 'Spoken or shown disclosure message.',\n type: 'text',\n },\n ],\n advanced: [\n {\n key: 'modelVersion',\n label: 'Model version',\n description: 'Voice AI model profile (set by Edvak support).',\n type: 'text',\n },\n {\n key: 'debugMode',\n label: 'Debug mode',\n description: 'Verbose logging for troubleshooting — not for production.',\n type: 'boolean',\n },\n ],\n};\n\n/** Fallback label for API fields not listed in config. */\nexport function humanizeFieldKey(key: string): string {\n return key\n .replace(/([A-Z])/g, ' $1')\n .replace(/_/g, ' ')\n .trim()\n .replace(/^\\w/, (c) => c.toUpperCase());\n}\n\nexport function resolveFieldMeta(\n section: SettingsSection,\n key: string,\n value: string | boolean | number,\n): SettingsFieldMeta {\n const known = SETTINGS_FIELDS[section]?.find((f) => f.key === key);\n if (known) return known;\n return {\n key,\n label: humanizeFieldKey(key),\n description: '',\n type: typeof value === 'boolean' ? 'boolean' : typeof value === 'number' ? 'number' : 'text',\n };\n}\n\nexport function parseCsvList(value: unknown): string[] {\n return String(value ?? '')\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean);\n}\n\nexport function toCsvList(values: string[]): string {\n return values.map((v) => v.trim()).filter(Boolean).join(',');\n}\n","import { ChangeDetectionStrategy, Component, computed, inject, OnDestroy, OnInit, signal } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { ActivatedRoute } from '@angular/router';\n\nimport { KnowledgeTestModalComponent } from '../../components/knowledge-test-modal/knowledge-test-modal.component';\nimport { AgentSettings, LocationOption } from '../../models/ai-receptionist.types';\nimport { AiReceptionistApiService } from '../../services/ai-receptionist-api.service';\nimport { AgentOnlineService } from '../../services/agent-online.service';\nimport { ModalComponent } from '../../shared/modal.component';\nimport { ToastService } from '../../shared/toast.service';\nimport { EdsButtonComponent } from '../../ui/eds-button.component';\nimport { EdsIconComponent } from '../../ui/eds-icon.component';\nimport {\n buildAutoWelcomeTemplate,\n resolveWelcomePreview,\n WELCOME_MESSAGE_MAX,\n} from '../../utils/welcome-message.util';\nimport { TTS_VOICE_PRESETS } from './tts-voice-presets';\nimport {\n AFTER_HOURS_OPTIONS,\n AGENT_TONE_OPTIONS,\n AI_ANSWER_MODE_OPTIONS,\n DEFAULT_DISCLOSURE_WARNING,\n DISABLED_SETTINGS_TABS,\n GREETING_VARIABLES,\n isFieldReadOnly,\n MAX_CALL_DURATION_OPTIONS,\n parseCsvList,\n READ_ONLY_SECTIONS,\n resolveFieldMeta,\n RETENTION_DAY_OPTIONS,\n RING_TIMEOUT_OPTIONS,\n SETTINGS_FIELDS,\n SETTINGS_SECTION_META,\n SettingsFieldMeta,\n SettingsSection,\n SILENCE_TIMEOUT_OPTIONS,\n toCsvList,\n} from './settings-fields.config';\n\ntype SettingsTab = keyof AgentSettings;\n\nconst CUSTOM_PANEL_TABS = new Set<SettingsTab>([\n 'general',\n 'phone',\n 'transcripts',\n 'knowledge',\n 'advanced',\n]);\nconst HIDDEN_GENERIC_KEYS = new Set([\n 'welcomeMessage',\n 'practiceName',\n 'language',\n 'languages',\n 'tone',\n 'timezone',\n]);\nconst KNOWLEDGE_MAX = 8000;\nconst DISCLOSURE_MAX = 1000;\n\n@Component({\n selector: 'eds-settings-page',\n imports: [\n FormsModule,\n EdsButtonComponent,\n EdsIconComponent,\n KnowledgeTestModalComponent,\n ModalComponent,\n ],\n templateUrl: './settings-page.component.html',\n styleUrl: './settings-page.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class SettingsPageComponent implements OnInit, OnDestroy {\n private readonly api = inject(AiReceptionistApiService);\n private readonly toast = inject(ToastService);\n private readonly route = inject(ActivatedRoute);\n private readonly agentOnline = inject(AgentOnlineService);\n private originalSettings: AgentSettings | null = null;\n private voiceAudio: HTMLAudioElement | null = null;\n private voiceObjectUrl: string | null = null;\n\n protected readonly isFieldReadOnly = isFieldReadOnly;\n protected readonly knowledgeMax = KNOWLEDGE_MAX;\n protected readonly disclosureMax = DISCLOSURE_MAX;\n protected readonly welcomeMax = WELCOME_MESSAGE_MAX;\n protected readonly voicePresets = TTS_VOICE_PRESETS;\n protected readonly toneOptions = AGENT_TONE_OPTIONS;\n protected readonly greetingVariables = GREETING_VARIABLES;\n protected readonly retentionOptions = RETENTION_DAY_OPTIONS;\n protected readonly ringTimeoutOptions = RING_TIMEOUT_OPTIONS;\n protected readonly maxCallDurationOptions = MAX_CALL_DURATION_OPTIONS;\n protected readonly silenceTimeoutOptions = SILENCE_TIMEOUT_OPTIONS;\n protected readonly answerModeOptions = AI_ANSWER_MODE_OPTIONS;\n protected readonly afterHoursOptions = AFTER_HOURS_OPTIONS;\n\n protected readonly settings = signal<AgentSettings | null>(null);\n protected readonly tab = signal<SettingsTab>('general');\n protected readonly loading = signal(true);\n protected readonly saving = signal(false);\n protected readonly saved = signal(false);\n protected readonly knowledgeTestOpen = signal(false);\n protected readonly locations = signal<LocationOption[]>([]);\n protected readonly locationsMenuOpen = signal(false);\n protected readonly confirmOffOpen = signal(false);\n protected readonly voicePreviewBusy = signal(false);\n protected readonly voicePreviewPlaying = signal(false);\n\n protected readonly online = this.agentOnline.online;\n protected readonly agentLoading = this.agentOnline.loading;\n protected readonly toggling = this.agentOnline.toggling;\n\n protected readonly tabs: { id: SettingsTab; label: string }[] = [\n { id: 'general', label: 'Identity & Greetings' },\n { id: 'phone', label: 'Phone & Availability' },\n { id: 'knowledge', label: 'Knowledge Base' },\n { id: 'transcripts', label: 'Data & Compliance' },\n { id: 'advanced', label: 'Advanced' },\n ];\n\n protected readonly sectionMeta = computed(() => {\n const id = this.tab();\n return SETTINGS_SECTION_META[id as SettingsSection] ?? { title: String(id), description: '' };\n });\n\n protected readonly fieldsForTab = computed((): SettingsFieldMeta[] => {\n const s = this.settings();\n const id = this.tab();\n if (!s || CUSTOM_PANEL_TABS.has(id)) return [];\n\n const section = s[id] as Record<string, string | boolean | number>;\n const configured = SETTINGS_FIELDS[id as SettingsSection] ?? [];\n const configuredKeys = new Set(configured.map((f) => f.key));\n\n const extras = Object.keys(section)\n .filter((key) => !HIDDEN_GENERIC_KEYS.has(key) && !configuredKeys.has(key))\n .map((key) => resolveFieldMeta(id as SettingsSection, key, section[key]));\n\n return [...configured, ...extras];\n });\n\n protected readonly welcomeMessage = computed(() =>\n String(this.settings()?.general['welcomeMessage'] ?? ''),\n );\n\n protected readonly welcomePlaceholder = computed(() => {\n const s = this.settings();\n if (!s) return '';\n return buildAutoWelcomeTemplate(\n String(s.general['practiceName'] ?? ''),\n String(s.general['agentName'] ?? ''),\n );\n });\n\n protected readonly welcomePreview = computed(() => {\n const s = this.settings();\n if (!s) return '';\n const raw = resolveWelcomePreview(\n String(s.general['welcomeMessage'] ?? ''),\n String(s.general['practiceName'] ?? ''),\n String(s.general['agentName'] ?? ''),\n );\n return raw\n .replaceAll('{{practiceName}}', String(s.general['practiceName'] || 'our practice'))\n .replaceAll('{{agentName}}', String(s.general['agentName'] || 'your AI receptionist'))\n .replaceAll('{{locationName}}', 'Main location')\n .replaceAll('{{businessHours}}', 'Mon–Fri 8am–5pm');\n });\n\n protected readonly whatToSay = computed(() =>\n String(this.settings()?.knowledge?.['whatToSay'] ?? ''),\n );\n\n protected readonly whatNotToSay = computed(() =>\n String(this.settings()?.knowledge?.['whatNotToSay'] ?? ''),\n );\n\n protected readonly selectedLocationIds = computed(() =>\n parseCsvList(this.settings()?.phone?.['locationIds']),\n );\n\n protected readonly locationSummary = computed(() => {\n const selected = this.selectedLocationIds();\n const all = this.locations();\n if (!all.length) return 'No locations available';\n if (!selected.length) return 'Select locations';\n const names = all.filter((l) => selected.includes(l.id)).map((l) => l.name);\n if (!names.length) return `${selected.length} selected`;\n if (names.length <= 2) return names.join(', ');\n return `${names[0]}, ${names[1]} +${names.length - 2}`;\n });\n\n protected readonly selectedTone = computed(() =>\n String(this.settings()?.general?.['tone'] ?? 'professional'),\n );\n\n protected readonly disclosureEnabled = computed(\n () => this.settings()?.transcripts?.['disclosureWarningEnabled'] !== false,\n );\n\n protected readonly disclosureText = computed(() =>\n String(this.settings()?.transcripts?.['disclosureWarningText'] ?? DEFAULT_DISCLOSURE_WARNING),\n );\n\n protected readonly agentSwitchDisabled = computed(\n () => this.agentLoading() || this.toggling() || this.online() === null,\n );\n\n ngOnInit(): void {\n this.agentOnline.refresh();\n\n const dataTab = this.route.snapshot.data['settingsTab'] as SettingsTab | undefined;\n const tabParam = this.route.snapshot.queryParamMap.get('tab');\n if (dataTab && this.tabs.some((t) => t.id === dataTab)) {\n this.tab.set(dataTab);\n } else if (tabParam && this.tabs.some((t) => t.id === tabParam)) {\n this.tab.set(tabParam as SettingsTab);\n }\n\n this.api.getSettings().subscribe({\n next: ({ data }) => {\n this.originalSettings = structuredClone(data);\n this.settings.set(structuredClone(data));\n this.loading.set(false);\n },\n error: () => {\n this.loading.set(false);\n this.toast.show('Failed to load agent settings', 'error');\n },\n });\n\n this.api.getLocations().subscribe({\n next: ({ data }) => this.locations.set(data ?? []),\n error: () => this.locations.set([]),\n });\n }\n\n ngOnDestroy(): void {\n this.stopVoicePreview();\n }\n\n protected fieldIsReadOnly(section: SettingsTab, key: string): boolean {\n if (section === 'safety' || section === 'effectiveWelcomeMessage') return true;\n return isFieldReadOnly(section, key);\n }\n\n protected sectionIsReadOnly(section: SettingsTab): boolean {\n if (section === 'safety' || section === 'effectiveWelcomeMessage') return true;\n return READ_ONLY_SECTIONS.has(section);\n }\n\n protected isTabDisabled(id: SettingsTab): boolean {\n return id !== 'safety' && id !== 'effectiveWelcomeMessage' && DISABLED_SETTINGS_TABS.has(id);\n }\n\n protected setTab(id: SettingsTab): void {\n if (this.isTabDisabled(id)) return;\n this.locationsMenuOpen.set(false);\n this.tab.set(id);\n }\n\n protected updateField(section: SettingsTab, key: string, value: string | boolean | number): void {\n const current = this.settings();\n if (!current || section === 'safety' || isFieldReadOnly(section as SettingsSection, key)) return;\n const sectionData = { ...(current[section] as Record<string, string | boolean | number>) };\n sectionData[key] = value;\n this.settings.set({ ...current, [section]: sectionData });\n }\n\n protected updateWelcomeMessage(value: string): void {\n this.updateField('general', 'welcomeMessage', value.slice(0, WELCOME_MESSAGE_MAX));\n }\n\n protected insertGreetingVariable(token: string): void {\n const current = this.welcomeMessage();\n const next = `${current}${current && !/\\s$/.test(current) ? ' ' : ''}${token}`;\n this.updateWelcomeMessage(next);\n }\n\n protected updateKnowledgeField(key: 'whatToSay' | 'whatNotToSay', value: string): void {\n this.updateField('knowledge', key, value.slice(0, KNOWLEDGE_MAX));\n }\n\n protected setTone(tone: string): void {\n this.updateField('general', 'tone', tone);\n }\n\n protected toggleLocationsMenu(): void {\n if (!this.locations().length) return;\n this.locationsMenuOpen.update((open) => !open);\n }\n\n protected onLocationsDocClick(event: MouseEvent): void {\n const target = event.target as HTMLElement | null;\n if (!target?.closest('.settings-page__locations-dd')) {\n this.locationsMenuOpen.set(false);\n }\n }\n\n protected toggleLocation(id: string): void {\n const current = this.selectedLocationIds();\n const next = current.includes(id) ? current.filter((x) => x !== id) : [...current, id];\n this.updateField('phone', 'locationIds', toCsvList(next));\n }\n\n protected selectNumberField(\n section: 'phone' | 'transcripts',\n key: string,\n value: string,\n ): void {\n this.updateField(section, key, Number(value));\n }\n\n protected numberFieldAsString(section: 'phone' | 'transcripts', key: string): string {\n return String(this.fieldValue(section, key) ?? '');\n }\n\n protected setDisclosureEnabled(enabled: boolean): void {\n this.updateField('transcripts', 'disclosureWarningEnabled', enabled);\n if (enabled && !String(this.settings()?.transcripts?.['disclosureWarningText'] ?? '').trim()) {\n this.updateField('transcripts', 'disclosureWarningText', DEFAULT_DISCLOSURE_WARNING);\n }\n }\n\n protected updateDisclosureText(value: string): void {\n this.updateField('transcripts', 'disclosureWarningText', value.slice(0, DISCLOSURE_MAX));\n }\n\n protected openTestCall(): void {\n const whatToSay = this.whatToSay().trim();\n const whatNotToSay = this.whatNotToSay().trim();\n if (!whatToSay || !whatNotToSay) {\n this.toast.show(\n 'Fill in both “What to say” and “What not to say” before testing.',\n 'error',\n );\n return;\n }\n this.knowledgeTestOpen.set(true);\n }\n\n protected closeTestCall(): void {\n this.knowledgeTestOpen.set(false);\n }\n\n protected selectedVoiceId(): string {\n return String(this.settings()?.general?.['ttsVoiceId'] ?? '').trim();\n }\n\n protected onVoiceChange(voiceId: string): void {\n this.stopVoicePreview();\n this.updateField('general', 'ttsVoiceId', voiceId);\n }\n\n protected toggleVoicePreview(): void {\n if (this.voicePreviewPlaying()) {\n this.stopVoicePreview();\n return;\n }\n const voiceId = this.selectedVoiceId();\n if (!voiceId || this.voicePreviewBusy()) return;\n\n this.voicePreviewBusy.set(true);\n this.api.previewVoice(voiceId).subscribe({\n next: (blob) => {\n this.voicePreviewBusy.set(false);\n this.playVoiceBlob(blob);\n },\n error: (err: { message?: string }) => {\n this.voicePreviewBusy.set(false);\n this.toast.show(err.message ?? 'Failed to preview voice.', 'error');\n },\n });\n }\n\n private playVoiceBlob(blob: Blob): void {\n this.stopVoicePreview();\n this.voiceObjectUrl = URL.createObjectURL(blob);\n const audio = new Audio(this.voiceObjectUrl);\n this.voiceAudio = audio;\n this.voicePreviewPlaying.set(true);\n audio.onended = () => this.stopVoicePreview();\n audio.onerror = () => {\n this.stopVoicePreview();\n this.toast.show('Failed to play voice preview.', 'error');\n };\n void audio.play().catch(() => {\n this.stopVoicePreview();\n this.toast.show('Failed to play voice preview.', 'error');\n });\n }\n\n private stopVoicePreview(): void {\n if (this.voiceAudio) {\n this.voiceAudio.pause();\n this.voiceAudio.onended = null;\n this.voiceAudio.onerror = null;\n this.voiceAudio = null;\n }\n if (this.voiceObjectUrl) {\n URL.revokeObjectURL(this.voiceObjectUrl);\n this.voiceObjectUrl = null;\n }\n this.voicePreviewPlaying.set(false);\n }\n\n protected onAgentToggleClick(): void {\n if (this.agentSwitchDisabled()) return;\n if (this.online()) {\n this.confirmOffOpen.set(true);\n return;\n }\n this.applyOnline(true);\n }\n\n protected cancelConfirmOff(): void {\n this.confirmOffOpen.set(false);\n }\n\n protected confirmTurnOff(): void {\n this.confirmOffOpen.set(false);\n this.applyOnline(false);\n }\n\n private applyOnline(enabled: boolean): void {\n this.agentOnline.setOnline(enabled).subscribe({\n next: () => {\n this.toast.show(\n enabled\n ? 'AI receptionist is online — it will answer inbound calls.'\n : 'AI receptionist is offline — calls go to the front desk.',\n 'success',\n );\n },\n error: (err: { message?: string }) => {\n this.toast.show(err.message ?? 'Failed to update agent status.', 'error');\n this.agentOnline.refresh();\n },\n });\n }\n\n protected fieldValue(section: SettingsTab, key: string): string | boolean | number {\n const s = this.settings();\n if (!s || section === 'safety') return '';\n return (s[section] as Record<string, string | boolean | number>)[key];\n }\n\n protected save(): void {\n const s = this.settings();\n const orig = this.originalSettings;\n if (!s || !orig) return;\n\n const payload = structuredClone(s);\n payload.general['welcomeMessage'] = String(payload.general['welcomeMessage'] ?? '').trim();\n payload.general['agentName'] = String(payload.general['agentName'] ?? '').trim();\n\n if (!String(payload.general['agentName'] ?? '').trim()) {\n this.tab.set('general');\n this.toast.show('Agent name is required.', 'error');\n return;\n }\n if (!String(payload.general['welcomeMessage'] ?? '').trim()) {\n this.tab.set('general');\n this.toast.show('Inbound greeting is required.', 'error');\n return;\n }\n\n const whatToSay = String(payload.knowledge?.['whatToSay'] ?? '').trim();\n const whatNotToSay = String(payload.knowledge?.['whatNotToSay'] ?? '').trim();\n if (!whatToSay || !whatNotToSay) {\n this.tab.set('knowledge');\n this.toast.show('Knowledge Base requires both “What to say” and “What not to say”.', 'error');\n return;\n }\n payload.knowledge = { whatToSay, whatNotToSay };\n\n // Keep legacy retainDays in sync for older BE consumers.\n const recDays = Number(payload.transcripts['recordingRetainDays'] ?? 30);\n const txDays = Number(payload.transcripts['transcriptRetainDays'] ?? 30);\n payload.transcripts['retainDays'] = Math.max(recDays, txDays);\n\n this.restoreReadOnlyFields(payload, orig);\n\n this.saving.set(true);\n this.api.putSettings(payload).subscribe({\n next: ({ data }) => {\n this.originalSettings = structuredClone(data);\n this.settings.set(structuredClone(data));\n this.saving.set(false);\n this.saved.set(true);\n this.toast.show('Agent settings saved', 'success');\n setTimeout(() => this.saved.set(false), 2000);\n },\n error: (err: unknown) => {\n this.saving.set(false);\n const message =\n err instanceof Error && err.message.trim()\n ? err.message\n : 'Failed to save agent settings';\n this.toast.show(message, 'error');\n },\n });\n }\n\n private restoreReadOnlyFields(payload: AgentSettings, orig: AgentSettings): void {\n const editableSections: SettingsSection[] = [\n 'general',\n 'phone',\n 'tasks',\n 'scheduling',\n 'refill',\n 'verify',\n 'escalation',\n 'outbound',\n 'knowledge',\n 'transcripts',\n 'advanced',\n ];\n\n for (const sectionKey of editableSections) {\n if (READ_ONLY_SECTIONS.has(sectionKey)) {\n payload[sectionKey] = structuredClone(orig[sectionKey]);\n continue;\n }\n\n const payloadSection = payload[sectionKey] as Record<string, string | boolean | number>;\n const origSection = orig[sectionKey] as Record<string, string | boolean | number>;\n for (const key of Object.keys(payloadSection)) {\n if (isFieldReadOnly(sectionKey, key)) {\n payloadSection[key] = origSection[key];\n }\n }\n }\n }\n}\n","<div class=\"eds-page settings-page\">\n <header class=\"mb-6 flex items-start justify-between gap-4\">\n <div>\n <h1 class=\"eds-h1\">Agent settings</h1>\n <p class=\"mt-2 text-base leading-normal text-zinc-500\">Configure AI receptionist behavior and safety</p>\n </div>\n <div class=\"flex shrink-0 items-center gap-3\">\n @if (saved()) {\n <span class=\"text-sm font-medium text-green-500\">Saved</span>\n }\n <eds-button variant=\"primary\" [disabled]=\"saving()\" (click)=\"save()\">\n <eds-icon name=\"save\" [size]=\"18\" />\n {{ saving() ? 'Saving…' : 'Save changes' }}\n </eds-button>\n </div>\n </header>\n\n @if (loading()) {\n <p class=\"mt-2 text-base leading-normal text-zinc-500\">Loading settings…</p>\n } @else if (settings()) {\n <div class=\"settings-page__layout grid items-start gap-5\">\n <nav class=\"eds-card settings-page__sidebar sticky top-4 flex max-h-[calc(100vh-120px)] flex-col gap-1 overflow-y-auto p-2 shadow-sm\" aria-label=\"Settings sections\">\n @for (t of tabs; track t.id) {\n <button\n type=\"button\"\n class=\"settings-page__nav-item flex w-full cursor-pointer items-center justify-between gap-3 rounded-md border-none bg-transparent px-4 py-3 text-left text-sm font-medium leading-snug text-zinc-600\"\n [class.settings-page__nav-item--active]=\"tab() === t.id\"\n [class.settings-page__nav-item--disabled]=\"isTabDisabled(t.id)\"\n [disabled]=\"isTabDisabled(t.id)\"\n [attr.title]=\"isTabDisabled(t.id) ? 'This section is currently disabled' : null\"\n (click)=\"setTab(t.id)\"\n >\n {{ t.label }}\n @if (isTabDisabled(t.id)) {\n <span class=\"ml-auto text-xs font-medium uppercase tracking-wide text-zinc-400\">Disabled</span>\n }\n </button>\n }\n </nav>\n\n <article class=\"eds-card settings-page__panel min-h-96 px-8 py-7 shadow-sm\">\n <header class=\"mb-6 flex items-start justify-between gap-4 border-b border-zinc-200 pb-4\">\n <div class=\"min-w-0\">\n <h2 class=\"mb-2 m-0 text-xl font-medium tracking-tight text-zinc-700\">{{ sectionMeta().title }}</h2>\n @if (tab() !== 'knowledge' && tab() !== 'general' && tab() !== 'phone' && tab() !== 'transcripts') {\n <p class=\"m-0 max-w-2xl text-base leading-relaxed text-zinc-500\">{{ sectionMeta().description }}</p>\n }\n </div>\n @if (tab() === 'knowledge') {\n <eds-button variant=\"secondary\" type=\"button\" (click)=\"openTestCall()\">\n <eds-icon name=\"phone_in_talk\" [size]=\"18\" />\n Test Call\n </eds-button>\n }\n </header>\n\n @if (sectionIsReadOnly(tab())) {\n <p class=\"mb-5 flex items-center gap-3 rounded-md border border-zinc-200 bg-slate-50 px-4 py-3 text-sm leading-snug text-zinc-500\">\n <eds-icon name=\"lock\" [size]=\"18\" />\n These settings are managed by Edvak. Contact support to request changes.\n </p>\n }\n\n @if (tab() === 'knowledge') {\n <div class=\"flex max-w-4xl flex-col gap-7\">\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\"flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n What to say <span class=\"font-medium text-red-600\">*</span>\n </span>\n <textarea\n class=\"settings-page__textarea min-h-56 w-full resize-y rounded-md border border-zinc-300 px-3 py-3 text-sm leading-relaxed text-zinc-700 font-inherit\"\n rows=\"10\"\n [maxlength]=\"knowledgeMax\"\n [ngModel]=\"whatToSay()\"\n (ngModelChange)=\"updateKnowledgeField('whatToSay', $event)\"\n placeholder=\"Hours, parking, payment options, arrival instructions, emergencies…\"\n autocomplete=\"off\"\n ></textarea>\n <span class=\"text-right text-xs text-zinc-500\">{{ whatToSay().length }}/{{ knowledgeMax }}</span>\n </label>\n\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\"flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n What not to say <span class=\"font-medium text-red-600\">*</span>\n </span>\n <textarea\n class=\"settings-page__textarea min-h-56 w-full resize-y rounded-md border border-zinc-300 px-3 py-3 text-sm leading-relaxed text-zinc-700 font-inherit\"\n rows=\"10\"\n [maxlength]=\"knowledgeMax\"\n [ngModel]=\"whatNotToSay()\"\n (ngModelChange)=\"updateKnowledgeField('whatNotToSay', $event)\"\n placeholder=\"Clinical advice, unverified prices, PHI, promises the practice cannot keep…\"\n autocomplete=\"off\"\n ></textarea>\n <span class=\"text-right text-xs text-zinc-500\">{{ whatNotToSay().length }}/{{ knowledgeMax }}</span>\n </label>\n </div>\n } @else if (tab() === 'general') {\n <div class=\"flex max-w-3xl flex-col gap-5\">\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Name <span class=\"font-medium text-red-600\">*</span>\n <eds-icon name=\"info\" [size]=\"16\" class=\"ml-auto text-zinc-400\" title=\"How the AI introduces itself on calls\" />\n </span>\n <input\n type=\"text\"\n class=\"settings-page__input w-full rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"fieldValue('general', 'agentName')\"\n (ngModelChange)=\"updateField('general', 'agentName', $event)\"\n autocomplete=\"off\"\n />\n </label>\n\n <div class=\"flex items-end gap-3\">\n <label class=\"settings-page__field min-w-0 flex-1 flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Voice <span class=\"font-medium text-red-600\">*</span>\n </span>\n <div class=\"relative w-full\">\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"fieldValue('general', 'ttsVoiceId')\"\n (ngModelChange)=\"onVoiceChange($event)\"\n autocomplete=\"off\"\n >\n @for (v of voicePresets; track v.id) {\n <option [ngValue]=\"v.id\">{{ v.gender }} · {{ v.label }}</option>\n }\n </select>\n <eds-icon name=\"expand_more\" [size]=\"20\" class=\"pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-zinc-500\" />\n </div>\n </label>\n <button\n type=\"button\"\n class=\"settings-page__voice-play inline-flex h-[50px] w-[50px] shrink-0 cursor-pointer items-center justify-center rounded-md border border-zinc-300 bg-white text-zinc-700 hover:border-blue-500 hover:text-blue-600 disabled:cursor-wait disabled:opacity-60\"\n [disabled]=\"!selectedVoiceId() || voicePreviewBusy()\"\n [attr.aria-label]=\"voicePreviewPlaying() ? 'Stop voice preview' : 'Play voice preview'\"\n [title]=\"voicePreviewPlaying() ? 'Stop preview' : 'Play sample'\"\n (click)=\"toggleVoicePreview()\"\n >\n <eds-icon [name]=\"voicePreviewPlaying() ? 'stop' : 'play_arrow'\" [size]=\"24\" [fill]=\"1\" />\n </button>\n </div>\n\n <div class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">Tone</span>\n <div class=\"flex flex-wrap gap-2\" role=\"radiogroup\" aria-label=\"Tone\">\n @for (tone of toneOptions; track tone.value) {\n <button\n type=\"button\"\n class=\"settings-page__tone h-9 cursor-pointer rounded-full border border-transparent bg-slate-100 px-4 text-sm font-medium text-zinc-500\"\n [class.settings-page__tone--active]=\"selectedTone() === tone.value\"\n (click)=\"setTone(tone.value)\"\n >\n {{ tone.label }}\n </button>\n }\n </div>\n </div>\n\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Inbound Greetings <span class=\"font-medium text-red-600\">*</span>\n </span>\n <textarea\n class=\"settings-page__textarea min-h-24 w-full resize-y rounded-md border border-zinc-300 px-3 py-3 text-base leading-normal text-zinc-700 font-inherit\"\n rows=\"4\"\n [maxlength]=\"welcomeMax\"\n [placeholder]=\"welcomePlaceholder()\"\n [ngModel]=\"welcomeMessage()\"\n (ngModelChange)=\"updateWelcomeMessage($event)\"\n autocomplete=\"off\"\n ></textarea>\n <span class=\"text-right text-xs text-zinc-500\">{{ welcomeMessage().length }}/{{ welcomeMax }}</span>\n <div class=\"mt-3 flex flex-wrap items-center gap-2\">\n <span class=\"text-sm text-zinc-500\">Variables</span>\n @for (v of greetingVariables; track v.key) {\n <button\n type=\"button\"\n class=\"settings-page__var-chip h-7 cursor-pointer rounded-full border border-zinc-200 bg-white px-3 text-xs font-medium text-zinc-700\"\n (click)=\"insertGreetingVariable(v.token)\"\n [title]=\"'Insert ' + v.token\"\n >\n {{ v.label }}\n </button>\n }\n </div>\n </label>\n </div>\n } @else if (tab() === 'phone') {\n <div class=\"flex max-w-3xl flex-col gap-5\">\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n AI Answer Mode <span class=\"font-medium text-red-600\">*</span>\n <eds-icon name=\"info\" [size]=\"16\" class=\"ml-auto text-zinc-400\" title=\"When the AI picks up inbound calls\" />\n </span>\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"fieldValue('phone', 'answerMode')\"\n (ngModelChange)=\"updateField('phone', 'answerMode', $event)\"\n autocomplete=\"off\"\n >\n @for (opt of answerModeOptions; track opt.value) {\n <option [ngValue]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n </label>\n\n <label\n class=\"settings-page__field col-span-full flex flex-col gap-2\"\n [class.settings-page__field--readonly]=\"isFieldReadOnly('phone', 'mainNumber')\"\n >\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n AI Phone Number <span class=\"font-medium text-red-600\">*</span>\n @if (isFieldReadOnly('phone', 'mainNumber')) {\n }\n </span>\n <input\n type=\"text\"\n class=\"settings-page__input w-full rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [class.settings-page__input--readonly]=\"isFieldReadOnly('phone', 'mainNumber')\"\n [disabled]=\"isFieldReadOnly('phone', 'mainNumber')\"\n [ngModel]=\"fieldValue('phone', 'mainNumber')\"\n (ngModelChange)=\"updateField('phone', 'mainNumber', $event)\"\n autocomplete=\"off\"\n />\n </label>\n\n <label\n class=\"settings-page__field col-span-full flex flex-col gap-2\"\n [class.settings-page__field--readonly]=\"isFieldReadOnly('phone', 'transferNumber')\"\n >\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Transfer Number <span class=\"font-medium text-red-600\">*</span>\n @if (isFieldReadOnly('phone', 'transferNumber')) {\n }\n </span>\n <input\n type=\"text\"\n class=\"settings-page__input w-full rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [class.settings-page__input--readonly]=\"isFieldReadOnly('phone', 'transferNumber')\"\n [disabled]=\"isFieldReadOnly('phone', 'transferNumber')\"\n [ngModel]=\"fieldValue('phone', 'transferNumber')\"\n (ngModelChange)=\"updateField('phone', 'transferNumber', $event)\"\n autocomplete=\"off\"\n />\n </label>\n\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Ringing Time Wait <span class=\"font-medium text-red-600\">*</span>\n </span>\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"numberFieldAsString('phone', 'ringTimeout')\"\n (ngModelChange)=\"selectNumberField('phone', 'ringTimeout', $event)\"\n autocomplete=\"off\"\n >\n @for (opt of ringTimeoutOptions; track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n </label>\n\n <div class=\"settings-page__feature-card flex items-center gap-4 rounded-xl border border-zinc-200 bg-white p-4\">\n <eds-icon name=\"event_available\" [size]=\"22\" class=\"shrink-0 text-blue-600\" />\n <div class=\"flex min-w-0 flex-1 flex-col gap-1\">\n <span class=\"text-sm font-medium leading-snug text-zinc-700\">Create Follow-up Task</span>\n <span class=\"text-xs leading-snug text-zinc-500\">\n If no one answers in time, the agent auto-creates a high priority task.\n </span>\n </div>\n <button\n type=\"button\"\n class=\"settings-page__switch shrink-0\"\n [class.settings-page__switch--on]=\"!!fieldValue('phone', 'createFollowUpTask')\"\n [attr.aria-pressed]=\"!!fieldValue('phone', 'createFollowUpTask')\"\n (click)=\"updateField('phone', 'createFollowUpTask', !fieldValue('phone', 'createFollowUpTask'))\"\n >\n <span class=\"settings-page__switch-thumb\"></span>\n </button>\n </div>\n\n <div class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Location Handled <span class=\"font-medium text-red-600\">*</span>\n </span>\n <div class=\"settings-page__locations-dd relative\" (document:click)=\"onLocationsDocClick($event)\">\n <button\n type=\"button\"\n class=\"settings-page__input settings-page__select flex w-full cursor-pointer items-center justify-between gap-2 rounded-md border border-zinc-300 bg-white px-3 py-2.5 text-left text-base leading-snug text-zinc-700\"\n [disabled]=\"locations().length === 0\"\n [attr.aria-expanded]=\"locationsMenuOpen()\"\n aria-haspopup=\"listbox\"\n aria-label=\"Locations handled\"\n (click)=\"$event.stopPropagation(); toggleLocationsMenu()\"\n >\n <span class=\"min-w-0 truncate\">{{ locationSummary() }}</span>\n <eds-icon name=\"expand_more\" [size]=\"18\" class=\"shrink-0 text-zinc-500\" />\n </button>\n @if (locationsMenuOpen()) {\n <ul\n class=\"absolute z-20 m-0 mt-1 max-h-56 w-full list-none overflow-auto rounded-md border border-zinc-200 bg-white p-1 shadow-md\"\n role=\"listbox\"\n aria-multiselectable=\"true\"\n >\n @for (loc of locations(); track loc.id) {\n <li role=\"option\" [attr.aria-selected]=\"selectedLocationIds().includes(loc.id)\">\n <label\n class=\"flex cursor-pointer items-center gap-2.5 rounded px-2.5 py-2 text-sm text-zinc-700 hover:bg-zinc-50\"\n >\n <input\n type=\"checkbox\"\n class=\"h-4 w-4 accent-blue-600\"\n [checked]=\"selectedLocationIds().includes(loc.id)\"\n (change)=\"toggleLocation(loc.id)\"\n />\n <span class=\"min-w-0 truncate\">{{ loc.name }}</span>\n </label>\n </li>\n }\n </ul>\n }\n </div>\n @if (locations().length === 0) {\n <p class=\"m-0 text-sm text-zinc-500\">No locations available.</p>\n }\n </div>\n\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Max AI Call Duration <span class=\"font-medium text-red-600\">*</span>\n </span>\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"numberFieldAsString('phone', 'maxCallDurationMin')\"\n (ngModelChange)=\"selectNumberField('phone', 'maxCallDurationMin', $event)\"\n autocomplete=\"off\"\n >\n @for (opt of maxCallDurationOptions; track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n </label>\n\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Silence Timeout <span class=\"font-medium text-red-600\">*</span>\n </span>\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"numberFieldAsString('phone', 'silenceTimeoutSec')\"\n (ngModelChange)=\"selectNumberField('phone', 'silenceTimeoutSec', $event)\"\n autocomplete=\"off\"\n >\n @for (opt of silenceTimeoutOptions; track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n </label>\n\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n After-Hours Behaviour <span class=\"font-medium text-red-600\">*</span>\n </span>\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"fieldValue('phone', 'afterHoursBehavior')\"\n (ngModelChange)=\"updateField('phone', 'afterHoursBehavior', $event)\"\n autocomplete=\"off\"\n >\n @for (opt of afterHoursOptions; track opt.value) {\n <option [ngValue]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n </label>\n\n <div class=\"border-t border-zinc-200 pt-5\">\n <div class=\"flex flex-col gap-5\">\n <label class=\"settings-page__field col-span-full flex flex-col gap-1.5\">\n <span class=\"settings-page__field-label flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Minimum lead time (hours)\n </span>\n <input\n type=\"number\"\n min=\"0\"\n class=\"settings-page__input w-full rounded-md border border-zinc-300 bg-white px-3 py-2.5 text-base leading-snug text-zinc-700\"\n [ngModel]=\"fieldValue('scheduling', 'leadTimeHours')\"\n (ngModelChange)=\"updateField('scheduling', 'leadTimeHours', +$event)\"\n autocomplete=\"off\"\n />\n <span class=\"text-xs text-zinc-500\">Earliest bookable slot from now.</span>\n </label>\n\n <div class=\"settings-page__feature-card flex items-center gap-3.5 rounded-xl border border-zinc-200 bg-white p-3.5\">\n <eds-icon name=\"today\" [size]=\"22\" class=\"shrink-0 text-blue-600\" />\n <div class=\"flex min-w-0 flex-1 flex-col gap-1\">\n <span class=\"text-sm font-medium leading-snug text-zinc-700\">Allow same-day booking</span>\n <span class=\"text-xs leading-snug text-zinc-500\">\n Let patients book appointments later today.\n </span>\n </div>\n <button\n type=\"button\"\n class=\"settings-page__switch shrink-0\"\n [class.settings-page__switch--on]=\"!!fieldValue('scheduling', 'allowSameDay')\"\n [attr.aria-pressed]=\"!!fieldValue('scheduling', 'allowSameDay')\"\n (click)=\"updateField('scheduling', 'allowSameDay', !fieldValue('scheduling', 'allowSameDay'))\"\n >\n <span class=\"settings-page__switch-thumb\"></span>\n </button>\n </div>\n </div>\n </div>\n </div>\n } @else if (tab() === 'transcripts') {\n <div class=\"flex max-w-3xl flex-col gap-5\">\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Keep Call Recordings <span class=\"font-medium text-red-600\">*</span>\n </span>\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"numberFieldAsString('transcripts', 'recordingRetainDays')\"\n (ngModelChange)=\"selectNumberField('transcripts', 'recordingRetainDays', $event)\"\n autocomplete=\"off\"\n >\n @for (opt of retentionOptions; track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n </label>\n\n <label class=\"settings-page__field col-span-full flex flex-col gap-2\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Keep Transcripts <span class=\"font-medium text-red-600\">*</span>\n </span>\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"numberFieldAsString('transcripts', 'transcriptRetainDays')\"\n (ngModelChange)=\"selectNumberField('transcripts', 'transcriptRetainDays', $event)\"\n autocomplete=\"off\"\n >\n @for (opt of retentionOptions; track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n </label>\n\n <div class=\"flex flex-col gap-3\">\n <div class=\"flex items-center justify-between gap-3\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">Disclosure Warning</span>\n <button\n type=\"button\"\n class=\"settings-page__switch shrink-0\"\n [class.settings-page__switch--on]=\"disclosureEnabled()\"\n [attr.aria-pressed]=\"disclosureEnabled()\"\n (click)=\"setDisclosureEnabled(!disclosureEnabled())\"\n >\n <span class=\"settings-page__switch-thumb\"></span>\n </button>\n </div>\n @if (disclosureEnabled()) {\n <textarea\n class=\"settings-page__textarea min-h-24 w-full resize-y rounded-md border border-zinc-300 px-3 py-3 text-base leading-normal text-zinc-700 font-inherit\"\n rows=\"4\"\n [maxlength]=\"disclosureMax\"\n [ngModel]=\"disclosureText()\"\n (ngModelChange)=\"updateDisclosureText($event)\"\n autocomplete=\"off\"\n ></textarea>\n }\n </div>\n </div>\n } @else if (tab() === 'advanced') {\n <div class=\"flex max-w-3xl flex-col gap-5\">\n <div class=\"settings-page__feature-card flex items-center gap-4 rounded-xl border border-zinc-200 bg-white p-4\">\n <span class=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-[10px] bg-violet-500/15 text-[var(--eds-violet-500,#8b5cf6)]\" aria-hidden=\"true\">\n <eds-icon name=\"auto_awesome\" [size]=\"20\" [fill]=\"1\" />\n </span>\n <div class=\"flex min-w-0 flex-1 flex-col gap-1\">\n <span class=\"text-sm font-medium leading-snug text-zinc-700\">\n @if (toggling()) {\n Updating…\n } @else if (online() === true) {\n Agent online\n } @else if (online() === false) {\n Agent offline\n } @else {\n Status unknown\n }\n </span>\n <span class=\"text-xs leading-snug text-zinc-500\">\n @if (online() === true) {\n AI receptionist is answering inbound calls.\n } @else if (online() === false) {\n AI is offline — calls go to the front desk.\n } @else {\n Checking agent status…\n }\n </span>\n </div>\n <button\n type=\"button\"\n class=\"settings-page__switch shrink-0\"\n [class.settings-page__switch--on]=\"online() === true\"\n [disabled]=\"agentSwitchDisabled()\"\n [attr.aria-pressed]=\"online() === true\"\n (click)=\"onAgentToggleClick()\"\n >\n <span class=\"settings-page__switch-thumb\"></span>\n </button>\n </div>\n\n <label class=\"settings-page__field col-span-full flex flex-col gap-2 settings-page__field--readonly\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Model version\n </span>\n <input\n type=\"text\"\n class=\"settings-page__input settings-page__input--readonly w-full rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [ngModel]=\"fieldValue('advanced', 'modelVersion')\"\n disabled\n autocomplete=\"off\"\n />\n </label>\n\n <label class=\"settings-page__toggle-row settings-page__toggle-row--readonly col-span-full flex cursor-pointer items-center justify-between gap-4 rounded-md border border-zinc-200 bg-slate-50 px-4 py-4\">\n <div class=\"flex min-w-0 flex-col gap-1\">\n <span class=\"flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n Debug mode\n </span>\n <span class=\"settings-page__field-desc mb-1 text-sm leading-snug text-zinc-500\">Verbose logging — contact Edvak to change.</span>\n </div>\n <input\n type=\"checkbox\"\n class=\"settings-page__checkbox h-[18px] w-[18px] shrink-0 accent-blue-600\"\n [ngModel]=\"fieldValue('advanced', 'debugMode')\"\n disabled\n autocomplete=\"off\"\n />\n </label>\n </div>\n } @else {\n <div class=\"settings-page__fields grid grid-cols-2 gap-x-7 gap-y-5\">\n @for (field of fieldsForTab(); track field.key) {\n @if (field.type === 'boolean') {\n <label\n class=\"settings-page__toggle-row col-span-full flex cursor-pointer items-center justify-between gap-4 rounded-md border border-zinc-200 bg-slate-50 px-4 py-4\"\n [class.settings-page__toggle-row--readonly]=\"fieldIsReadOnly(tab(), field.key)\"\n >\n <div class=\"flex min-w-0 flex-col gap-1\">\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n {{ field.label }}\n </span>\n @if (field.description) {\n <span class=\"settings-page__field-desc mb-1 text-sm leading-snug text-zinc-500\">{{ field.description }}</span>\n }\n </div>\n <input\n type=\"checkbox\"\n class=\"settings-page__checkbox h-[18px] w-[18px] shrink-0 accent-blue-600\"\n [disabled]=\"fieldIsReadOnly(tab(), field.key)\"\n [ngModel]=\"fieldValue(tab(), field.key)\"\n (ngModelChange)=\"updateField(tab(), field.key, $event)\"\n autocomplete=\"off\"\n />\n </label>\n } @else {\n <label\n class=\"settings-page__field flex flex-col gap-2\"\n [class.settings-page__field--readonly]=\"fieldIsReadOnly(tab(), field.key)\"\n >\n <span class=\" flex flex-wrap items-center gap-2 text-sm font-medium leading-snug text-zinc-700\">\n {{ field.label }}\n </span>\n @if (field.description) {\n <span class=\"settings-page__field-desc mb-1 text-sm leading-snug text-zinc-500\">{{ field.description }}</span>\n }\n @if (field.type === 'number') {\n <input\n type=\"number\"\n class=\"settings-page__input w-full rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [class.settings-page__input--readonly]=\"fieldIsReadOnly(tab(), field.key)\"\n [disabled]=\"fieldIsReadOnly(tab(), field.key)\"\n [ngModel]=\"fieldValue(tab(), field.key)\"\n (ngModelChange)=\"updateField(tab(), field.key, +$event)\"\n autocomplete=\"off\"\n />\n } @else if (field.type === 'select' && field.options?.length) {\n <select\n class=\"settings-page__input settings-page__select w-full cursor-pointer appearance-none rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [class.settings-page__input--readonly]=\"fieldIsReadOnly(tab(), field.key)\"\n [disabled]=\"fieldIsReadOnly(tab(), field.key)\"\n [ngModel]=\"fieldValue(tab(), field.key)\"\n (ngModelChange)=\"updateField(tab(), field.key, $event)\"\n autocomplete=\"off\"\n >\n @for (opt of field.options; track opt.value) {\n <option [ngValue]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n } @else {\n <input\n type=\"text\"\n class=\"settings-page__input w-full rounded-md border border-zinc-300 bg-white px-3 py-3 text-base leading-snug text-zinc-700\"\n [class.settings-page__input--readonly]=\"fieldIsReadOnly(tab(), field.key)\"\n [disabled]=\"fieldIsReadOnly(tab(), field.key)\"\n [ngModel]=\"fieldValue(tab(), field.key)\"\n (ngModelChange)=\"updateField(tab(), field.key, $event)\"\n autocomplete=\"off\"\n />\n }\n </label>\n }\n }\n </div>\n }\n </article>\n </div>\n }\n</div>\n\n<eds-knowledge-test-modal\n [open]=\"knowledgeTestOpen()\"\n [whatToSay]=\"whatToSay()\"\n [whatNotToSay]=\"whatNotToSay()\"\n [voiceId]=\"selectedVoiceId()\"\n (closed)=\"closeTestCall()\"\n/>\n\n@if (confirmOffOpen()) {\n <app-modal\n title=\"Turn off AI receptionist?\"\n subtitle=\"Inbound callers will be transferred to the front desk instead of the AI.\"\n maxWidth=\"480px\"\n (closed)=\"cancelConfirmOff()\"\n >\n <p class=\"mb-4 m-0 text-sm leading-normal text-zinc-500\">While offline, the AI will not answer calls. Callers are routed to the human receptionist.</p>\n <div class=\"flex justify-end gap-2\">\n <eds-button variant=\"secondary\" type=\"button\" (click)=\"cancelConfirmOff()\">Cancel</eds-button>\n <eds-button variant=\"danger\" type=\"button\" [disabled]=\"toggling()\" (click)=\"confirmTurnOff()\">\n Turn off\n </eds-button>\n </div>\n </app-modal>\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,194 @@
1
+ import { DatePipe } from '@angular/common';
2
+ import * as i0 from '@angular/core';
3
+ import { inject, signal, Input, ChangeDetectionStrategy, Component, input, output } from '@angular/core';
4
+ import { RouterLink } from '@angular/router';
5
+ import { ToastService, EdsBadgeComponent, EdsButtonComponent, EdsIconComponent } from './edvak99-voice-receptionist-widget.mjs';
6
+
7
+ class CopyButtonComponent {
8
+ constructor() {
9
+ /** Raw value to copy (full ID / phone / etc.) */
10
+ this.value = '';
11
+ /** Accessible label, e.g. "patient ID" */
12
+ this.label = 'value';
13
+ this.toast = inject(ToastService);
14
+ this.copied = signal(false);
15
+ }
16
+ get copyValue() {
17
+ const v = this.value?.trim();
18
+ return v && v !== '—' ? v : '';
19
+ }
20
+ get ariaLabel() {
21
+ return this.copied() ? 'Copied' : `Copy ${this.label}`;
22
+ }
23
+ async onCopy(event) {
24
+ event.stopPropagation();
25
+ const text = this.copyValue;
26
+ if (!text)
27
+ return;
28
+ try {
29
+ await navigator.clipboard.writeText(text);
30
+ this.copied.set(true);
31
+ setTimeout(() => this.copied.set(false), 1500);
32
+ }
33
+ catch {
34
+ this.toast.show('Could not copy — clipboard unavailable', 'error', 2500);
35
+ }
36
+ }
37
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: CopyButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
38
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: CopyButtonComponent, isStandalone: true, selector: "app-copy-btn", inputs: { value: "value", label: "label" }, ngImport: i0, template: `
39
+ @if (copyValue) {
40
+ <button
41
+ type="button"
42
+ class="copy-btn inline-flex shrink-0 items-center justify-center p-0"
43
+ (click)="onCopy($event)"
44
+ [attr.aria-label]="ariaLabel"
45
+ [title]="copied() ? 'Copied' : 'Copy to clipboard'"
46
+ >
47
+ @if (copied()) {
48
+ <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor"
49
+ stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
50
+ <polyline points="20 6 9 17 4 12" />
51
+ </svg>
52
+ } @else {
53
+ <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor"
54
+ stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
55
+ <rect x="9" y="9" width="13" height="13" rx="2" ry="2" />
56
+ <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" />
57
+ </svg>
58
+ }
59
+ </button>
60
+ }
61
+ `, isInline: true, styles: [".copy-btn{width:22px;height:22px;border:1px solid var(--eds-color-border);border-radius:4px;background:var(--eds-color-surface);color:var(--eds-color-text-muted);cursor:pointer;transition:background .1s ease,color .1s ease,border-color .1s ease}.copy-btn:hover{background:var(--eds-color-surface-alt);color:var(--eds-color-primary);border-color:var(--eds-color-border-strong)}.copy-btn:focus-visible{outline:2px solid var(--eds-color-primary);outline-offset:1px}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
62
+ }
63
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: CopyButtonComponent, decorators: [{
64
+ type: Component,
65
+ args: [{ selector: 'app-copy-btn', standalone: true, template: `
66
+ @if (copyValue) {
67
+ <button
68
+ type="button"
69
+ class="copy-btn inline-flex shrink-0 items-center justify-center p-0"
70
+ (click)="onCopy($event)"
71
+ [attr.aria-label]="ariaLabel"
72
+ [title]="copied() ? 'Copied' : 'Copy to clipboard'"
73
+ >
74
+ @if (copied()) {
75
+ <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor"
76
+ stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
77
+ <polyline points="20 6 9 17 4 12" />
78
+ </svg>
79
+ } @else {
80
+ <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor"
81
+ stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
82
+ <rect x="9" y="9" width="13" height="13" rx="2" ry="2" />
83
+ <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" />
84
+ </svg>
85
+ }
86
+ </button>
87
+ }
88
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".copy-btn{width:22px;height:22px;border:1px solid var(--eds-color-border);border-radius:4px;background:var(--eds-color-surface);color:var(--eds-color-text-muted);cursor:pointer;transition:background .1s ease,color .1s ease,border-color .1s ease}.copy-btn:hover{background:var(--eds-color-surface-alt);color:var(--eds-color-primary);border-color:var(--eds-color-border-strong)}.copy-btn:focus-visible{outline:2px solid var(--eds-color-primary);outline-offset:1px}\n"] }]
89
+ }], propDecorators: { value: [{
90
+ type: Input
91
+ }], label: [{
92
+ type: Input
93
+ }] } });
94
+
95
+ const TASK_TYPE_OPTIONS = [
96
+ 'Refill request',
97
+ 'Callback',
98
+ 'Billing',
99
+ 'Scheduling',
100
+ 'Clinical',
101
+ 'Other',
102
+ ];
103
+ function taskStatusLabel(status) {
104
+ if (status === 'in_progress')
105
+ return 'In progress';
106
+ if (status === 'done')
107
+ return 'Done';
108
+ return 'Open';
109
+ }
110
+ function taskStatusTone(status) {
111
+ const map = {
112
+ open: 'brand',
113
+ in_progress: 'notice',
114
+ done: 'pos',
115
+ };
116
+ return map[status];
117
+ }
118
+ function taskPriorityTone(priority) {
119
+ return priority === 'urgent' ? 'neg' : 'gray';
120
+ }
121
+ function taskPriorityLabel(priority) {
122
+ return priority === 'urgent' ? 'Urgent' : 'Normal';
123
+ }
124
+ function taskSourceLabel(source) {
125
+ if (source === 'voice')
126
+ return 'Voice';
127
+ if (source === 'sync')
128
+ return 'Sync';
129
+ return 'Manual';
130
+ }
131
+ function taskTypeTone(type) {
132
+ const key = type.toLowerCase();
133
+ if (key.includes('refill'))
134
+ return 'violet';
135
+ if (key.includes('callback'))
136
+ return 'brand';
137
+ if (key.includes('billing'))
138
+ return 'notice';
139
+ return 'gray';
140
+ }
141
+ function taskCallRoute(callId) {
142
+ return callId.startsWith('LC') ? ['../live', callId] : ['../history', callId];
143
+ }
144
+
145
+ class TaskDetailDrawerComponent {
146
+ constructor() {
147
+ this.task = input.required();
148
+ this.closed = output();
149
+ this.statusChange = output();
150
+ this.taskStatusLabel = taskStatusLabel;
151
+ this.taskStatusTone = taskStatusTone;
152
+ this.taskPriorityLabel = taskPriorityLabel;
153
+ this.taskPriorityTone = taskPriorityTone;
154
+ this.taskSourceLabel = taskSourceLabel;
155
+ this.taskTypeTone = taskTypeTone;
156
+ this.taskCallRoute = taskCallRoute;
157
+ }
158
+ assigneeInitials() {
159
+ const name = this.task().assignee?.trim();
160
+ if (!name || name === '—')
161
+ return '?';
162
+ const parts = name.split(/\s+/).filter(Boolean);
163
+ if (parts.length === 1)
164
+ return parts[0].slice(0, 2).toUpperCase();
165
+ return `${parts[0][0] ?? ''}${parts[parts.length - 1][0] ?? ''}`.toUpperCase();
166
+ }
167
+ close() {
168
+ this.closed.emit();
169
+ }
170
+ markDone() {
171
+ const t = this.task();
172
+ this.statusChange.emit(t.status === 'done' ? 'open' : 'done');
173
+ }
174
+ onBackdropClick(event) {
175
+ if (event.target === event.currentTarget)
176
+ this.close();
177
+ }
178
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: TaskDetailDrawerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
179
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: TaskDetailDrawerComponent, isStandalone: true, selector: "eds-task-detail-drawer", inputs: { task: { classPropertyName: "task", publicName: "task", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { closed: "closed", statusChange: "statusChange" }, ngImport: i0, template: "<div class=\"fixed inset-0 z-[200] flex justify-end bg-[rgba(15,23,42,0.4)]\" (click)=\"onBackdropClick($event)\">\n <aside\n class=\"task-drawer flex h-full w-[min(520px,100%)] flex-col bg-[#f7f8fa] shadow-[-8px_0_32px_rgba(15,23,42,0.12)]\"\n role=\"dialog\"\n aria-modal=\"true\"\n [attr.aria-label]=\"task().title\"\n >\n <header class=\"flex items-center gap-3 border-b border-zinc-200 bg-white px-4 py-3\">\n <eds-button\n variant=\"primary\"\n type=\"button\"\n class=\"mr-auto\"\n (click)=\"markDone()\"\n >\n <eds-icon name=\"check\" [size]=\"18\" />\n {{ task().status === 'done' ? 'Reopen task' : 'Mark as completed' }}\n </eds-button>\n <button\n type=\"button\"\n class=\"inline-flex h-9 w-9 cursor-pointer items-center justify-center rounded-md border-none bg-transparent text-zinc-500 hover:bg-zinc-100 hover:text-zinc-800\"\n (click)=\"close()\"\n aria-label=\"Close\"\n >\n <eds-icon name=\"close\" [size]=\"22\" />\n </button>\n </header>\n\n <div class=\"flex min-h-0 flex-1 flex-col gap-3 overflow-y-auto p-4\">\n <section class=\"rounded-xl border border-zinc-200 bg-white p-4\">\n <h2 class=\"m-0 text-xl font-semibold leading-snug text-zinc-900\">{{ task().title }}</h2>\n\n <div class=\"mt-4\">\n <h3 class=\"m-0 text-sm font-semibold text-zinc-800\">Description</h3>\n <p class=\"mt-2 mb-0 whitespace-pre-wrap text-sm leading-relaxed text-zinc-600\">\n {{ task().description || '\u2014' }}\n </p>\n </div>\n\n <div class=\"mt-5 flex flex-wrap items-center gap-x-5 gap-y-3 border-t border-zinc-100 pt-4 text-sm\">\n <div class=\"inline-flex items-center gap-2 font-medium\" [class.text-red-600]=\"task().priority === 'urgent'\" [class.text-zinc-700]=\"task().priority !== 'urgent'\">\n <span\n class=\"h-2.5 w-2.5 shrink-0 rotate-45 rounded-sm\"\n [class.bg-red-600]=\"task().priority === 'urgent'\"\n [class.bg-amber-500]=\"task().priority !== 'urgent'\"\n aria-hidden=\"true\"\n ></span>\n {{ task().priority === 'urgent' ? 'High Priority' : taskPriorityLabel(task().priority) }}\n </div>\n\n <div class=\"inline-flex items-center gap-2 text-zinc-700\">\n <span class=\"inline-flex h-7 w-7 items-center justify-center rounded-full bg-teal-100 text-[11px] font-bold text-teal-800\">\n {{ assigneeInitials() }}\n </span>\n <span class=\"text-zinc-500\">{{ task().assignee || 'Unassigned' }}</span>\n </div>\n\n <div class=\"inline-flex items-center gap-1.5 text-zinc-500\">\n <eds-icon name=\"schedule\" [size]=\"16\" />\n Created: {{ task().created | date: 'MM-dd-yyyy' }}\n </div>\n </div>\n </section>\n\n <section class=\"rounded-xl border border-zinc-200 bg-white px-4 py-3\">\n <div class=\"flex items-center justify-between gap-3\">\n <span class=\"text-sm font-medium text-zinc-800\">Patient</span>\n <span class=\"text-sm text-zinc-600\">{{ task().patient || '\u2014' }}</span>\n </div>\n </section>\n\n <section class=\"rounded-xl border border-zinc-200 bg-white px-4 py-3\">\n <div class=\"flex items-center justify-between gap-3\">\n <span class=\"text-sm font-medium text-zinc-800\">Status</span>\n <eds-badge [tone]=\"taskStatusTone(task().status)\">{{ taskStatusLabel(task().status) }}</eds-badge>\n </div>\n </section>\n\n <section class=\"rounded-xl border border-zinc-200 bg-white px-4 py-3\">\n <div class=\"flex items-center justify-between gap-3\">\n <span class=\"text-sm font-medium text-zinc-800\">Source</span>\n <span class=\"text-sm text-zinc-600\">{{ taskSourceLabel(task().source) }}</span>\n </div>\n </section>\n\n @if (task().callId) {\n <section class=\"rounded-xl border border-zinc-200 bg-white px-4 py-3\">\n <div class=\"flex items-center justify-between gap-3\">\n <span class=\"text-sm font-medium text-zinc-800\">Call</span>\n <a\n [routerLink]=\"taskCallRoute(task().callId!)\"\n class=\"text-sm font-medium text-blue-600 no-underline hover:underline\"\n >\n {{ task().callId }}\n </a>\n </div>\n </section>\n }\n\n @if (task().edvakTaskId || task().edvakStatus || task().medicationName || task().medicationId) {\n <section class=\"rounded-xl border border-zinc-200 bg-white p-4\">\n <h3 class=\"m-0 mb-3 text-sm font-semibold text-zinc-800\">Edvak / refill details</h3>\n <dl class=\"m-0 grid grid-cols-2 gap-4\">\n @if (task().edvakTaskId) {\n <div>\n <dt class=\"eds-label mb-1\">Edvak task ID</dt>\n <dd class=\"inline-flex items-center gap-2 text-sm\">\n <code class=\"rounded bg-zinc-100 px-2 py-1 font-mono text-xs\">{{ task().edvakTaskId }}</code>\n <app-copy-btn [value]=\"task().edvakTaskId\" label=\"Edvak task ID\" />\n </dd>\n </div>\n }\n @if (task().edvakStatus) {\n <div>\n <dt class=\"eds-label mb-1\">Edvak status</dt>\n <dd class=\"m-0 text-sm\"><eds-badge tone=\"brand\">{{ task().edvakStatus }}</eds-badge></dd>\n </div>\n }\n @if (task().medicationName) {\n <div>\n <dt class=\"eds-label mb-1\">Medication</dt>\n <dd class=\"m-0 text-sm text-zinc-700\">{{ task().medicationName }}</dd>\n </div>\n }\n @if (task().medicationId) {\n <div>\n <dt class=\"eds-label mb-1\">Medication ID</dt>\n <dd class=\"inline-flex items-center gap-2 text-sm\">\n <code class=\"rounded bg-zinc-100 px-2 py-1 font-mono text-xs\">{{ task().medicationId }}</code>\n <app-copy-btn [value]=\"task().medicationId\" label=\"medication ID\" />\n </dd>\n </div>\n }\n </dl>\n </section>\n }\n </div>\n </aside>\n</div>\n", styles: [".task-drawer{animation:task-drawer-in .2s ease}@keyframes task-drawer-in{0%{transform:translate(100%)}to{transform:translate(0)}}\n"], dependencies: [{ kind: "pipe", type: DatePipe, name: "date" }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: CopyButtonComponent, selector: "app-copy-btn", inputs: ["value", "label"] }, { kind: "component", type: EdsBadgeComponent, selector: "eds-badge", inputs: ["tone"] }, { kind: "component", type: EdsButtonComponent, selector: "eds-button", inputs: ["variant", "type", "disabled"] }, { kind: "component", type: EdsIconComponent, selector: "eds-icon", inputs: ["name", "size", "fill", "weight"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
180
+ }
181
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: TaskDetailDrawerComponent, decorators: [{
182
+ type: Component,
183
+ args: [{ selector: 'eds-task-detail-drawer', imports: [
184
+ DatePipe,
185
+ RouterLink,
186
+ CopyButtonComponent,
187
+ EdsBadgeComponent,
188
+ EdsButtonComponent,
189
+ EdsIconComponent,
190
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"fixed inset-0 z-[200] flex justify-end bg-[rgba(15,23,42,0.4)]\" (click)=\"onBackdropClick($event)\">\n <aside\n class=\"task-drawer flex h-full w-[min(520px,100%)] flex-col bg-[#f7f8fa] shadow-[-8px_0_32px_rgba(15,23,42,0.12)]\"\n role=\"dialog\"\n aria-modal=\"true\"\n [attr.aria-label]=\"task().title\"\n >\n <header class=\"flex items-center gap-3 border-b border-zinc-200 bg-white px-4 py-3\">\n <eds-button\n variant=\"primary\"\n type=\"button\"\n class=\"mr-auto\"\n (click)=\"markDone()\"\n >\n <eds-icon name=\"check\" [size]=\"18\" />\n {{ task().status === 'done' ? 'Reopen task' : 'Mark as completed' }}\n </eds-button>\n <button\n type=\"button\"\n class=\"inline-flex h-9 w-9 cursor-pointer items-center justify-center rounded-md border-none bg-transparent text-zinc-500 hover:bg-zinc-100 hover:text-zinc-800\"\n (click)=\"close()\"\n aria-label=\"Close\"\n >\n <eds-icon name=\"close\" [size]=\"22\" />\n </button>\n </header>\n\n <div class=\"flex min-h-0 flex-1 flex-col gap-3 overflow-y-auto p-4\">\n <section class=\"rounded-xl border border-zinc-200 bg-white p-4\">\n <h2 class=\"m-0 text-xl font-semibold leading-snug text-zinc-900\">{{ task().title }}</h2>\n\n <div class=\"mt-4\">\n <h3 class=\"m-0 text-sm font-semibold text-zinc-800\">Description</h3>\n <p class=\"mt-2 mb-0 whitespace-pre-wrap text-sm leading-relaxed text-zinc-600\">\n {{ task().description || '\u2014' }}\n </p>\n </div>\n\n <div class=\"mt-5 flex flex-wrap items-center gap-x-5 gap-y-3 border-t border-zinc-100 pt-4 text-sm\">\n <div class=\"inline-flex items-center gap-2 font-medium\" [class.text-red-600]=\"task().priority === 'urgent'\" [class.text-zinc-700]=\"task().priority !== 'urgent'\">\n <span\n class=\"h-2.5 w-2.5 shrink-0 rotate-45 rounded-sm\"\n [class.bg-red-600]=\"task().priority === 'urgent'\"\n [class.bg-amber-500]=\"task().priority !== 'urgent'\"\n aria-hidden=\"true\"\n ></span>\n {{ task().priority === 'urgent' ? 'High Priority' : taskPriorityLabel(task().priority) }}\n </div>\n\n <div class=\"inline-flex items-center gap-2 text-zinc-700\">\n <span class=\"inline-flex h-7 w-7 items-center justify-center rounded-full bg-teal-100 text-[11px] font-bold text-teal-800\">\n {{ assigneeInitials() }}\n </span>\n <span class=\"text-zinc-500\">{{ task().assignee || 'Unassigned' }}</span>\n </div>\n\n <div class=\"inline-flex items-center gap-1.5 text-zinc-500\">\n <eds-icon name=\"schedule\" [size]=\"16\" />\n Created: {{ task().created | date: 'MM-dd-yyyy' }}\n </div>\n </div>\n </section>\n\n <section class=\"rounded-xl border border-zinc-200 bg-white px-4 py-3\">\n <div class=\"flex items-center justify-between gap-3\">\n <span class=\"text-sm font-medium text-zinc-800\">Patient</span>\n <span class=\"text-sm text-zinc-600\">{{ task().patient || '\u2014' }}</span>\n </div>\n </section>\n\n <section class=\"rounded-xl border border-zinc-200 bg-white px-4 py-3\">\n <div class=\"flex items-center justify-between gap-3\">\n <span class=\"text-sm font-medium text-zinc-800\">Status</span>\n <eds-badge [tone]=\"taskStatusTone(task().status)\">{{ taskStatusLabel(task().status) }}</eds-badge>\n </div>\n </section>\n\n <section class=\"rounded-xl border border-zinc-200 bg-white px-4 py-3\">\n <div class=\"flex items-center justify-between gap-3\">\n <span class=\"text-sm font-medium text-zinc-800\">Source</span>\n <span class=\"text-sm text-zinc-600\">{{ taskSourceLabel(task().source) }}</span>\n </div>\n </section>\n\n @if (task().callId) {\n <section class=\"rounded-xl border border-zinc-200 bg-white px-4 py-3\">\n <div class=\"flex items-center justify-between gap-3\">\n <span class=\"text-sm font-medium text-zinc-800\">Call</span>\n <a\n [routerLink]=\"taskCallRoute(task().callId!)\"\n class=\"text-sm font-medium text-blue-600 no-underline hover:underline\"\n >\n {{ task().callId }}\n </a>\n </div>\n </section>\n }\n\n @if (task().edvakTaskId || task().edvakStatus || task().medicationName || task().medicationId) {\n <section class=\"rounded-xl border border-zinc-200 bg-white p-4\">\n <h3 class=\"m-0 mb-3 text-sm font-semibold text-zinc-800\">Edvak / refill details</h3>\n <dl class=\"m-0 grid grid-cols-2 gap-4\">\n @if (task().edvakTaskId) {\n <div>\n <dt class=\"eds-label mb-1\">Edvak task ID</dt>\n <dd class=\"inline-flex items-center gap-2 text-sm\">\n <code class=\"rounded bg-zinc-100 px-2 py-1 font-mono text-xs\">{{ task().edvakTaskId }}</code>\n <app-copy-btn [value]=\"task().edvakTaskId\" label=\"Edvak task ID\" />\n </dd>\n </div>\n }\n @if (task().edvakStatus) {\n <div>\n <dt class=\"eds-label mb-1\">Edvak status</dt>\n <dd class=\"m-0 text-sm\"><eds-badge tone=\"brand\">{{ task().edvakStatus }}</eds-badge></dd>\n </div>\n }\n @if (task().medicationName) {\n <div>\n <dt class=\"eds-label mb-1\">Medication</dt>\n <dd class=\"m-0 text-sm text-zinc-700\">{{ task().medicationName }}</dd>\n </div>\n }\n @if (task().medicationId) {\n <div>\n <dt class=\"eds-label mb-1\">Medication ID</dt>\n <dd class=\"inline-flex items-center gap-2 text-sm\">\n <code class=\"rounded bg-zinc-100 px-2 py-1 font-mono text-xs\">{{ task().medicationId }}</code>\n <app-copy-btn [value]=\"task().medicationId\" label=\"medication ID\" />\n </dd>\n </div>\n }\n </dl>\n </section>\n }\n </div>\n </aside>\n</div>\n", styles: [".task-drawer{animation:task-drawer-in .2s ease}@keyframes task-drawer-in{0%{transform:translate(100%)}to{transform:translate(0)}}\n"] }]
191
+ }] });
192
+
193
+ export { TaskDetailDrawerComponent as T, TASK_TYPE_OPTIONS as a, taskStatusTone as b, taskPriorityTone as c, taskSourceLabel as d, taskTypeTone as e, taskCallRoute as f, taskStatusLabel as t };
194
+ //# sourceMappingURL=edvak99-voice-receptionist-widget-task-detail-drawer.component-B3KmFJNH.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edvak99-voice-receptionist-widget-task-detail-drawer.component-B3KmFJNH.mjs","sources":["../../../projects/voice-receptionist-widget/src/lib/shared/copy-button.component.ts","../../../projects/voice-receptionist-widget/src/lib/utils/task.util.ts","../../../projects/voice-receptionist-widget/src/lib/components/task-detail-drawer/task-detail-drawer.component.ts","../../../projects/voice-receptionist-widget/src/lib/components/task-detail-drawer/task-detail-drawer.component.html"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n Input,\n inject,\n signal,\n} from '@angular/core';\n\nimport { ToastService } from './toast.service';\n\n@Component({\n selector: 'app-copy-btn',\n standalone: true,\n template: `\n @if (copyValue) {\n <button\n type=\"button\"\n class=\"copy-btn inline-flex shrink-0 items-center justify-center p-0\"\n (click)=\"onCopy($event)\"\n [attr.aria-label]=\"ariaLabel\"\n [title]=\"copied() ? 'Copied' : 'Copy to clipboard'\"\n >\n @if (copied()) {\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n } @else {\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\" />\n <path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\" />\n </svg>\n }\n </button>\n }\n `,\n styleUrl: './copy-button.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class CopyButtonComponent {\n /** Raw value to copy (full ID / phone / etc.) */\n @Input() value: string | null | undefined = '';\n /** Accessible label, e.g. \"patient ID\" */\n @Input() label = 'value';\n\n private readonly toast = inject(ToastService);\n\n protected readonly copied = signal(false);\n\n protected get copyValue(): string {\n const v = this.value?.trim();\n return v && v !== '—' ? v : '';\n }\n\n protected get ariaLabel(): string {\n return this.copied() ? 'Copied' : `Copy ${this.label}`;\n }\n\n async onCopy(event: MouseEvent): Promise<void> {\n event.stopPropagation();\n const text = this.copyValue;\n if (!text) return;\n\n try {\n await navigator.clipboard.writeText(text);\n this.copied.set(true);\n setTimeout(() => this.copied.set(false), 1500);\n } catch {\n this.toast.show('Could not copy — clipboard unavailable', 'error', 2500);\n }\n }\n}\n","import { BadgeTone } from '../ui/eds-badge.component';\nimport { TaskPriority, TaskSource, TaskStatus } from '../models/ai-receptionist.types';\n\nexport const TASK_TYPE_OPTIONS = [\n 'Refill request',\n 'Callback',\n 'Billing',\n 'Scheduling',\n 'Clinical',\n 'Other',\n] as const;\n\nexport function taskStatusLabel(status: TaskStatus): string {\n if (status === 'in_progress') return 'In progress';\n if (status === 'done') return 'Done';\n return 'Open';\n}\n\nexport function taskStatusTone(status: TaskStatus): BadgeTone {\n const map: Record<TaskStatus, BadgeTone> = {\n open: 'brand',\n in_progress: 'notice',\n done: 'pos',\n };\n return map[status];\n}\n\nexport function taskPriorityTone(priority: TaskPriority): BadgeTone {\n return priority === 'urgent' ? 'neg' : 'gray';\n}\n\nexport function taskPriorityLabel(priority: TaskPriority): string {\n return priority === 'urgent' ? 'Urgent' : 'Normal';\n}\n\nexport function taskSourceLabel(source: TaskSource): string {\n if (source === 'voice') return 'Voice';\n if (source === 'sync') return 'Sync';\n return 'Manual';\n}\n\nexport function taskTypeTone(type: string): BadgeTone {\n const key = type.toLowerCase();\n if (key.includes('refill')) return 'violet';\n if (key.includes('callback')) return 'brand';\n if (key.includes('billing')) return 'notice';\n return 'gray';\n}\n\nexport function taskCallRoute(callId: string): string[] {\n return callId.startsWith('LC') ? ['../live', callId] : ['../history', callId];\n}\n","import { DatePipe } from '@angular/common';\nimport {\n ChangeDetectionStrategy,\n Component,\n input,\n output,\n} from '@angular/core';\nimport { RouterLink } from '@angular/router';\n\nimport { TaskItem, TaskStatus } from '../../models/ai-receptionist.types';\nimport { CopyButtonComponent } from '../../shared/copy-button.component';\nimport { EdsBadgeComponent } from '../../ui/eds-badge.component';\nimport { EdsButtonComponent } from '../../ui/eds-button.component';\nimport { EdsIconComponent } from '../../ui/eds-icon.component';\nimport {\n taskCallRoute,\n taskPriorityLabel,\n taskPriorityTone,\n taskSourceLabel,\n taskStatusLabel,\n taskStatusTone,\n taskTypeTone,\n} from '../../utils/task.util';\n\n@Component({\n selector: 'eds-task-detail-drawer',\n imports: [\n DatePipe,\n RouterLink,\n CopyButtonComponent,\n EdsBadgeComponent,\n EdsButtonComponent,\n EdsIconComponent,\n ],\n templateUrl: './task-detail-drawer.component.html',\n styleUrl: './task-detail-drawer.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class TaskDetailDrawerComponent {\n readonly task = input.required<TaskItem>();\n\n readonly closed = output<void>();\n readonly statusChange = output<TaskStatus>();\n\n protected readonly taskStatusLabel = taskStatusLabel;\n protected readonly taskStatusTone = taskStatusTone;\n protected readonly taskPriorityLabel = taskPriorityLabel;\n protected readonly taskPriorityTone = taskPriorityTone;\n protected readonly taskSourceLabel = taskSourceLabel;\n protected readonly taskTypeTone = taskTypeTone;\n protected readonly taskCallRoute = taskCallRoute;\n\n protected assigneeInitials(): string {\n const name = this.task().assignee?.trim();\n if (!name || name === '—') return '?';\n const parts = name.split(/\\s+/).filter(Boolean);\n if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();\n return `${parts[0][0] ?? ''}${parts[parts.length - 1][0] ?? ''}`.toUpperCase();\n }\n\n protected close(): void {\n this.closed.emit();\n }\n\n protected markDone(): void {\n const t = this.task();\n this.statusChange.emit(t.status === 'done' ? 'open' : 'done');\n }\n\n protected onBackdropClick(event: MouseEvent): void {\n if (event.target === event.currentTarget) this.close();\n }\n}\n","<div class=\"fixed inset-0 z-[200] flex justify-end bg-[rgba(15,23,42,0.4)]\" (click)=\"onBackdropClick($event)\">\n <aside\n class=\"task-drawer flex h-full w-[min(520px,100%)] flex-col bg-[#f7f8fa] shadow-[-8px_0_32px_rgba(15,23,42,0.12)]\"\n role=\"dialog\"\n aria-modal=\"true\"\n [attr.aria-label]=\"task().title\"\n >\n <header class=\"flex items-center gap-3 border-b border-zinc-200 bg-white px-4 py-3\">\n <eds-button\n variant=\"primary\"\n type=\"button\"\n class=\"mr-auto\"\n (click)=\"markDone()\"\n >\n <eds-icon name=\"check\" [size]=\"18\" />\n {{ task().status === 'done' ? 'Reopen task' : 'Mark as completed' }}\n </eds-button>\n <button\n type=\"button\"\n class=\"inline-flex h-9 w-9 cursor-pointer items-center justify-center rounded-md border-none bg-transparent text-zinc-500 hover:bg-zinc-100 hover:text-zinc-800\"\n (click)=\"close()\"\n aria-label=\"Close\"\n >\n <eds-icon name=\"close\" [size]=\"22\" />\n </button>\n </header>\n\n <div class=\"flex min-h-0 flex-1 flex-col gap-3 overflow-y-auto p-4\">\n <section class=\"rounded-xl border border-zinc-200 bg-white p-4\">\n <h2 class=\"m-0 text-xl font-semibold leading-snug text-zinc-900\">{{ task().title }}</h2>\n\n <div class=\"mt-4\">\n <h3 class=\"m-0 text-sm font-semibold text-zinc-800\">Description</h3>\n <p class=\"mt-2 mb-0 whitespace-pre-wrap text-sm leading-relaxed text-zinc-600\">\n {{ task().description || '—' }}\n </p>\n </div>\n\n <div class=\"mt-5 flex flex-wrap items-center gap-x-5 gap-y-3 border-t border-zinc-100 pt-4 text-sm\">\n <div class=\"inline-flex items-center gap-2 font-medium\" [class.text-red-600]=\"task().priority === 'urgent'\" [class.text-zinc-700]=\"task().priority !== 'urgent'\">\n <span\n class=\"h-2.5 w-2.5 shrink-0 rotate-45 rounded-sm\"\n [class.bg-red-600]=\"task().priority === 'urgent'\"\n [class.bg-amber-500]=\"task().priority !== 'urgent'\"\n aria-hidden=\"true\"\n ></span>\n {{ task().priority === 'urgent' ? 'High Priority' : taskPriorityLabel(task().priority) }}\n </div>\n\n <div class=\"inline-flex items-center gap-2 text-zinc-700\">\n <span class=\"inline-flex h-7 w-7 items-center justify-center rounded-full bg-teal-100 text-[11px] font-bold text-teal-800\">\n {{ assigneeInitials() }}\n </span>\n <span class=\"text-zinc-500\">{{ task().assignee || 'Unassigned' }}</span>\n </div>\n\n <div class=\"inline-flex items-center gap-1.5 text-zinc-500\">\n <eds-icon name=\"schedule\" [size]=\"16\" />\n Created: {{ task().created | date: 'MM-dd-yyyy' }}\n </div>\n </div>\n </section>\n\n <section class=\"rounded-xl border border-zinc-200 bg-white px-4 py-3\">\n <div class=\"flex items-center justify-between gap-3\">\n <span class=\"text-sm font-medium text-zinc-800\">Patient</span>\n <span class=\"text-sm text-zinc-600\">{{ task().patient || '—' }}</span>\n </div>\n </section>\n\n <section class=\"rounded-xl border border-zinc-200 bg-white px-4 py-3\">\n <div class=\"flex items-center justify-between gap-3\">\n <span class=\"text-sm font-medium text-zinc-800\">Status</span>\n <eds-badge [tone]=\"taskStatusTone(task().status)\">{{ taskStatusLabel(task().status) }}</eds-badge>\n </div>\n </section>\n\n <section class=\"rounded-xl border border-zinc-200 bg-white px-4 py-3\">\n <div class=\"flex items-center justify-between gap-3\">\n <span class=\"text-sm font-medium text-zinc-800\">Source</span>\n <span class=\"text-sm text-zinc-600\">{{ taskSourceLabel(task().source) }}</span>\n </div>\n </section>\n\n @if (task().callId) {\n <section class=\"rounded-xl border border-zinc-200 bg-white px-4 py-3\">\n <div class=\"flex items-center justify-between gap-3\">\n <span class=\"text-sm font-medium text-zinc-800\">Call</span>\n <a\n [routerLink]=\"taskCallRoute(task().callId!)\"\n class=\"text-sm font-medium text-blue-600 no-underline hover:underline\"\n >\n {{ task().callId }}\n </a>\n </div>\n </section>\n }\n\n @if (task().edvakTaskId || task().edvakStatus || task().medicationName || task().medicationId) {\n <section class=\"rounded-xl border border-zinc-200 bg-white p-4\">\n <h3 class=\"m-0 mb-3 text-sm font-semibold text-zinc-800\">Edvak / refill details</h3>\n <dl class=\"m-0 grid grid-cols-2 gap-4\">\n @if (task().edvakTaskId) {\n <div>\n <dt class=\"eds-label mb-1\">Edvak task ID</dt>\n <dd class=\"inline-flex items-center gap-2 text-sm\">\n <code class=\"rounded bg-zinc-100 px-2 py-1 font-mono text-xs\">{{ task().edvakTaskId }}</code>\n <app-copy-btn [value]=\"task().edvakTaskId\" label=\"Edvak task ID\" />\n </dd>\n </div>\n }\n @if (task().edvakStatus) {\n <div>\n <dt class=\"eds-label mb-1\">Edvak status</dt>\n <dd class=\"m-0 text-sm\"><eds-badge tone=\"brand\">{{ task().edvakStatus }}</eds-badge></dd>\n </div>\n }\n @if (task().medicationName) {\n <div>\n <dt class=\"eds-label mb-1\">Medication</dt>\n <dd class=\"m-0 text-sm text-zinc-700\">{{ task().medicationName }}</dd>\n </div>\n }\n @if (task().medicationId) {\n <div>\n <dt class=\"eds-label mb-1\">Medication ID</dt>\n <dd class=\"inline-flex items-center gap-2 text-sm\">\n <code class=\"rounded bg-zinc-100 px-2 py-1 font-mono text-xs\">{{ task().medicationId }}</code>\n <app-copy-btn [value]=\"task().medicationId\" label=\"medication ID\" />\n </dd>\n </div>\n }\n </dl>\n </section>\n }\n </div>\n </aside>\n</div>\n"],"names":[],"mappings":"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"}