@edvak99/voice-receptionist-widget 1.1.2 → 1.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-analytics-page.component-CW5OKmik.mjs → edvak99-voice-receptionist-widget-analytics-page.component-Dsujn5az.mjs} +4 -4
- package/fesm2022/{edvak99-voice-receptionist-widget-analytics-page.component-CW5OKmik.mjs.map → edvak99-voice-receptionist-widget-analytics-page.component-Dsujn5az.mjs.map} +1 -1
- package/fesm2022/edvak99-voice-receptionist-widget-audit-page.component-xoLlHj8K.mjs +67 -0
- package/fesm2022/edvak99-voice-receptionist-widget-audit-page.component-xoLlHj8K.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-call-history-detail-page.component-CTwfUHUf.mjs → edvak99-voice-receptionist-widget-call-history-detail-page.component-2K9W77As.mjs} +11 -11
- package/fesm2022/{edvak99-voice-receptionist-widget-call-history-detail-page.component-CTwfUHUf.mjs.map → edvak99-voice-receptionist-widget-call-history-detail-page.component-2K9W77As.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-call-history-page.component-Cj4wxd4e.mjs → edvak99-voice-receptionist-widget-call-history-page.component-B5AnEjoh.mjs} +62 -26
- package/fesm2022/edvak99-voice-receptionist-widget-call-history-page.component-B5AnEjoh.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-call-recording-player.component-AN6GcSDq.mjs → edvak99-voice-receptionist-widget-call-recording-player.component-B8_qp7Fe.mjs} +4 -4
- package/fesm2022/{edvak99-voice-receptionist-widget-call-recording-player.component-AN6GcSDq.mjs.map → edvak99-voice-receptionist-widget-call-recording-player.component-B8_qp7Fe.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-call-review.service-Cy_Bf7AO.mjs → edvak99-voice-receptionist-widget-call-review.service-Cj2XTeK4.mjs} +2 -2
- package/fesm2022/{edvak99-voice-receptionist-widget-call-review.service-Cy_Bf7AO.mjs.map → edvak99-voice-receptionist-widget-call-review.service-Cj2XTeK4.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-call-review.util-DQLIw7xb.mjs → edvak99-voice-receptionist-widget-call-review.util-BgsBCKgZ.mjs} +2 -2
- package/fesm2022/{edvak99-voice-receptionist-widget-call-review.util-DQLIw7xb.mjs.map → edvak99-voice-receptionist-widget-call-review.util-BgsBCKgZ.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-dashboard-page.component-DzdIt2A7.mjs → edvak99-voice-receptionist-widget-dashboard-page.component-BNdnbAVM.mjs} +10 -10
- package/fesm2022/{edvak99-voice-receptionist-widget-dashboard-page.component-DzdIt2A7.mjs.map → edvak99-voice-receptionist-widget-dashboard-page.component-BNdnbAVM.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-eds-avatar.component-PCnIWeOA.mjs → edvak99-voice-receptionist-widget-eds-avatar.component-CbphhP6o.mjs} +3 -3
- package/fesm2022/{edvak99-voice-receptionist-widget-eds-avatar.component-PCnIWeOA.mjs.map → edvak99-voice-receptionist-widget-eds-avatar.component-CbphhP6o.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-eds-elapsed.pipe-ouRlPpwT.mjs → edvak99-voice-receptionist-widget-eds-elapsed.pipe-BgLsnq6A.mjs} +2 -2
- package/fesm2022/{edvak99-voice-receptionist-widget-eds-elapsed.pipe-ouRlPpwT.mjs.map → edvak99-voice-receptionist-widget-eds-elapsed.pipe-BgLsnq6A.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-CMhknpGf.mjs → edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-Dn0GrZ6_.mjs} +106 -48
- package/fesm2022/edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-Dn0GrZ6_.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-knowledge-hub.page-cZqBuull.mjs → edvak99-voice-receptionist-widget-knowledge-hub.page-BngGx_Lc.mjs} +70 -36
- package/fesm2022/edvak99-voice-receptionist-widget-knowledge-hub.page-BngGx_Lc.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-live-calls-list.service-CDtFRW8w.mjs → edvak99-voice-receptionist-widget-live-calls-list.service-0kGWO6sh.mjs} +3 -3
- package/fesm2022/{edvak99-voice-receptionist-widget-live-calls-list.service-CDtFRW8w.mjs.map → edvak99-voice-receptionist-widget-live-calls-list.service-0kGWO6sh.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-live-calls-page.component-DrYzXJQW.mjs → edvak99-voice-receptionist-widget-live-calls-page.component-DfLmK89M.mjs} +7 -7
- package/fesm2022/{edvak99-voice-receptionist-widget-live-calls-page.component-DrYzXJQW.mjs.map → edvak99-voice-receptionist-widget-live-calls-page.component-DfLmK89M.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-live-monitor-page.component-D7dlk0y2.mjs → edvak99-voice-receptionist-widget-live-monitor-page.component-DNpLFqBw.mjs} +11 -11
- package/fesm2022/{edvak99-voice-receptionist-widget-live-monitor-page.component-D7dlk0y2.mjs.map → edvak99-voice-receptionist-widget-live-monitor-page.component-DNpLFqBw.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-outbound-purposes-page.component-CJ8NEjcj.mjs → edvak99-voice-receptionist-widget-outbound-purposes-page.component-CYSZ832p.mjs} +6 -6
- package/fesm2022/{edvak99-voice-receptionist-widget-outbound-purposes-page.component-CJ8NEjcj.mjs.map → edvak99-voice-receptionist-widget-outbound-purposes-page.component-CYSZ832p.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-settings-page.component-Bo3XNK3b.mjs → edvak99-voice-receptionist-widget-settings-page.component-B9nv6wtB.mjs} +4 -4
- package/fesm2022/{edvak99-voice-receptionist-widget-settings-page.component-Bo3XNK3b.mjs.map → edvak99-voice-receptionist-widget-settings-page.component-B9nv6wtB.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-tasks-page.component-CBwl15NP.mjs → edvak99-voice-receptionist-widget-tasks-page.component-DXxjMVUv.mjs} +40 -11
- package/fesm2022/edvak99-voice-receptionist-widget-tasks-page.component-DXxjMVUv.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-wizard-page.component-CJLa5pia.mjs → edvak99-voice-receptionist-widget-wizard-page.component-C1Z6yC0q.mjs} +4 -4
- package/fesm2022/{edvak99-voice-receptionist-widget-wizard-page.component-CJLa5pia.mjs.map → edvak99-voice-receptionist-widget-wizard-page.component-C1Z6yC0q.mjs.map} +1 -1
- package/fesm2022/edvak99-voice-receptionist-widget.mjs +1 -1
- package/lib/knowledge/models/practice-faq.model.d.ts +3 -0
- package/lib/knowledge/pages/knowledge-hub.page.d.ts +8 -1
- package/lib/knowledge/services/practice-faq-api.service.d.ts +6 -2
- package/lib/models/ai-receptionist.types.d.ts +1 -0
- package/lib/models/pagination.d.ts +11 -0
- package/lib/pages/audit-page/audit-page.component.d.ts +7 -0
- package/lib/pages/call-history-page/call-history-page.component.d.ts +7 -3
- package/lib/pages/tasks-page/tasks-page.component.d.ts +6 -0
- package/lib/services/ai-receptionist-api.mock.d.ts +10 -9
- package/lib/services/ai-receptionist-api.service.d.ts +9 -9
- package/package.json +1 -1
- package/styles/_index.scss +5 -40
- package/styles/chat-ui.scss +18 -18
- package/styles/eds.scss +135 -95
- package/fesm2022/edvak99-voice-receptionist-widget-audit-page.component-DL1GfQyF.mjs +0 -35
- package/fesm2022/edvak99-voice-receptionist-widget-audit-page.component-DL1GfQyF.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-call-history-page.component-Cj4wxd4e.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-CMhknpGf.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-knowledge-hub.page-cZqBuull.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-tasks-page.component-CBwl15NP.mjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"edvak99-voice-receptionist-widget-settings-page.component-Bo3XNK3b.mjs","sources":["../../../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":["/** Curated ElevenLabs voices — keep in sync with backend `tts-voice-presets.ts`. */\n\nexport interface TtsVoicePreset {\n id: string;\n label: string;\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 },\n {\n id: 'NUjosfEayZAdRcDmcHM8',\n label: 'Madison – Cool, Calm & Conversational',\n },\n {\n id: 'gE0owC0H9C8SzfDyIUtB',\n label: 'Ivanna – Sassy, Condescending and Clear',\n },\n {\n id: 'Uc7anshoV8mdBhDnEZEX',\n label: 'Cecily – Clear and Warm',\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 SETTINGS_SECTION_META: Record<SettingsSection, SettingsSectionMeta> = {\n general: {\n title: 'General',\n description: 'Practice identity and how the AI introduces itself on calls.',\n },\n phone: {\n title: 'Phone',\n description: 'Inbound routing, after-hours behavior, and ring timing.',\n },\n tasks: {\n title: 'Tasks & follow-ups',\n description: 'When the AI should create staff tasks after a call.',\n },\n scheduling: {\n title: 'Scheduling',\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: 'Escalation',\n description: 'When to offer a human or transfer to reception.',\n },\n outbound: {\n title: 'Outbound calling',\n description: 'Outbound dialer defaults. Purpose templates are managed separately.',\n },\n transcripts: {\n title: 'Transcripts & recording',\n description: 'Retention and PHI handling for call transcripts.',\n },\n advanced: {\n title: 'Advanced',\n description: 'Model and debug options — read-only. Contact Edvak support to change.',\n },\n};\n\n/** Entire sections where every field is read-only (including unknown API fields). */\nexport const READ_ONLY_SECTIONS = new Set<SettingsSection>(['advanced', 'verify']);\n\n/** Settings tabs that stay visible but cannot be selected/edited. */\nexport const DISABLED_SETTINGS_TABS = new Set<SettingsSection>(['verify']);\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: 'practiceName', reason: 'Core practice identity' },\n { section: 'general', key: 'agentName', reason: 'AI agent identity' },\n { section: 'general', key: 'timezone', reason: 'Practice timezone' },\n { section: 'general', key: 'language', reason: 'Default language' },\n { section: 'phone', key: 'mainNumber', reason: 'Inbound phone routing' },\n { section: 'outbound', key: 'callerId', reason: 'Outbound caller ID' },\n { section: 'transcripts', key: 'retainDays', reason: 'Recording retention policy' },\n { section: 'transcripts', key: 'redactPhi', reason: 'PHI redaction policy' },\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: 'practiceName',\n label: 'Practice name',\n description: 'Spoken on greetings and confirmations.',\n type: 'text',\n },\n {\n key: 'agentName',\n label: 'AI agent name',\n description: 'How the assistant introduces itself (e.g. “Ava”).',\n type: 'text',\n },\n {\n key: 'timezone',\n label: 'Timezone',\n description: 'Used for hours, scheduling, and call timestamps.',\n type: 'text',\n },\n {\n key: 'language',\n label: 'Default language',\n description: 'Primary language for the AI receptionist.',\n type: 'text',\n },\n {\n key: 'ttsVoiceId',\n label: 'Voice',\n description: 'Spoken voice used on phone calls for this practice.',\n type: 'select',\n options: TTS_VOICE_PRESETS.map((p) => ({ value: p.id, label: p.label })),\n },\n ],\n phone: [\n {\n key: 'mainNumber',\n label: 'Main phone number',\n description: 'Primary inbound number patients call.',\n type: 'text',\n },\n {\n key: 'afterHours',\n label: 'After-hours mode',\n description: 'Use after-hours greeting and routing outside business hours.',\n type: 'boolean',\n },\n {\n key: 'ringTimeout',\n label: 'Ring timeout (seconds)',\n description: 'How long to ring before the AI answers.',\n type: 'number',\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 transcripts: [\n {\n key: 'retainDays',\n label: 'Retention (days)',\n description: 'How long transcripts and recordings are kept.',\n type: 'number',\n },\n {\n key: 'redactPhi',\n label: 'Redact PHI in transcripts',\n description: 'Mask sensitive identifiers in stored transcripts.',\n type: 'boolean',\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","import { ChangeDetectionStrategy, Component, computed, inject, OnInit, signal } from '@angular/core';\n\nimport { FormsModule } from '@angular/forms';\n\nimport { RouterLink } from '@angular/router';\n\n\n\nimport { AgentSettings } from '../../models/ai-receptionist.types';\n\nimport { AiReceptionistApiService } from '../../services/ai-receptionist-api.service';\n\nimport { EdsBadgeComponent } from '../../ui/eds-badge.component';\n\nimport { EdsButtonComponent } from '../../ui/eds-button.component';\n\nimport { EdsIconComponent } from '../../ui/eds-icon.component';\n\nimport { ToastService } from '../../shared/toast.service';\n\nimport {\n\n buildAutoWelcomeTemplate,\n\n resolveWelcomePreview,\n\n WELCOME_MESSAGE_MAX,\n\n} from '../../utils/welcome-message.util';\n\nimport {\n DISABLED_SETTINGS_TABS,\n isFieldReadOnly,\n READ_ONLY_SECTIONS,\n resolveFieldMeta,\n SETTINGS_FIELDS,\n SETTINGS_SECTION_META,\n SettingsFieldMeta,\n SettingsSection,\n} from './settings-fields.config';\n\n\n\ntype SettingsTab = keyof AgentSettings;\n\n\n\nconst GENERAL_IDENTITY_KEYS = new Set(['practiceName', 'agentName']);\n\nconst GENERAL_OTHER_KEYS = new Set(['timezone', 'language', 'ttsVoiceId']);\n\n\n\n@Component({\n selector: 'eds-settings-page',\n imports: [FormsModule, RouterLink, EdsBadgeComponent, EdsButtonComponent, EdsIconComponent],\n templateUrl: './settings-page.component.html',\n styleUrl: './settings-page.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush\n})\n\nexport class SettingsPageComponent implements OnInit {\n\n private readonly api = inject(AiReceptionistApiService);\n\n private readonly toast = inject(ToastService);\n\n private originalSettings: AgentSettings | null = null;\n\n protected readonly isFieldReadOnly = isFieldReadOnly;\n\n protected readonly readOnlySections = READ_ONLY_SECTIONS;\n\n protected readonly disabledTabs = DISABLED_SETTINGS_TABS;\n\n\n\n protected readonly settings = signal<AgentSettings | null>(null);\n\n protected readonly tab = signal<SettingsTab>('general');\n\n protected readonly loading = signal(true);\n\n protected readonly saving = signal(false);\n\n protected readonly saved = signal(false);\n\n\n\n protected readonly welcomeMax = WELCOME_MESSAGE_MAX;\n\n protected readonly previewingVoice = signal(false);\n\n private voicePreviewAudio: HTMLAudioElement | null = null;\n\n\n\n protected readonly tabs: { id: SettingsTab; label: string; icon: string }[] = [\n\n { id: 'general', label: 'General', icon: 'business' },\n\n { id: 'phone', label: 'Phone', icon: 'call' },\n\n { id: 'tasks', label: 'Tasks', icon: 'task_alt' },\n\n { id: 'scheduling', label: 'Scheduling', icon: 'calendar_month' },\n\n { id: 'refill', label: 'Refills', icon: 'medication' },\n\n { id: 'verify', label: 'Verification', icon: 'verified_user' },\n\n { id: 'escalation', label: 'Escalation', icon: 'warning' },\n\n { id: 'outbound', label: 'Outbound', icon: 'call_made' },\n\n { id: 'transcripts', label: 'Transcripts', icon: 'transcribe' },\n\n { id: 'advanced', label: 'Advanced', icon: 'tune' },\n\n { id: 'safety', label: 'Safety', icon: 'health_and_safety' },\n\n ];\n\n\n\n protected readonly sectionMeta = computed(() => {\n\n const id = this.tab();\n\n if (id === 'safety') {\n\n return { title: 'Safety checklist', description: '' };\n\n }\n\n return SETTINGS_SECTION_META[id as SettingsSection];\n\n });\n\n\n\n protected readonly fieldsForTab = computed((): SettingsFieldMeta[] => {\n\n const s = this.settings();\n\n const id = this.tab();\n\n if (!s || id === 'safety') return [];\n\n\n\n const section = s[id] as Record<string, string | boolean | number>;\n\n const configured = SETTINGS_FIELDS[id as SettingsSection] ?? [];\n\n const configuredKeys = new Set(configured.map((f) => f.key));\n\n\n\n const extras = Object.keys(section)\n\n .filter((key) => key !== 'welcomeMessage' && !configuredKeys.has(key))\n\n .map((key) => resolveFieldMeta(id as SettingsSection, key, section[key]));\n\n\n\n return [...configured, ...extras];\n\n });\n\n\n\n protected readonly generalIdentityFields = computed(() =>\n\n this.fieldsForTab().filter((f) => GENERAL_IDENTITY_KEYS.has(f.key)),\n\n );\n\n\n\n protected readonly generalOtherFields = computed(() =>\n\n this.fieldsForTab().filter((f) => GENERAL_OTHER_KEYS.has(f.key)),\n\n );\n\n\n\n protected readonly welcomeMessage = computed(() =>\n\n String(this.settings()?.general['welcomeMessage'] ?? ''),\n\n );\n\n\n\n protected readonly welcomePlaceholder = computed(() => {\n\n const s = this.settings();\n\n if (!s) return '';\n\n return buildAutoWelcomeTemplate(\n\n String(s.general['practiceName'] ?? ''),\n\n String(s.general['agentName'] ?? ''),\n\n );\n\n });\n\n\n\n protected readonly welcomePreview = computed(() => {\n\n const s = this.settings();\n\n if (!s) return '';\n\n return resolveWelcomePreview(\n\n String(s.general['welcomeMessage'] ?? ''),\n\n String(s.general['practiceName'] ?? ''),\n\n String(s.general['agentName'] ?? ''),\n\n );\n\n });\n\n\n\n protected readonly usingDefaultWelcome = computed(() => !this.welcomeMessage().trim());\n\n\n\n protected readonly showRecordingConsentHint = computed(() => {\n\n const t = this.settings()?.transcripts;\n\n if (!t) return false;\n\n const retain = Number(t['retainDays'] ?? 0);\n\n return retain > 0 || t['redactPhi'] === true;\n\n });\n\n\n\n ngOnInit(): void {\n\n this.api.getSettings().subscribe({\n\n next: ({ data }) => {\n\n this.originalSettings = structuredClone(data);\n\n this.settings.set(structuredClone(data));\n\n this.loading.set(false);\n\n },\n\n error: () => {\n\n this.loading.set(false);\n\n this.toast.show('Failed to load agent settings', 'error');\n\n },\n\n });\n\n }\n\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.tab.set(id);\n }\n\n\n\n protected updateField(section: SettingsTab, key: string, value: string | boolean | number): void {\n\n const current = this.settings();\n\n if (!current || section === 'safety' || isFieldReadOnly(section as SettingsSection, key)) return;\n\n const sectionData = { ...(current[section] as Record<string, string | boolean | number>) };\n\n sectionData[key] = value;\n\n this.settings.set({ ...current, [section]: sectionData });\n\n }\n\n\n\n protected updateWelcomeMessage(value: string): void {\n\n this.updateField('general', 'welcomeMessage', value.slice(0, WELCOME_MESSAGE_MAX));\n\n }\n\n\n\n protected resetWelcomeMessage(): void {\n\n this.updateField('general', 'welcomeMessage', '');\n\n }\n\n protected previewSelectedVoice(): void {\n const voiceId = String(this.fieldValue('general', 'ttsVoiceId') ?? '').trim();\n if (!voiceId || this.previewingVoice()) return;\n\n this.previewingVoice.set(true);\n this.api.previewVoice(voiceId).subscribe({\n next: (blob) => {\n this.previewingVoice.set(false);\n if (this.voicePreviewAudio) {\n this.voicePreviewAudio.pause();\n URL.revokeObjectURL(this.voicePreviewAudio.src);\n this.voicePreviewAudio = null;\n }\n const url = URL.createObjectURL(blob);\n const audio = new Audio(url);\n this.voicePreviewAudio = audio;\n audio.onended = () => {\n URL.revokeObjectURL(url);\n if (this.voicePreviewAudio === audio) this.voicePreviewAudio = null;\n };\n void audio.play().catch(() => {\n this.toast.show('Could not play voice preview in this browser.', 'error');\n URL.revokeObjectURL(url);\n });\n },\n error: () => {\n this.previewingVoice.set(false);\n this.toast.show('Could not generate voice preview. Try again.', 'error');\n },\n });\n }\n\n\n\n protected fieldValue(section: SettingsTab, key: string): string | boolean | number {\n\n const s = this.settings();\n\n if (!s || section === 'safety') return '';\n\n return (s[section] as Record<string, string | boolean | number>)[key];\n\n }\n\n\n\n protected save(): void {\n\n const s = this.settings();\n\n const orig = this.originalSettings;\n\n if (!s || !orig) return;\n\n\n\n const payload = structuredClone(s);\n\n const wm = String(payload.general['welcomeMessage'] ?? '').trim();\n\n payload.general['welcomeMessage'] = wm;\n\n this.restoreReadOnlyFields(payload, orig);\n\n\n\n this.saving.set(true);\n\n this.api.putSettings(payload).subscribe({\n\n next: ({ data }) => {\n\n this.originalSettings = structuredClone(data);\n\n this.settings.set(structuredClone(data));\n\n this.saving.set(false);\n\n this.saved.set(true);\n\n this.toast.show('Agent settings saved', 'success');\n\n setTimeout(() => this.saved.set(false), 2000);\n\n },\n\n error: () => {\n\n this.saving.set(false);\n\n this.toast.show('Failed to save agent settings', 'error');\n\n },\n\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 '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}\n\n\n","<div class=\"eds-page settings-page\">\n <header class=\"settings-page__header\">\n <div>\n <h1 class=\"eds-h1\">Agent settings</h1>\n <p class=\"settings-page__subtitle\">Configure AI receptionist behavior and safety</p>\n </div>\n <div class=\"settings-page__save-row\">\n @if (saved()) {\n <span class=\"settings-page__saved\">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=\"settings-page__loading\">Loading settings…</p>\n } @else if (settings()) {\n <div class=\"settings-page__layout\">\n <nav class=\"eds-card settings-page__sidebar\" aria-label=\"Settings sections\">\n @for (t of tabs; track t.id) {\n <button\n type=\"button\"\n class=\"settings-page__nav-item\"\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 <eds-icon [name]=\"t.icon\" [size]=\"18\" />\n {{ t.label }}\n @if (isTabDisabled(t.id)) {\n <span class=\"settings-page__nav-disabled-badge\">Disabled</span>\n }\n </button>\n }\n </nav>\n\n <article class=\"eds-card settings-page__panel\">\n @if (tab() === 'safety') {\n <header class=\"settings-page__panel-head\">\n <h2 class=\"settings-page__panel-title\">Safety checklist</h2>\n <p class=\"settings-page__panel-desc\">\n Read-only compliance status. Contact Edvak support to change safety configuration.\n </p>\n </header>\n <ul class=\"settings-page__safety\">\n @for (item of settings()!.safety; track item.id) {\n <li>\n <eds-icon\n [name]=\"item.status === 'ok' ? 'check_circle' : 'error'\"\n [size]=\"22\"\n />\n <span class=\"settings-page__safety-label\">{{ item.label }}</span>\n <eds-badge [tone]=\"item.status === 'ok' ? 'pos' : 'notice'\">\n {{ item.status === 'ok' ? 'Pass' : 'Needs attention' }}\n </eds-badge>\n </li>\n }\n </ul>\n } @else {\n <header class=\"settings-page__panel-head\">\n <h2 class=\"settings-page__panel-title\">{{ sectionMeta().title }}</h2>\n <p class=\"settings-page__panel-desc\">{{ sectionMeta().description }}</p>\n </header>\n\n @if (sectionIsReadOnly(tab())) {\n <p class=\"settings-page__readonly-banner\">\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() === 'general') {\n <a routerLink=\"../knowledge\" class=\"settings-page__quick-link\">\n <eds-icon name=\"menu_book\" [size]=\"22\" />\n <div>\n <span class=\"settings-page__quick-link-title\">Practice Knowledge Base</span>\n <span class=\"settings-page__quick-link-desc\">FAQ answers your AI uses on phone calls</span>\n </div>\n <eds-icon name=\"chevron_right\" [size]=\"20\" />\n </a>\n\n <div class=\"settings-page__fields settings-page__fields--general\">\n @for (field of generalIdentityFields(); track field.key) {\n <label\n class=\"settings-page__field\"\n [class.settings-page__field--readonly]=\"isFieldReadOnly('general', field.key)\"\n >\n <span class=\"settings-page__field-label\">\n {{ field.label }}\n @if (isFieldReadOnly('general', field.key)) {\n <span class=\"settings-page__readonly-badge\">Read-only</span>\n }\n </span>\n @if (field.description) {\n <span class=\"settings-page__field-desc\">{{ field.description }}</span>\n }\n <input\n type=\"text\"\n class=\"settings-page__input\"\n [class.settings-page__input--readonly]=\"isFieldReadOnly('general', field.key)\"\n [disabled]=\"isFieldReadOnly('general', field.key)\"\n [ngModel]=\"fieldValue('general', field.key)\"\n (ngModelChange)=\"updateField('general', field.key, $event)\"\n />\n </label>\n }\n\n <section class=\"settings-page__welcome\">\n <label class=\"settings-page__field settings-page__field--full\">\n <span class=\"settings-page__field-label\">Welcome message</span>\n <span class=\"settings-page__field-desc\">\n Spoken automatically when a caller connects. Leave blank to use the default template.\n </span>\n <textarea\n class=\"settings-page__textarea\"\n rows=\"4\"\n [maxlength]=\"welcomeMax\"\n [placeholder]=\"welcomePlaceholder()\"\n [ngModel]=\"welcomeMessage()\"\n (ngModelChange)=\"updateWelcomeMessage($event)\"\n ></textarea>\n <span class=\"settings-page__char-count\">\n {{ welcomeMessage().length }}/{{ welcomeMax }}\n </span>\n @if (showRecordingConsentHint()) {\n <p class=\"settings-page__recording-hint\">\n Call recording is enabled — consider mentioning that the call may be recorded or monitored.\n </p>\n }\n </label>\n\n <div class=\"settings-page__welcome-preview eds-card\">\n <div class=\"settings-page__welcome-preview-head\">\n <eds-icon name=\"record_voice_over\" [size]=\"20\" />\n <span class=\"settings-page__field-label\">Live preview</span>\n @if (usingDefaultWelcome()) {\n <eds-badge tone=\"gray\">Default template</eds-badge>\n }\n </div>\n <p class=\"settings-page__welcome-preview-text\">“{{ welcomePreview() }}”</p>\n </div>\n\n @if (!usingDefaultWelcome()) {\n <eds-button variant=\"secondary\" type=\"button\" (click)=\"resetWelcomeMessage()\">\n Reset to default\n </eds-button>\n }\n </section>\n\n @for (field of generalOtherFields(); track field.key) {\n <label\n class=\"settings-page__field\"\n [class.settings-page__field--readonly]=\"isFieldReadOnly('general', field.key)\"\n >\n <span class=\"settings-page__field-label\">\n {{ field.label }}\n @if (isFieldReadOnly('general', field.key)) {\n <span class=\"settings-page__readonly-badge\">Read-only</span>\n }\n </span>\n @if (field.description) {\n <span class=\"settings-page__field-desc\">{{ field.description }}</span>\n }\n @if (field.type === 'select' && field.options?.length) {\n <select\n class=\"settings-page__input settings-page__select\"\n [class.settings-page__input--readonly]=\"isFieldReadOnly('general', field.key)\"\n [disabled]=\"isFieldReadOnly('general', field.key)\"\n [ngModel]=\"fieldValue('general', field.key)\"\n (ngModelChange)=\"updateField('general', field.key, $event)\"\n >\n @for (opt of field.options; track opt.value) {\n <option [ngValue]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n @if (field.key === 'ttsVoiceId') {\n <div class=\"settings-page__voice-preview-row\">\n <eds-button\n variant=\"secondary\"\n type=\"button\"\n [disabled]=\"previewingVoice()\"\n (click)=\"previewSelectedVoice()\"\n >\n {{ previewingVoice() ? 'Generating…' : 'Preview voice' }}\n </eds-button>\n <span class=\"settings-page__field-desc\">\n Plays a short sample in the browser — save to use on phone calls.\n </span>\n </div>\n }\n } @else {\n <input\n type=\"text\"\n class=\"settings-page__input\"\n [class.settings-page__input--readonly]=\"isFieldReadOnly('general', field.key)\"\n [disabled]=\"isFieldReadOnly('general', field.key)\"\n [ngModel]=\"fieldValue('general', field.key)\"\n (ngModelChange)=\"updateField('general', field.key, $event)\"\n />\n }\n </label>\n }\n </div>\n } @else {\n @if (tab() === 'outbound') {\n <a [routerLink]=\"['../settings/outbound-purposes']\" class=\"settings-page__quick-link\">\n <eds-icon name=\"call_made\" [size]=\"22\" />\n <div>\n <span class=\"settings-page__quick-link-title\">Outbound Call Purposes</span>\n <span class=\"settings-page__quick-link-desc\">Templates, required fields, and opening scripts</span>\n </div>\n <eds-icon name=\"chevron_right\" [size]=\"20\" />\n </a>\n }\n\n <div class=\"settings-page__fields\">\n @for (field of fieldsForTab(); track field.key) {\n @if (field.type === 'boolean') {\n <label\n class=\"settings-page__toggle-row\"\n [class.settings-page__toggle-row--readonly]=\"fieldIsReadOnly(tab(), field.key)\"\n >\n <div class=\"settings-page__toggle-copy\">\n <span class=\"settings-page__field-label\">\n {{ field.label }}\n @if (fieldIsReadOnly(tab(), field.key)) {\n <span class=\"settings-page__readonly-badge\">Read-only</span>\n }\n </span>\n @if (field.description) {\n <span class=\"settings-page__field-desc\">{{ field.description }}</span>\n }\n </div>\n <input\n type=\"checkbox\"\n class=\"settings-page__checkbox\"\n [disabled]=\"fieldIsReadOnly(tab(), field.key)\"\n [ngModel]=\"fieldValue(tab(), field.key)\"\n (ngModelChange)=\"updateField(tab(), field.key, $event)\"\n />\n </label>\n } @else {\n <label\n class=\"settings-page__field\"\n [class.settings-page__field--readonly]=\"fieldIsReadOnly(tab(), field.key)\"\n >\n <span class=\"settings-page__field-label\">\n {{ field.label }}\n @if (fieldIsReadOnly(tab(), field.key)) {\n <span class=\"settings-page__readonly-badge\">Read-only</span>\n }\n </span>\n @if (field.description) {\n <span class=\"settings-page__field-desc\">{{ field.description }}</span>\n }\n @if (field.type === 'number') {\n <input\n type=\"number\"\n class=\"settings-page__input\"\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 />\n } @else if (field.type === 'select' && field.options?.length) {\n <select\n class=\"settings-page__input settings-page__select\"\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 >\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\"\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 />\n }\n </label>\n }\n }\n </div>\n }\n }\n </article>\n </div>\n }\n</div>\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"edvak99-voice-receptionist-widget-settings-page.component-B9nv6wtB.mjs","sources":["../../../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":["/** Curated ElevenLabs voices — keep in sync with backend `tts-voice-presets.ts`. */\n\nexport interface TtsVoicePreset {\n id: string;\n label: string;\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 },\n {\n id: 'NUjosfEayZAdRcDmcHM8',\n label: 'Madison – Cool, Calm & Conversational',\n },\n {\n id: 'gE0owC0H9C8SzfDyIUtB',\n label: 'Ivanna – Sassy, Condescending and Clear',\n },\n {\n id: 'Uc7anshoV8mdBhDnEZEX',\n label: 'Cecily – Clear and Warm',\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 SETTINGS_SECTION_META: Record<SettingsSection, SettingsSectionMeta> = {\n general: {\n title: 'General',\n description: 'Practice identity and how the AI introduces itself on calls.',\n },\n phone: {\n title: 'Phone',\n description: 'Inbound routing, after-hours behavior, and ring timing.',\n },\n tasks: {\n title: 'Tasks & follow-ups',\n description: 'When the AI should create staff tasks after a call.',\n },\n scheduling: {\n title: 'Scheduling',\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: 'Escalation',\n description: 'When to offer a human or transfer to reception.',\n },\n outbound: {\n title: 'Outbound calling',\n description: 'Outbound dialer defaults. Purpose templates are managed separately.',\n },\n transcripts: {\n title: 'Transcripts & recording',\n description: 'Retention and PHI handling for call transcripts.',\n },\n advanced: {\n title: 'Advanced',\n description: 'Model and debug options — read-only. Contact Edvak support to change.',\n },\n};\n\n/** Entire sections where every field is read-only (including unknown API fields). */\nexport const READ_ONLY_SECTIONS = new Set<SettingsSection>(['advanced', 'verify']);\n\n/** Settings tabs that stay visible but cannot be selected/edited. */\nexport const DISABLED_SETTINGS_TABS = new Set<SettingsSection>(['verify']);\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: 'practiceName', reason: 'Core practice identity' },\n { section: 'general', key: 'agentName', reason: 'AI agent identity' },\n { section: 'general', key: 'timezone', reason: 'Practice timezone' },\n { section: 'general', key: 'language', reason: 'Default language' },\n { section: 'phone', key: 'mainNumber', reason: 'Inbound phone routing' },\n { section: 'outbound', key: 'callerId', reason: 'Outbound caller ID' },\n { section: 'transcripts', key: 'retainDays', reason: 'Recording retention policy' },\n { section: 'transcripts', key: 'redactPhi', reason: 'PHI redaction policy' },\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: 'practiceName',\n label: 'Practice name',\n description: 'Spoken on greetings and confirmations.',\n type: 'text',\n },\n {\n key: 'agentName',\n label: 'AI agent name',\n description: 'How the assistant introduces itself (e.g. “Ava”).',\n type: 'text',\n },\n {\n key: 'timezone',\n label: 'Timezone',\n description: 'Used for hours, scheduling, and call timestamps.',\n type: 'text',\n },\n {\n key: 'language',\n label: 'Default language',\n description: 'Primary language for the AI receptionist.',\n type: 'text',\n },\n {\n key: 'ttsVoiceId',\n label: 'Voice',\n description: 'Spoken voice used on phone calls for this practice.',\n type: 'select',\n options: TTS_VOICE_PRESETS.map((p) => ({ value: p.id, label: p.label })),\n },\n ],\n phone: [\n {\n key: 'mainNumber',\n label: 'Main phone number',\n description: 'Primary inbound number patients call.',\n type: 'text',\n },\n {\n key: 'afterHours',\n label: 'After-hours mode',\n description: 'Use after-hours greeting and routing outside business hours.',\n type: 'boolean',\n },\n {\n key: 'ringTimeout',\n label: 'Ring timeout (seconds)',\n description: 'How long to ring before the AI answers.',\n type: 'number',\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 transcripts: [\n {\n key: 'retainDays',\n label: 'Retention (days)',\n description: 'How long transcripts and recordings are kept.',\n type: 'number',\n },\n {\n key: 'redactPhi',\n label: 'Redact PHI in transcripts',\n description: 'Mask sensitive identifiers in stored transcripts.',\n type: 'boolean',\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","import { ChangeDetectionStrategy, Component, computed, inject, OnInit, signal } from '@angular/core';\n\nimport { FormsModule } from '@angular/forms';\n\nimport { RouterLink } from '@angular/router';\n\n\n\nimport { AgentSettings } from '../../models/ai-receptionist.types';\n\nimport { AiReceptionistApiService } from '../../services/ai-receptionist-api.service';\n\nimport { EdsBadgeComponent } from '../../ui/eds-badge.component';\n\nimport { EdsButtonComponent } from '../../ui/eds-button.component';\n\nimport { EdsIconComponent } from '../../ui/eds-icon.component';\n\nimport { ToastService } from '../../shared/toast.service';\n\nimport {\n\n buildAutoWelcomeTemplate,\n\n resolveWelcomePreview,\n\n WELCOME_MESSAGE_MAX,\n\n} from '../../utils/welcome-message.util';\n\nimport {\n DISABLED_SETTINGS_TABS,\n isFieldReadOnly,\n READ_ONLY_SECTIONS,\n resolveFieldMeta,\n SETTINGS_FIELDS,\n SETTINGS_SECTION_META,\n SettingsFieldMeta,\n SettingsSection,\n} from './settings-fields.config';\n\n\n\ntype SettingsTab = keyof AgentSettings;\n\n\n\nconst GENERAL_IDENTITY_KEYS = new Set(['practiceName', 'agentName']);\n\nconst GENERAL_OTHER_KEYS = new Set(['timezone', 'language', 'ttsVoiceId']);\n\n\n\n@Component({\n selector: 'eds-settings-page',\n imports: [FormsModule, RouterLink, EdsBadgeComponent, EdsButtonComponent, EdsIconComponent],\n templateUrl: './settings-page.component.html',\n styleUrl: './settings-page.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush\n})\n\nexport class SettingsPageComponent implements OnInit {\n\n private readonly api = inject(AiReceptionistApiService);\n\n private readonly toast = inject(ToastService);\n\n private originalSettings: AgentSettings | null = null;\n\n protected readonly isFieldReadOnly = isFieldReadOnly;\n\n protected readonly readOnlySections = READ_ONLY_SECTIONS;\n\n protected readonly disabledTabs = DISABLED_SETTINGS_TABS;\n\n\n\n protected readonly settings = signal<AgentSettings | null>(null);\n\n protected readonly tab = signal<SettingsTab>('general');\n\n protected readonly loading = signal(true);\n\n protected readonly saving = signal(false);\n\n protected readonly saved = signal(false);\n\n\n\n protected readonly welcomeMax = WELCOME_MESSAGE_MAX;\n\n protected readonly previewingVoice = signal(false);\n\n private voicePreviewAudio: HTMLAudioElement | null = null;\n\n\n\n protected readonly tabs: { id: SettingsTab; label: string; icon: string }[] = [\n\n { id: 'general', label: 'General', icon: 'business' },\n\n { id: 'phone', label: 'Phone', icon: 'call' },\n\n { id: 'tasks', label: 'Tasks', icon: 'task_alt' },\n\n { id: 'scheduling', label: 'Scheduling', icon: 'calendar_month' },\n\n { id: 'refill', label: 'Refills', icon: 'medication' },\n\n { id: 'verify', label: 'Verification', icon: 'verified_user' },\n\n { id: 'escalation', label: 'Escalation', icon: 'warning' },\n\n { id: 'outbound', label: 'Outbound', icon: 'call_made' },\n\n { id: 'transcripts', label: 'Transcripts', icon: 'transcribe' },\n\n { id: 'advanced', label: 'Advanced', icon: 'tune' },\n\n { id: 'safety', label: 'Safety', icon: 'health_and_safety' },\n\n ];\n\n\n\n protected readonly sectionMeta = computed(() => {\n\n const id = this.tab();\n\n if (id === 'safety') {\n\n return { title: 'Safety checklist', description: '' };\n\n }\n\n return SETTINGS_SECTION_META[id as SettingsSection];\n\n });\n\n\n\n protected readonly fieldsForTab = computed((): SettingsFieldMeta[] => {\n\n const s = this.settings();\n\n const id = this.tab();\n\n if (!s || id === 'safety') return [];\n\n\n\n const section = s[id] as Record<string, string | boolean | number>;\n\n const configured = SETTINGS_FIELDS[id as SettingsSection] ?? [];\n\n const configuredKeys = new Set(configured.map((f) => f.key));\n\n\n\n const extras = Object.keys(section)\n\n .filter((key) => key !== 'welcomeMessage' && !configuredKeys.has(key))\n\n .map((key) => resolveFieldMeta(id as SettingsSection, key, section[key]));\n\n\n\n return [...configured, ...extras];\n\n });\n\n\n\n protected readonly generalIdentityFields = computed(() =>\n\n this.fieldsForTab().filter((f) => GENERAL_IDENTITY_KEYS.has(f.key)),\n\n );\n\n\n\n protected readonly generalOtherFields = computed(() =>\n\n this.fieldsForTab().filter((f) => GENERAL_OTHER_KEYS.has(f.key)),\n\n );\n\n\n\n protected readonly welcomeMessage = computed(() =>\n\n String(this.settings()?.general['welcomeMessage'] ?? ''),\n\n );\n\n\n\n protected readonly welcomePlaceholder = computed(() => {\n\n const s = this.settings();\n\n if (!s) return '';\n\n return buildAutoWelcomeTemplate(\n\n String(s.general['practiceName'] ?? ''),\n\n String(s.general['agentName'] ?? ''),\n\n );\n\n });\n\n\n\n protected readonly welcomePreview = computed(() => {\n\n const s = this.settings();\n\n if (!s) return '';\n\n return resolveWelcomePreview(\n\n String(s.general['welcomeMessage'] ?? ''),\n\n String(s.general['practiceName'] ?? ''),\n\n String(s.general['agentName'] ?? ''),\n\n );\n\n });\n\n\n\n protected readonly usingDefaultWelcome = computed(() => !this.welcomeMessage().trim());\n\n\n\n protected readonly showRecordingConsentHint = computed(() => {\n\n const t = this.settings()?.transcripts;\n\n if (!t) return false;\n\n const retain = Number(t['retainDays'] ?? 0);\n\n return retain > 0 || t['redactPhi'] === true;\n\n });\n\n\n\n ngOnInit(): void {\n\n this.api.getSettings().subscribe({\n\n next: ({ data }) => {\n\n this.originalSettings = structuredClone(data);\n\n this.settings.set(structuredClone(data));\n\n this.loading.set(false);\n\n },\n\n error: () => {\n\n this.loading.set(false);\n\n this.toast.show('Failed to load agent settings', 'error');\n\n },\n\n });\n\n }\n\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.tab.set(id);\n }\n\n\n\n protected updateField(section: SettingsTab, key: string, value: string | boolean | number): void {\n\n const current = this.settings();\n\n if (!current || section === 'safety' || isFieldReadOnly(section as SettingsSection, key)) return;\n\n const sectionData = { ...(current[section] as Record<string, string | boolean | number>) };\n\n sectionData[key] = value;\n\n this.settings.set({ ...current, [section]: sectionData });\n\n }\n\n\n\n protected updateWelcomeMessage(value: string): void {\n\n this.updateField('general', 'welcomeMessage', value.slice(0, WELCOME_MESSAGE_MAX));\n\n }\n\n\n\n protected resetWelcomeMessage(): void {\n\n this.updateField('general', 'welcomeMessage', '');\n\n }\n\n protected previewSelectedVoice(): void {\n const voiceId = String(this.fieldValue('general', 'ttsVoiceId') ?? '').trim();\n if (!voiceId || this.previewingVoice()) return;\n\n this.previewingVoice.set(true);\n this.api.previewVoice(voiceId).subscribe({\n next: (blob) => {\n this.previewingVoice.set(false);\n if (this.voicePreviewAudio) {\n this.voicePreviewAudio.pause();\n URL.revokeObjectURL(this.voicePreviewAudio.src);\n this.voicePreviewAudio = null;\n }\n const url = URL.createObjectURL(blob);\n const audio = new Audio(url);\n this.voicePreviewAudio = audio;\n audio.onended = () => {\n URL.revokeObjectURL(url);\n if (this.voicePreviewAudio === audio) this.voicePreviewAudio = null;\n };\n void audio.play().catch(() => {\n this.toast.show('Could not play voice preview in this browser.', 'error');\n URL.revokeObjectURL(url);\n });\n },\n error: () => {\n this.previewingVoice.set(false);\n this.toast.show('Could not generate voice preview. Try again.', 'error');\n },\n });\n }\n\n\n\n protected fieldValue(section: SettingsTab, key: string): string | boolean | number {\n\n const s = this.settings();\n\n if (!s || section === 'safety') return '';\n\n return (s[section] as Record<string, string | boolean | number>)[key];\n\n }\n\n\n\n protected save(): void {\n\n const s = this.settings();\n\n const orig = this.originalSettings;\n\n if (!s || !orig) return;\n\n\n\n const payload = structuredClone(s);\n\n const wm = String(payload.general['welcomeMessage'] ?? '').trim();\n\n payload.general['welcomeMessage'] = wm;\n\n this.restoreReadOnlyFields(payload, orig);\n\n\n\n this.saving.set(true);\n\n this.api.putSettings(payload).subscribe({\n\n next: ({ data }) => {\n\n this.originalSettings = structuredClone(data);\n\n this.settings.set(structuredClone(data));\n\n this.saving.set(false);\n\n this.saved.set(true);\n\n this.toast.show('Agent settings saved', 'success');\n\n setTimeout(() => this.saved.set(false), 2000);\n\n },\n\n error: () => {\n\n this.saving.set(false);\n\n this.toast.show('Failed to save agent settings', 'error');\n\n },\n\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 '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}\n\n\n","<div class=\"eds-page settings-page\">\n <header class=\"settings-page__header\">\n <div>\n <h1 class=\"eds-h1\">Agent settings</h1>\n <p class=\"settings-page__subtitle\">Configure AI receptionist behavior and safety</p>\n </div>\n <div class=\"settings-page__save-row\">\n @if (saved()) {\n <span class=\"settings-page__saved\">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=\"settings-page__loading\">Loading settings…</p>\n } @else if (settings()) {\n <div class=\"settings-page__layout\">\n <nav class=\"eds-card settings-page__sidebar\" aria-label=\"Settings sections\">\n @for (t of tabs; track t.id) {\n <button\n type=\"button\"\n class=\"settings-page__nav-item\"\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 <eds-icon [name]=\"t.icon\" [size]=\"18\" />\n {{ t.label }}\n @if (isTabDisabled(t.id)) {\n <span class=\"settings-page__nav-disabled-badge\">Disabled</span>\n }\n </button>\n }\n </nav>\n\n <article class=\"eds-card settings-page__panel\">\n @if (tab() === 'safety') {\n <header class=\"settings-page__panel-head\">\n <h2 class=\"settings-page__panel-title\">Safety checklist</h2>\n <p class=\"settings-page__panel-desc\">\n Read-only compliance status. Contact Edvak support to change safety configuration.\n </p>\n </header>\n <ul class=\"settings-page__safety\">\n @for (item of settings()!.safety; track item.id) {\n <li>\n <eds-icon\n [name]=\"item.status === 'ok' ? 'check_circle' : 'error'\"\n [size]=\"22\"\n />\n <span class=\"settings-page__safety-label\">{{ item.label }}</span>\n <eds-badge [tone]=\"item.status === 'ok' ? 'pos' : 'notice'\">\n {{ item.status === 'ok' ? 'Pass' : 'Needs attention' }}\n </eds-badge>\n </li>\n }\n </ul>\n } @else {\n <header class=\"settings-page__panel-head\">\n <h2 class=\"settings-page__panel-title\">{{ sectionMeta().title }}</h2>\n <p class=\"settings-page__panel-desc\">{{ sectionMeta().description }}</p>\n </header>\n\n @if (sectionIsReadOnly(tab())) {\n <p class=\"settings-page__readonly-banner\">\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() === 'general') {\n <a routerLink=\"../knowledge\" class=\"settings-page__quick-link\">\n <eds-icon name=\"menu_book\" [size]=\"22\" />\n <div>\n <span class=\"settings-page__quick-link-title\">Practice Knowledge Base</span>\n <span class=\"settings-page__quick-link-desc\">FAQ answers your AI uses on phone calls</span>\n </div>\n <eds-icon name=\"chevron_right\" [size]=\"20\" />\n </a>\n\n <div class=\"settings-page__fields settings-page__fields--general\">\n @for (field of generalIdentityFields(); track field.key) {\n <label\n class=\"settings-page__field\"\n [class.settings-page__field--readonly]=\"isFieldReadOnly('general', field.key)\"\n >\n <span class=\"settings-page__field-label\">\n {{ field.label }}\n @if (isFieldReadOnly('general', field.key)) {\n <span class=\"settings-page__readonly-badge\">Read-only</span>\n }\n </span>\n @if (field.description) {\n <span class=\"settings-page__field-desc\">{{ field.description }}</span>\n }\n <input\n type=\"text\"\n class=\"settings-page__input\"\n [class.settings-page__input--readonly]=\"isFieldReadOnly('general', field.key)\"\n [disabled]=\"isFieldReadOnly('general', field.key)\"\n [ngModel]=\"fieldValue('general', field.key)\"\n (ngModelChange)=\"updateField('general', field.key, $event)\"\n />\n </label>\n }\n\n <section class=\"settings-page__welcome\">\n <label class=\"settings-page__field settings-page__field--full\">\n <span class=\"settings-page__field-label\">Welcome message</span>\n <span class=\"settings-page__field-desc\">\n Spoken automatically when a caller connects. Leave blank to use the default template.\n </span>\n <textarea\n class=\"settings-page__textarea\"\n rows=\"4\"\n [maxlength]=\"welcomeMax\"\n [placeholder]=\"welcomePlaceholder()\"\n [ngModel]=\"welcomeMessage()\"\n (ngModelChange)=\"updateWelcomeMessage($event)\"\n ></textarea>\n <span class=\"settings-page__char-count\">\n {{ welcomeMessage().length }}/{{ welcomeMax }}\n </span>\n @if (showRecordingConsentHint()) {\n <p class=\"settings-page__recording-hint\">\n Call recording is enabled — consider mentioning that the call may be recorded or monitored.\n </p>\n }\n </label>\n\n <div class=\"settings-page__welcome-preview eds-card\">\n <div class=\"settings-page__welcome-preview-head\">\n <eds-icon name=\"record_voice_over\" [size]=\"20\" />\n <span class=\"settings-page__field-label\">Live preview</span>\n @if (usingDefaultWelcome()) {\n <eds-badge tone=\"gray\">Default template</eds-badge>\n }\n </div>\n <p class=\"settings-page__welcome-preview-text\">“{{ welcomePreview() }}”</p>\n </div>\n\n @if (!usingDefaultWelcome()) {\n <eds-button variant=\"secondary\" type=\"button\" (click)=\"resetWelcomeMessage()\">\n Reset to default\n </eds-button>\n }\n </section>\n\n @for (field of generalOtherFields(); track field.key) {\n <label\n class=\"settings-page__field\"\n [class.settings-page__field--readonly]=\"isFieldReadOnly('general', field.key)\"\n >\n <span class=\"settings-page__field-label\">\n {{ field.label }}\n @if (isFieldReadOnly('general', field.key)) {\n <span class=\"settings-page__readonly-badge\">Read-only</span>\n }\n </span>\n @if (field.description) {\n <span class=\"settings-page__field-desc\">{{ field.description }}</span>\n }\n @if (field.type === 'select' && field.options?.length) {\n <select\n class=\"settings-page__input settings-page__select\"\n [class.settings-page__input--readonly]=\"isFieldReadOnly('general', field.key)\"\n [disabled]=\"isFieldReadOnly('general', field.key)\"\n [ngModel]=\"fieldValue('general', field.key)\"\n (ngModelChange)=\"updateField('general', field.key, $event)\"\n >\n @for (opt of field.options; track opt.value) {\n <option [ngValue]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n @if (field.key === 'ttsVoiceId') {\n <div class=\"settings-page__voice-preview-row\">\n <eds-button\n variant=\"secondary\"\n type=\"button\"\n [disabled]=\"previewingVoice()\"\n (click)=\"previewSelectedVoice()\"\n >\n {{ previewingVoice() ? 'Generating…' : 'Preview voice' }}\n </eds-button>\n <span class=\"settings-page__field-desc\">\n Plays a short sample in the browser — save to use on phone calls.\n </span>\n </div>\n }\n } @else {\n <input\n type=\"text\"\n class=\"settings-page__input\"\n [class.settings-page__input--readonly]=\"isFieldReadOnly('general', field.key)\"\n [disabled]=\"isFieldReadOnly('general', field.key)\"\n [ngModel]=\"fieldValue('general', field.key)\"\n (ngModelChange)=\"updateField('general', field.key, $event)\"\n />\n }\n </label>\n }\n </div>\n } @else {\n @if (tab() === 'outbound') {\n <a [routerLink]=\"['../settings/outbound-purposes']\" class=\"settings-page__quick-link\">\n <eds-icon name=\"call_made\" [size]=\"22\" />\n <div>\n <span class=\"settings-page__quick-link-title\">Outbound Call Purposes</span>\n <span class=\"settings-page__quick-link-desc\">Templates, required fields, and opening scripts</span>\n </div>\n <eds-icon name=\"chevron_right\" [size]=\"20\" />\n </a>\n }\n\n <div class=\"settings-page__fields\">\n @for (field of fieldsForTab(); track field.key) {\n @if (field.type === 'boolean') {\n <label\n class=\"settings-page__toggle-row\"\n [class.settings-page__toggle-row--readonly]=\"fieldIsReadOnly(tab(), field.key)\"\n >\n <div class=\"settings-page__toggle-copy\">\n <span class=\"settings-page__field-label\">\n {{ field.label }}\n @if (fieldIsReadOnly(tab(), field.key)) {\n <span class=\"settings-page__readonly-badge\">Read-only</span>\n }\n </span>\n @if (field.description) {\n <span class=\"settings-page__field-desc\">{{ field.description }}</span>\n }\n </div>\n <input\n type=\"checkbox\"\n class=\"settings-page__checkbox\"\n [disabled]=\"fieldIsReadOnly(tab(), field.key)\"\n [ngModel]=\"fieldValue(tab(), field.key)\"\n (ngModelChange)=\"updateField(tab(), field.key, $event)\"\n />\n </label>\n } @else {\n <label\n class=\"settings-page__field\"\n [class.settings-page__field--readonly]=\"fieldIsReadOnly(tab(), field.key)\"\n >\n <span class=\"settings-page__field-label\">\n {{ field.label }}\n @if (fieldIsReadOnly(tab(), field.key)) {\n <span class=\"settings-page__readonly-badge\">Read-only</span>\n }\n </span>\n @if (field.description) {\n <span class=\"settings-page__field-desc\">{{ field.description }}</span>\n }\n @if (field.type === 'number') {\n <input\n type=\"number\"\n class=\"settings-page__input\"\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 />\n } @else if (field.type === 'select' && field.options?.length) {\n <select\n class=\"settings-page__input settings-page__select\"\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 >\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\"\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 />\n }\n </label>\n }\n }\n </div>\n }\n }\n </article>\n </div>\n }\n</div>\n"],"names":[],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import { DatePipe } from '@angular/common';
|
|
|
2
2
|
import * as i0 from '@angular/core';
|
|
3
3
|
import { inject, signal, Input, ChangeDetectionStrategy, Component, input, output, computed } from '@angular/core';
|
|
4
4
|
import { RouterLink, ActivatedRoute } from '@angular/router';
|
|
5
|
-
import { T as ToastService, a as EdsBadgeComponent, E as EdsButtonComponent, b as EdsIconComponent, A as AiReceptionistApiService } from './edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-
|
|
5
|
+
import { T as ToastService, a as EdsBadgeComponent, E as EdsButtonComponent, b as EdsIconComponent, A as AiReceptionistApiService, D as DEFAULT_PAGE_SIZE, f as totalPages } from './edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-Dn0GrZ6_.mjs';
|
|
6
6
|
import { t as taskStatusLabel, a as taskStatusTone, c as taskPriorityLabel, d as taskPriorityTone, e as taskSourceLabel, b as taskTypeTone, f as taskCallRoute, T as TASK_TYPE_OPTIONS } from './edvak99-voice-receptionist-widget-task.util-DdtI0CR3.mjs';
|
|
7
7
|
|
|
8
8
|
class CopyButtonComponent {
|
|
@@ -59,7 +59,7 @@ class CopyButtonComponent {
|
|
|
59
59
|
}
|
|
60
60
|
</button>
|
|
61
61
|
}
|
|
62
|
-
`, isInline: true, styles: [".copy-btn{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:22px;height:22px;padding:0;border:1px solid var(--color-border);border-radius:4px;background:var(--color-surface);color:var(--color-text-muted);cursor:pointer;transition:background .1s ease,color .1s ease,border-color .1s ease}.copy-btn:hover{background:var(--color-surface-alt);color:var(--color-primary);border-color:var(--color-border-strong)}.copy-btn:focus-visible{outline:2px solid var(--color-primary);outline-offset:1px}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
62
|
+
`, isInline: true, styles: [".copy-btn{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:22px;height:22px;padding:0;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 }); }
|
|
63
63
|
}
|
|
64
64
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: CopyButtonComponent, decorators: [{
|
|
65
65
|
type: Component,
|
|
@@ -86,7 +86,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
86
86
|
}
|
|
87
87
|
</button>
|
|
88
88
|
}
|
|
89
|
-
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".copy-btn{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:22px;height:22px;padding:0;border:1px solid var(--color-border);border-radius:4px;background:var(--color-surface);color:var(--color-text-muted);cursor:pointer;transition:background .1s ease,color .1s ease,border-color .1s ease}.copy-btn:hover{background:var(--color-surface-alt);color:var(--color-primary);border-color:var(--color-border-strong)}.copy-btn:focus-visible{outline:2px solid var(--color-primary);outline-offset:1px}\n"] }]
|
|
89
|
+
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".copy-btn{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:22px;height:22px;padding:0;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"] }]
|
|
90
90
|
}], propDecorators: { value: [{
|
|
91
91
|
type: Input
|
|
92
92
|
}], label: [{
|
|
@@ -118,7 +118,7 @@ class TaskDetailDrawerComponent {
|
|
|
118
118
|
this.close();
|
|
119
119
|
}
|
|
120
120
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: TaskDetailDrawerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
121
|
-
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=\"task-drawer__backdrop\" (click)=\"onBackdropClick($event)\">\n <aside class=\"task-drawer\" role=\"dialog\" aria-modal=\"true\" [attr.aria-label]=\"task().title\">\n <header class=\"task-drawer__head\">\n <div>\n <eds-badge [tone]=\"taskTypeTone(task().type)\">{{ task().type }}</eds-badge>\n <h2 class=\"task-drawer__title\">{{ task().title }}</h2>\n </div>\n <button type=\"button\" class=\"task-drawer__close\" (click)=\"close()\" aria-label=\"Close\">\n <eds-icon name=\"close\" [size]=\"22\" />\n </button>\n </header>\n\n <div class=\"task-drawer__body\">\n <section class=\"task-drawer__section\">\n <h3 class=\"eds-label\">Description</h3>\n <p class=\"task-drawer__description\">{{ task().description || '\u2014' }}</p>\n </section>\n\n <dl class=\"task-drawer__meta\">\n <div>\n <dt class=\"eds-label\">Patient</dt>\n <dd>{{ task().patient }}</dd>\n </div>\n <div>\n <dt class=\"eds-label\">Assignee</dt>\n <dd>{{ task().assignee }}</dd>\n </div>\n <div>\n <dt class=\"eds-label\">Status</dt>\n <dd><eds-badge [tone]=\"taskStatusTone(task().status)\">{{ taskStatusLabel(task().status) }}</eds-badge></dd>\n </div>\n <div>\n <dt class=\"eds-label\">Priority</dt>\n <dd><eds-badge [tone]=\"taskPriorityTone(task().priority)\">{{ taskPriorityLabel(task().priority) }}</eds-badge></dd>\n </div>\n <div>\n <dt class=\"eds-label\">Source</dt>\n <dd>{{ taskSourceLabel(task().source) }}</dd>\n </div>\n <div>\n <dt class=\"eds-label\">Created</dt>\n <dd>{{ task().created | date: 'medium' }}</dd>\n </div>\n <div>\n <dt class=\"eds-label\">Call</dt>\n <dd>\n @if (task().callId) {\n <a [routerLink]=\"taskCallRoute(task().callId!)\" class=\"task-drawer__link\">{{ task().callId }}</a>\n } @else {\n \u2014\n }\n </dd>\n </div>\n </dl>\n\n @if (task().edvakTaskId || task().edvakStatus || task().medicationName || task().medicationId) {\n <section class=\"task-drawer__section task-drawer__section--edvak\">\n <h3 class=\"eds-label\">Edvak / refill details</h3>\n <dl class=\"task-drawer__meta\">\n @if (task().edvakTaskId) {\n <div>\n <dt class=\"eds-label\">Edvak task ID</dt>\n <dd class=\"task-drawer__copy-row\">\n <code>{{ 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\">Edvak status</dt>\n <dd><eds-badge tone=\"brand\">{{ task().edvakStatus }}</eds-badge></dd>\n </div>\n }\n @if (task().medicationName) {\n <div>\n <dt class=\"eds-label\">Medication</dt>\n <dd>{{ task().medicationName }}</dd>\n </div>\n }\n @if (task().medicationId) {\n <div>\n <dt class=\"eds-label\">Medication ID</dt>\n <dd class=\"task-drawer__copy-row\">\n <code>{{ 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\n <footer class=\"task-drawer__foot\">\n <eds-button variant=\"secondary\" type=\"button\" (click)=\"markDone()\">\n {{ task().status === 'done' ? 'Reopen task' : 'Mark done' }}\n </eds-button>\n </footer>\n </aside>\n</div>\n", styles: [".task-drawer__backdrop{position:fixed;inset:0;z-index:200;background:#0f172a66;display:flex;justify-content:flex-end}.task-drawer{width:min(440px,100%);height:100%;background:#fff;box-shadow:-8px 0 32px #0f172a1f;display:flex;flex-direction:column;animation:task-drawer-in .2s ease}.task-drawer__head{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;padding:20px 24px;border-bottom:1px solid var(--color-border, #e2e8f0)}.task-drawer__title{margin:8px 0 0;font-size:20px;font-weight:600;line-height:1.3;color:var(--color-text, #0f172a)}.task-drawer__close{border:none;background:none;padding:4px;cursor:pointer;color:var(--color-text-muted, #64748b);border-radius:6px}.task-drawer__close:hover{background:var(--color-surface-alt, #f1f5f9)}.task-drawer__body{flex:1;overflow-y:auto;padding:20px 24px;display:flex;flex-direction:column;gap:24px}.task-drawer__section--edvak{padding:14px;border-radius:8px;background:var(--color-surface-alt, #f8fafc);border:1px solid var(--color-border, #e2e8f0)}.task-drawer__description{margin:8px 0 0;font-size:15px;line-height:1.55;color:var(--color-text, #0f172a);white-space:pre-wrap}.task-drawer__meta{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin:0}.task-drawer__meta dt{margin:0 0 4px}.task-drawer__meta dd{margin:0;font-size:14px;color:var(--color-text, #0f172a)}.task-drawer__copy-row{display:inline-flex;align-items:center;gap:6px}.task-drawer__copy-row code{font-family:ui-monospace,monospace;font-size:12px;background:var(--color-surface-alt, #f1f5f9);padding:2px 6px;border-radius:4px}.task-drawer__link{color:var(--color-primary, #3681f4);text-decoration:none;font-weight:500}.task-drawer__link:hover{text-decoration:underline}.task-drawer__foot{padding:16px 24px;border-top:1px solid var(--color-border, #e2e8f0)}@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 }); }
|
|
121
|
+
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=\"task-drawer__backdrop\" (click)=\"onBackdropClick($event)\">\n <aside class=\"task-drawer\" role=\"dialog\" aria-modal=\"true\" [attr.aria-label]=\"task().title\">\n <header class=\"task-drawer__head\">\n <div>\n <eds-badge [tone]=\"taskTypeTone(task().type)\">{{ task().type }}</eds-badge>\n <h2 class=\"task-drawer__title\">{{ task().title }}</h2>\n </div>\n <button type=\"button\" class=\"task-drawer__close\" (click)=\"close()\" aria-label=\"Close\">\n <eds-icon name=\"close\" [size]=\"22\" />\n </button>\n </header>\n\n <div class=\"task-drawer__body\">\n <section class=\"task-drawer__section\">\n <h3 class=\"eds-label\">Description</h3>\n <p class=\"task-drawer__description\">{{ task().description || '\u2014' }}</p>\n </section>\n\n <dl class=\"task-drawer__meta\">\n <div>\n <dt class=\"eds-label\">Patient</dt>\n <dd>{{ task().patient }}</dd>\n </div>\n <div>\n <dt class=\"eds-label\">Assignee</dt>\n <dd>{{ task().assignee }}</dd>\n </div>\n <div>\n <dt class=\"eds-label\">Status</dt>\n <dd><eds-badge [tone]=\"taskStatusTone(task().status)\">{{ taskStatusLabel(task().status) }}</eds-badge></dd>\n </div>\n <div>\n <dt class=\"eds-label\">Priority</dt>\n <dd><eds-badge [tone]=\"taskPriorityTone(task().priority)\">{{ taskPriorityLabel(task().priority) }}</eds-badge></dd>\n </div>\n <div>\n <dt class=\"eds-label\">Source</dt>\n <dd>{{ taskSourceLabel(task().source) }}</dd>\n </div>\n <div>\n <dt class=\"eds-label\">Created</dt>\n <dd>{{ task().created | date: 'medium' }}</dd>\n </div>\n <div>\n <dt class=\"eds-label\">Call</dt>\n <dd>\n @if (task().callId) {\n <a [routerLink]=\"taskCallRoute(task().callId!)\" class=\"task-drawer__link\">{{ task().callId }}</a>\n } @else {\n \u2014\n }\n </dd>\n </div>\n </dl>\n\n @if (task().edvakTaskId || task().edvakStatus || task().medicationName || task().medicationId) {\n <section class=\"task-drawer__section task-drawer__section--edvak\">\n <h3 class=\"eds-label\">Edvak / refill details</h3>\n <dl class=\"task-drawer__meta\">\n @if (task().edvakTaskId) {\n <div>\n <dt class=\"eds-label\">Edvak task ID</dt>\n <dd class=\"task-drawer__copy-row\">\n <code>{{ 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\">Edvak status</dt>\n <dd><eds-badge tone=\"brand\">{{ task().edvakStatus }}</eds-badge></dd>\n </div>\n }\n @if (task().medicationName) {\n <div>\n <dt class=\"eds-label\">Medication</dt>\n <dd>{{ task().medicationName }}</dd>\n </div>\n }\n @if (task().medicationId) {\n <div>\n <dt class=\"eds-label\">Medication ID</dt>\n <dd class=\"task-drawer__copy-row\">\n <code>{{ 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\n <footer class=\"task-drawer__foot\">\n <eds-button variant=\"secondary\" type=\"button\" (click)=\"markDone()\">\n {{ task().status === 'done' ? 'Reopen task' : 'Mark done' }}\n </eds-button>\n </footer>\n </aside>\n</div>\n", styles: [".task-drawer__backdrop{position:fixed;inset:0;z-index:200;background:#0f172a66;display:flex;justify-content:flex-end}.task-drawer{width:min(440px,100%);height:100%;background:#fff;box-shadow:-8px 0 32px #0f172a1f;display:flex;flex-direction:column;animation:task-drawer-in .2s ease}.task-drawer__head{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;padding:20px 24px;border-bottom:1px solid var(--eds-color-border, #e2e8f0)}.task-drawer__title{margin:8px 0 0;font-size:20px;font-weight:600;line-height:1.3;color:var(--eds-color-text, #0f172a)}.task-drawer__close{border:none;background:none;padding:4px;cursor:pointer;color:var(--eds-color-text-muted, #64748b);border-radius:6px}.task-drawer__close:hover{background:var(--eds-color-surface-alt, #f1f5f9)}.task-drawer__body{flex:1;overflow-y:auto;padding:20px 24px;display:flex;flex-direction:column;gap:24px}.task-drawer__section--edvak{padding:14px;border-radius:8px;background:var(--eds-color-surface-alt, #f8fafc);border:1px solid var(--eds-color-border, #e2e8f0)}.task-drawer__description{margin:8px 0 0;font-size:15px;line-height:1.55;color:var(--eds-color-text, #0f172a);white-space:pre-wrap}.task-drawer__meta{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin:0}.task-drawer__meta dt{margin:0 0 4px}.task-drawer__meta dd{margin:0;font-size:14px;color:var(--eds-color-text, #0f172a)}.task-drawer__copy-row{display:inline-flex;align-items:center;gap:6px}.task-drawer__copy-row code{font-family:ui-monospace,monospace;font-size:12px;background:var(--eds-color-surface-alt, #f1f5f9);padding:2px 6px;border-radius:4px}.task-drawer__link{color:var(--eds-color-primary, #3681f4);text-decoration:none;font-weight:500}.task-drawer__link:hover{text-decoration:underline}.task-drawer__foot{padding:16px 24px;border-top:1px solid var(--eds-color-border, #e2e8f0)}@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 }); }
|
|
122
122
|
}
|
|
123
123
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: TaskDetailDrawerComponent, decorators: [{
|
|
124
124
|
type: Component,
|
|
@@ -129,14 +129,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
129
129
|
EdsBadgeComponent,
|
|
130
130
|
EdsButtonComponent,
|
|
131
131
|
EdsIconComponent,
|
|
132
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"task-drawer__backdrop\" (click)=\"onBackdropClick($event)\">\n <aside class=\"task-drawer\" role=\"dialog\" aria-modal=\"true\" [attr.aria-label]=\"task().title\">\n <header class=\"task-drawer__head\">\n <div>\n <eds-badge [tone]=\"taskTypeTone(task().type)\">{{ task().type }}</eds-badge>\n <h2 class=\"task-drawer__title\">{{ task().title }}</h2>\n </div>\n <button type=\"button\" class=\"task-drawer__close\" (click)=\"close()\" aria-label=\"Close\">\n <eds-icon name=\"close\" [size]=\"22\" />\n </button>\n </header>\n\n <div class=\"task-drawer__body\">\n <section class=\"task-drawer__section\">\n <h3 class=\"eds-label\">Description</h3>\n <p class=\"task-drawer__description\">{{ task().description || '\u2014' }}</p>\n </section>\n\n <dl class=\"task-drawer__meta\">\n <div>\n <dt class=\"eds-label\">Patient</dt>\n <dd>{{ task().patient }}</dd>\n </div>\n <div>\n <dt class=\"eds-label\">Assignee</dt>\n <dd>{{ task().assignee }}</dd>\n </div>\n <div>\n <dt class=\"eds-label\">Status</dt>\n <dd><eds-badge [tone]=\"taskStatusTone(task().status)\">{{ taskStatusLabel(task().status) }}</eds-badge></dd>\n </div>\n <div>\n <dt class=\"eds-label\">Priority</dt>\n <dd><eds-badge [tone]=\"taskPriorityTone(task().priority)\">{{ taskPriorityLabel(task().priority) }}</eds-badge></dd>\n </div>\n <div>\n <dt class=\"eds-label\">Source</dt>\n <dd>{{ taskSourceLabel(task().source) }}</dd>\n </div>\n <div>\n <dt class=\"eds-label\">Created</dt>\n <dd>{{ task().created | date: 'medium' }}</dd>\n </div>\n <div>\n <dt class=\"eds-label\">Call</dt>\n <dd>\n @if (task().callId) {\n <a [routerLink]=\"taskCallRoute(task().callId!)\" class=\"task-drawer__link\">{{ task().callId }}</a>\n } @else {\n \u2014\n }\n </dd>\n </div>\n </dl>\n\n @if (task().edvakTaskId || task().edvakStatus || task().medicationName || task().medicationId) {\n <section class=\"task-drawer__section task-drawer__section--edvak\">\n <h3 class=\"eds-label\">Edvak / refill details</h3>\n <dl class=\"task-drawer__meta\">\n @if (task().edvakTaskId) {\n <div>\n <dt class=\"eds-label\">Edvak task ID</dt>\n <dd class=\"task-drawer__copy-row\">\n <code>{{ 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\">Edvak status</dt>\n <dd><eds-badge tone=\"brand\">{{ task().edvakStatus }}</eds-badge></dd>\n </div>\n }\n @if (task().medicationName) {\n <div>\n <dt class=\"eds-label\">Medication</dt>\n <dd>{{ task().medicationName }}</dd>\n </div>\n }\n @if (task().medicationId) {\n <div>\n <dt class=\"eds-label\">Medication ID</dt>\n <dd class=\"task-drawer__copy-row\">\n <code>{{ 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\n <footer class=\"task-drawer__foot\">\n <eds-button variant=\"secondary\" type=\"button\" (click)=\"markDone()\">\n {{ task().status === 'done' ? 'Reopen task' : 'Mark done' }}\n </eds-button>\n </footer>\n </aside>\n</div>\n", styles: [".task-drawer__backdrop{position:fixed;inset:0;z-index:200;background:#0f172a66;display:flex;justify-content:flex-end}.task-drawer{width:min(440px,100%);height:100%;background:#fff;box-shadow:-8px 0 32px #0f172a1f;display:flex;flex-direction:column;animation:task-drawer-in .2s ease}.task-drawer__head{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;padding:20px 24px;border-bottom:1px solid var(--color-border, #e2e8f0)}.task-drawer__title{margin:8px 0 0;font-size:20px;font-weight:600;line-height:1.3;color:var(--color-text, #0f172a)}.task-drawer__close{border:none;background:none;padding:4px;cursor:pointer;color:var(--color-text-muted, #64748b);border-radius:6px}.task-drawer__close:hover{background:var(--color-surface-alt, #f1f5f9)}.task-drawer__body{flex:1;overflow-y:auto;padding:20px 24px;display:flex;flex-direction:column;gap:24px}.task-drawer__section--edvak{padding:14px;border-radius:8px;background:var(--color-surface-alt, #f8fafc);border:1px solid var(--color-border, #e2e8f0)}.task-drawer__description{margin:8px 0 0;font-size:15px;line-height:1.55;color:var(--color-text, #0f172a);white-space:pre-wrap}.task-drawer__meta{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin:0}.task-drawer__meta dt{margin:0 0 4px}.task-drawer__meta dd{margin:0;font-size:14px;color:var(--color-text, #0f172a)}.task-drawer__copy-row{display:inline-flex;align-items:center;gap:6px}.task-drawer__copy-row code{font-family:ui-monospace,monospace;font-size:12px;background:var(--color-surface-alt, #f1f5f9);padding:2px 6px;border-radius:4px}.task-drawer__link{color:var(--color-primary, #3681f4);text-decoration:none;font-weight:500}.task-drawer__link:hover{text-decoration:underline}.task-drawer__foot{padding:16px 24px;border-top:1px solid var(--color-border, #e2e8f0)}@keyframes task-drawer-in{0%{transform:translate(100%)}to{transform:translate(0)}}\n"] }]
|
|
132
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"task-drawer__backdrop\" (click)=\"onBackdropClick($event)\">\n <aside class=\"task-drawer\" role=\"dialog\" aria-modal=\"true\" [attr.aria-label]=\"task().title\">\n <header class=\"task-drawer__head\">\n <div>\n <eds-badge [tone]=\"taskTypeTone(task().type)\">{{ task().type }}</eds-badge>\n <h2 class=\"task-drawer__title\">{{ task().title }}</h2>\n </div>\n <button type=\"button\" class=\"task-drawer__close\" (click)=\"close()\" aria-label=\"Close\">\n <eds-icon name=\"close\" [size]=\"22\" />\n </button>\n </header>\n\n <div class=\"task-drawer__body\">\n <section class=\"task-drawer__section\">\n <h3 class=\"eds-label\">Description</h3>\n <p class=\"task-drawer__description\">{{ task().description || '\u2014' }}</p>\n </section>\n\n <dl class=\"task-drawer__meta\">\n <div>\n <dt class=\"eds-label\">Patient</dt>\n <dd>{{ task().patient }}</dd>\n </div>\n <div>\n <dt class=\"eds-label\">Assignee</dt>\n <dd>{{ task().assignee }}</dd>\n </div>\n <div>\n <dt class=\"eds-label\">Status</dt>\n <dd><eds-badge [tone]=\"taskStatusTone(task().status)\">{{ taskStatusLabel(task().status) }}</eds-badge></dd>\n </div>\n <div>\n <dt class=\"eds-label\">Priority</dt>\n <dd><eds-badge [tone]=\"taskPriorityTone(task().priority)\">{{ taskPriorityLabel(task().priority) }}</eds-badge></dd>\n </div>\n <div>\n <dt class=\"eds-label\">Source</dt>\n <dd>{{ taskSourceLabel(task().source) }}</dd>\n </div>\n <div>\n <dt class=\"eds-label\">Created</dt>\n <dd>{{ task().created | date: 'medium' }}</dd>\n </div>\n <div>\n <dt class=\"eds-label\">Call</dt>\n <dd>\n @if (task().callId) {\n <a [routerLink]=\"taskCallRoute(task().callId!)\" class=\"task-drawer__link\">{{ task().callId }}</a>\n } @else {\n \u2014\n }\n </dd>\n </div>\n </dl>\n\n @if (task().edvakTaskId || task().edvakStatus || task().medicationName || task().medicationId) {\n <section class=\"task-drawer__section task-drawer__section--edvak\">\n <h3 class=\"eds-label\">Edvak / refill details</h3>\n <dl class=\"task-drawer__meta\">\n @if (task().edvakTaskId) {\n <div>\n <dt class=\"eds-label\">Edvak task ID</dt>\n <dd class=\"task-drawer__copy-row\">\n <code>{{ 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\">Edvak status</dt>\n <dd><eds-badge tone=\"brand\">{{ task().edvakStatus }}</eds-badge></dd>\n </div>\n }\n @if (task().medicationName) {\n <div>\n <dt class=\"eds-label\">Medication</dt>\n <dd>{{ task().medicationName }}</dd>\n </div>\n }\n @if (task().medicationId) {\n <div>\n <dt class=\"eds-label\">Medication ID</dt>\n <dd class=\"task-drawer__copy-row\">\n <code>{{ 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\n <footer class=\"task-drawer__foot\">\n <eds-button variant=\"secondary\" type=\"button\" (click)=\"markDone()\">\n {{ task().status === 'done' ? 'Reopen task' : 'Mark done' }}\n </eds-button>\n </footer>\n </aside>\n</div>\n", styles: [".task-drawer__backdrop{position:fixed;inset:0;z-index:200;background:#0f172a66;display:flex;justify-content:flex-end}.task-drawer{width:min(440px,100%);height:100%;background:#fff;box-shadow:-8px 0 32px #0f172a1f;display:flex;flex-direction:column;animation:task-drawer-in .2s ease}.task-drawer__head{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;padding:20px 24px;border-bottom:1px solid var(--eds-color-border, #e2e8f0)}.task-drawer__title{margin:8px 0 0;font-size:20px;font-weight:600;line-height:1.3;color:var(--eds-color-text, #0f172a)}.task-drawer__close{border:none;background:none;padding:4px;cursor:pointer;color:var(--eds-color-text-muted, #64748b);border-radius:6px}.task-drawer__close:hover{background:var(--eds-color-surface-alt, #f1f5f9)}.task-drawer__body{flex:1;overflow-y:auto;padding:20px 24px;display:flex;flex-direction:column;gap:24px}.task-drawer__section--edvak{padding:14px;border-radius:8px;background:var(--eds-color-surface-alt, #f8fafc);border:1px solid var(--eds-color-border, #e2e8f0)}.task-drawer__description{margin:8px 0 0;font-size:15px;line-height:1.55;color:var(--eds-color-text, #0f172a);white-space:pre-wrap}.task-drawer__meta{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin:0}.task-drawer__meta dt{margin:0 0 4px}.task-drawer__meta dd{margin:0;font-size:14px;color:var(--eds-color-text, #0f172a)}.task-drawer__copy-row{display:inline-flex;align-items:center;gap:6px}.task-drawer__copy-row code{font-family:ui-monospace,monospace;font-size:12px;background:var(--eds-color-surface-alt, #f1f5f9);padding:2px 6px;border-radius:4px}.task-drawer__link{color:var(--eds-color-primary, #3681f4);text-decoration:none;font-weight:500}.task-drawer__link:hover{text-decoration:underline}.task-drawer__foot{padding:16px 24px;border-top:1px solid var(--eds-color-border, #e2e8f0)}@keyframes task-drawer-in{0%{transform:translate(100%)}to{transform:translate(0)}}\n"] }]
|
|
133
133
|
}] });
|
|
134
134
|
|
|
135
135
|
class TasksPageComponent {
|
|
136
136
|
constructor() {
|
|
137
137
|
this.api = inject(AiReceptionistApiService);
|
|
138
138
|
this.route = inject(ActivatedRoute);
|
|
139
|
+
this.pageSize = DEFAULT_PAGE_SIZE;
|
|
139
140
|
this.tasks = signal([]);
|
|
141
|
+
this.total = signal(0);
|
|
142
|
+
this.page = signal(1);
|
|
140
143
|
this.loading = signal(true);
|
|
141
144
|
this.selectedTask = signal(null);
|
|
142
145
|
this.statusFilter = signal('');
|
|
@@ -163,18 +166,22 @@ class TasksPageComponent {
|
|
|
163
166
|
}
|
|
164
167
|
setStatusFilter(value) {
|
|
165
168
|
this.statusFilter.set(value);
|
|
169
|
+
this.page.set(1);
|
|
166
170
|
this.load();
|
|
167
171
|
}
|
|
168
172
|
setTypeFilter(value) {
|
|
169
173
|
this.typeFilter.set(value);
|
|
174
|
+
this.page.set(1);
|
|
170
175
|
this.load();
|
|
171
176
|
}
|
|
172
177
|
setSourceFilter(value) {
|
|
173
178
|
this.sourceFilter.set(value);
|
|
179
|
+
this.page.set(1);
|
|
174
180
|
this.load();
|
|
175
181
|
}
|
|
176
182
|
setCallIdFilter(value) {
|
|
177
183
|
this.callIdFilter.set(value);
|
|
184
|
+
this.page.set(1);
|
|
178
185
|
this.load();
|
|
179
186
|
}
|
|
180
187
|
clearFilters() {
|
|
@@ -182,6 +189,7 @@ class TasksPageComponent {
|
|
|
182
189
|
this.typeFilter.set('');
|
|
183
190
|
this.sourceFilter.set('');
|
|
184
191
|
this.callIdFilter.set('');
|
|
192
|
+
this.page.set(1);
|
|
185
193
|
this.load();
|
|
186
194
|
}
|
|
187
195
|
openTask(task) {
|
|
@@ -201,9 +209,27 @@ class TasksPageComponent {
|
|
|
201
209
|
}
|
|
202
210
|
});
|
|
203
211
|
}
|
|
212
|
+
totalPages() {
|
|
213
|
+
return totalPages(this.total(), DEFAULT_PAGE_SIZE);
|
|
214
|
+
}
|
|
215
|
+
prevPage() {
|
|
216
|
+
if (this.page() <= 1)
|
|
217
|
+
return;
|
|
218
|
+
this.page.update((p) => p - 1);
|
|
219
|
+
this.load();
|
|
220
|
+
}
|
|
221
|
+
nextPage() {
|
|
222
|
+
if (this.page() >= this.totalPages())
|
|
223
|
+
return;
|
|
224
|
+
this.page.update((p) => p + 1);
|
|
225
|
+
this.load();
|
|
226
|
+
}
|
|
204
227
|
load() {
|
|
205
228
|
this.loading.set(true);
|
|
206
|
-
const filters = {
|
|
229
|
+
const filters = {
|
|
230
|
+
page: this.page(),
|
|
231
|
+
limit: DEFAULT_PAGE_SIZE,
|
|
232
|
+
};
|
|
207
233
|
if (this.statusFilter())
|
|
208
234
|
filters.status = this.statusFilter();
|
|
209
235
|
if (this.typeFilter())
|
|
@@ -213,15 +239,17 @@ class TasksPageComponent {
|
|
|
213
239
|
if (this.callIdFilter().trim())
|
|
214
240
|
filters.callId = this.callIdFilter().trim();
|
|
215
241
|
this.api.getTasks(filters).subscribe({
|
|
216
|
-
next: ({
|
|
217
|
-
this.tasks.set(
|
|
242
|
+
next: ({ items, total, page }) => {
|
|
243
|
+
this.tasks.set(items);
|
|
244
|
+
this.total.set(total);
|
|
245
|
+
this.page.set(page);
|
|
218
246
|
this.loading.set(false);
|
|
219
247
|
},
|
|
220
248
|
error: () => this.loading.set(false),
|
|
221
249
|
});
|
|
222
250
|
}
|
|
223
251
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: TasksPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
224
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: TasksPageComponent, isStandalone: true, selector: "eds-tasks-page", ngImport: i0, template: "<div class=\"eds-page tasks-page\">\n <header class=\"tasks-page__header\">\n <div>\n <h1 class=\"eds-h1\">Tasks & follow-ups</h1>\n <p class=\"eds-body-sm\">Action items from calls \u2014 all types, not just refills</p>\n </div>\n </header>\n\n <section class=\"list-section\">\n <div class=\"list-toolbar\">\n <div class=\"filter-group\">\n <label for=\"task-status\">Status</label>\n <select\n id=\"task-status\"\n class=\"filter-input\"\n [value]=\"statusFilter()\"\n (change)=\"setStatusFilter($any($event.target).value)\"\n >\n <option value=\"\">All</option>\n <option value=\"open\">Open</option>\n <option value=\"in_progress\">In progress</option>\n <option value=\"done\">Done</option>\n </select>\n </div>\n <div class=\"filter-group\">\n <label for=\"task-type\">Type</label>\n <select\n id=\"task-type\"\n class=\"filter-input\"\n [value]=\"typeFilter()\"\n (change)=\"setTypeFilter($any($event.target).value)\"\n >\n <option value=\"\">All types</option>\n @for (t of typeOptions; track t) {\n <option [value]=\"t\">{{ t }}</option>\n }\n </select>\n </div>\n <div class=\"filter-group\">\n <label for=\"task-source\">Source</label>\n <select\n id=\"task-source\"\n class=\"filter-input\"\n [value]=\"sourceFilter()\"\n (change)=\"setSourceFilter($any($event.target).value)\"\n >\n <option value=\"\">All sources</option>\n <option value=\"voice\">Voice</option>\n <option value=\"sync\">Sync</option>\n <option value=\"manual\">Manual</option>\n </select>\n </div>\n <div class=\"filter-group\">\n <label for=\"task-call\">Call ID</label>\n <input\n id=\"task-call\"\n type=\"text\"\n class=\"filter-input\"\n [value]=\"callIdFilter()\"\n placeholder=\"Filter by call\"\n (change)=\"setCallIdFilter($any($event.target).value)\"\n />\n </div>\n @if (hasActiveFilters()) {\n <button type=\"button\" class=\"link-btn\" (click)=\"clearFilters()\">Clear filters</button>\n }\n </div>\n\n @if (loading()) {\n <p class=\"eds-body-sm tasks-page__loading\">Loading tasks\u2026</p>\n } @else {\n <div class=\"table-wrap\">\n <table class=\"data-table\">\n <thead>\n <tr>\n <th>Created</th>\n <th>Title</th>\n <th>Type</th>\n <th>Patient</th>\n <th>Priority</th>\n <th>Status</th>\n <th>Source</th>\n <th>Call</th>\n </tr>\n </thead>\n <tbody>\n @for (task of tasks(); track task.id) {\n <tr class=\"tasks-page__row\" (click)=\"openTask(task)\">\n <td class=\"cell-muted\">{{ task.created | date: 'MM/dd/yy, h:mm a' }}</td>\n <td class=\"tasks-page__title-cell\">{{ task.title }}</td>\n <td><eds-badge [tone]=\"taskTypeTone(task.type)\">{{ task.type }}</eds-badge></td>\n <td>{{ task.patient }}</td>\n <td>\n <eds-badge [tone]=\"taskPriorityTone(task.priority)\">\n {{ task.priority === 'urgent' ? 'Urgent' : 'Normal' }}\n </eds-badge>\n </td>\n <td><eds-badge [tone]=\"taskStatusTone(task.status)\">{{ taskStatusLabel(task.status) }}</eds-badge></td>\n <td class=\"cell-muted\">{{ taskSourceLabel(task.source) }}</td>\n <td (click)=\"$event.stopPropagation()\">\n @if (task.callId) {\n <a [routerLink]=\"taskCallRoute(task.callId)\" class=\"link-btn\">{{ task.callId }}</a>\n } @else {\n <span class=\"cell-muted\">\u2014</span>\n }\n </td>\n </tr>\n } @empty {\n <tr>\n <td colspan=\"8\" class=\"empty-state\">No tasks match these filters.</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n </section>\n</div>\n\n@if (selectedTask(); as task) {\n <eds-task-detail-drawer\n [task]=\"task\"\n (closed)=\"closeDrawer()\"\n (statusChange)=\"onStatusChange($event)\"\n />\n}", styles: [".list-section{background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-lg);box-shadow:var(--shadow-card);overflow:hidden}.list-toolbar{padding:18px 24px;display:flex;flex-wrap:wrap;align-items:flex-end;gap:14px;border-bottom:1px solid var(--color-border)}.filter-group{display:flex;flex-direction:column;gap:5px}.filter-group label{font-size:12px;font-weight:500;color:var(--color-text-muted)}.filter-input{padding:8px 10px;font-size:13px;min-width:140px}.toolbar-actions{display:flex;align-items:center;gap:8px;margin-left:auto}.result-meta{font-size:12.5px;color:var(--color-text-soft);width:100%;margin-top:4px}.api-banner{margin:0 24px 12px;padding:10px 14px;border-radius:var(--radius-md);font-size:13px}.api-banner-error{background:var(--color-danger-soft);color:var(--color-danger);border:1px solid rgba(231,111,111,.25)}.table-wrap{overflow-x:auto}.data-table{width:100%;border-collapse:collapse;min-width:720px}.data-table thead th{text-align:left;font-size:12px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:var(--color-text-muted);padding:12px 18px;background:var(--color-surface-alt);border-bottom:1px solid var(--color-border);white-space:nowrap}.data-table tbody tr{transition:background .1s ease}.data-table tbody tr:hover{background:var(--color-surface-alt)}.data-table tbody tr+tr{border-top:1px solid var(--color-border)}.data-table tbody td{padding:14px 18px;font-size:13.5px;color:var(--color-text);vertical-align:middle}.cell-muted{color:var(--color-text-muted)}.cell-mono code{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:12px;color:var(--color-text-muted);background:var(--color-surface-alt);padding:3px 7px;border-radius:4px}.cell-with-copy{display:inline-flex;align-items:center;gap:6px;max-width:100%}.cell-with-copy .cell-value{min-width:0;overflow:hidden;text-overflow:ellipsis}.empty-state{padding:48px 18px!important;text-align:center;color:var(--color-text-soft);font-size:13px}.pagination{display:flex;align-items:center;justify-content:space-between;padding:14px 24px;border-top:1px solid var(--color-border);font-size:13px;color:var(--color-text-muted)}.pagination-btns{display:flex;gap:8px}.link-btn{background:none;border:none;padding:0;color:var(--color-primary);font-size:13px;font-weight:500;cursor:pointer;text-decoration:none}.link-btn:hover{text-decoration:underline}.advanced-panel{width:100%;display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:12px;padding-top:4px}@media(max-width:920px){.list-toolbar{padding:16px 18px}}.tasks-page__header{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;margin-bottom:20px}.tasks-page__loading{padding:24px;margin:0}.tasks-page__row{cursor:pointer}.tasks-page__title-cell{font-weight:500;max-width:280px}\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: EdsBadgeComponent, selector: "eds-badge", inputs: ["tone"] }, { kind: "component", type: TaskDetailDrawerComponent, selector: "eds-task-detail-drawer", inputs: ["task"], outputs: ["closed", "statusChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
252
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: TasksPageComponent, isStandalone: true, selector: "eds-tasks-page", ngImport: i0, template: "<div class=\"eds-page tasks-page\">\n <header class=\"tasks-page__header\">\n <div>\n <h1 class=\"eds-h1\">Tasks & follow-ups</h1>\n <p class=\"eds-body-sm\">Action items from calls \u2014 all types, not just refills</p>\n </div>\n </header>\n\n <section class=\"list-section\">\n <div class=\"list-toolbar\">\n <div class=\"filter-group\">\n <label for=\"task-status\">Status</label>\n <select\n id=\"task-status\"\n class=\"filter-input\"\n [value]=\"statusFilter()\"\n (change)=\"setStatusFilter($any($event.target).value)\"\n >\n <option value=\"\">All</option>\n <option value=\"open\">Open</option>\n <option value=\"in_progress\">In progress</option>\n <option value=\"done\">Done</option>\n </select>\n </div>\n <div class=\"filter-group\">\n <label for=\"task-type\">Type</label>\n <select\n id=\"task-type\"\n class=\"filter-input\"\n [value]=\"typeFilter()\"\n (change)=\"setTypeFilter($any($event.target).value)\"\n >\n <option value=\"\">All types</option>\n @for (t of typeOptions; track t) {\n <option [value]=\"t\">{{ t }}</option>\n }\n </select>\n </div>\n <div class=\"filter-group\">\n <label for=\"task-source\">Source</label>\n <select\n id=\"task-source\"\n class=\"filter-input\"\n [value]=\"sourceFilter()\"\n (change)=\"setSourceFilter($any($event.target).value)\"\n >\n <option value=\"\">All sources</option>\n <option value=\"voice\">Voice</option>\n <option value=\"sync\">Sync</option>\n <option value=\"manual\">Manual</option>\n </select>\n </div>\n <div class=\"filter-group\">\n <label for=\"task-call\">Call ID</label>\n <input\n id=\"task-call\"\n type=\"text\"\n class=\"filter-input\"\n [value]=\"callIdFilter()\"\n placeholder=\"Filter by call\"\n (change)=\"setCallIdFilter($any($event.target).value)\"\n />\n </div>\n @if (hasActiveFilters()) {\n <button type=\"button\" class=\"link-btn\" (click)=\"clearFilters()\">Clear filters</button>\n }\n </div>\n\n @if (loading()) {\n <p class=\"eds-body-sm tasks-page__loading\">Loading tasks\u2026</p>\n } @else {\n <div class=\"table-wrap\">\n <table class=\"data-table\">\n <thead>\n <tr>\n <th>Created</th>\n <th>Title</th>\n <th>Type</th>\n <th>Patient</th>\n <th>Priority</th>\n <th>Status</th>\n <th>Source</th>\n <th>Call</th>\n </tr>\n </thead>\n <tbody>\n @for (task of tasks(); track task.id) {\n <tr class=\"tasks-page__row\" (click)=\"openTask(task)\">\n <td class=\"cell-muted\">{{ task.created | date: 'MM/dd/yy, h:mm a' }}</td>\n <td class=\"tasks-page__title-cell\">{{ task.title }}</td>\n <td><eds-badge [tone]=\"taskTypeTone(task.type)\">{{ task.type }}</eds-badge></td>\n <td>{{ task.patient }}</td>\n <td>\n <eds-badge [tone]=\"taskPriorityTone(task.priority)\">\n {{ task.priority === 'urgent' ? 'Urgent' : 'Normal' }}\n </eds-badge>\n </td>\n <td><eds-badge [tone]=\"taskStatusTone(task.status)\">{{ taskStatusLabel(task.status) }}</eds-badge></td>\n <td class=\"cell-muted\">{{ taskSourceLabel(task.source) }}</td>\n <td (click)=\"$event.stopPropagation()\">\n @if (task.callId) {\n <a [routerLink]=\"taskCallRoute(task.callId)\" class=\"link-btn\">{{ task.callId }}</a>\n } @else {\n <span class=\"cell-muted\">\u2014</span>\n }\n </td>\n </tr>\n } @empty {\n <tr>\n <td colspan=\"8\" class=\"empty-state\">No tasks match these filters.</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n\n <footer class=\"pagination\">\n <span>Page {{ page() }} of {{ totalPages() }} \u00B7 {{ total() }} total</span>\n <div class=\"pagination-btns\">\n <eds-button variant=\"secondary\" [disabled]=\"page() <= 1\" (click)=\"prevPage()\">Previous</eds-button>\n <eds-button variant=\"secondary\" [disabled]=\"page() >= totalPages()\" (click)=\"nextPage()\">Next</eds-button>\n </div>\n </footer>\n </section>\n</div>\n\n@if (selectedTask(); as task) {\n <eds-task-detail-drawer\n [task]=\"task\"\n (closed)=\"closeDrawer()\"\n (statusChange)=\"onStatusChange($event)\"\n />\n}", styles: [".list-section{background:var(--eds-color-surface);border:1px solid var(--eds-color-border);border-radius:var(--eds-radius-lg);box-shadow:var(--eds-shadow-card);overflow:hidden}.list-toolbar{padding:18px 24px;display:flex;flex-wrap:wrap;align-items:flex-end;gap:14px;border-bottom:1px solid var(--eds-color-border)}.filter-group{display:flex;flex-direction:column;gap:5px}.filter-group label{font-size:12px;font-weight:500;color:var(--eds-color-text-muted)}.filter-input{padding:8px 10px;font-size:13px;min-width:140px}.toolbar-actions{display:flex;align-items:center;gap:8px;margin-left:auto}.result-meta{font-size:12.5px;color:var(--eds-color-text-soft);width:100%;margin-top:4px}.api-banner{margin:0 24px 12px;padding:10px 14px;border-radius:var(--eds-radius-md);font-size:13px}.api-banner-error{background:var(--eds-color-danger-soft);color:var(--eds-color-danger);border:1px solid rgba(231,111,111,.25)}.table-wrap{overflow-x:auto}.data-table{width:100%;border-collapse:collapse;min-width:720px}.data-table thead th{text-align:left;font-size:12px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:var(--eds-color-text-muted);padding:12px 18px;background:var(--eds-color-surface-alt);border-bottom:1px solid var(--eds-color-border);white-space:nowrap}.data-table tbody tr{transition:background .1s ease}.data-table tbody tr:hover{background:var(--eds-color-surface-alt)}.data-table tbody tr+tr{border-top:1px solid var(--eds-color-border)}.data-table tbody td{padding:14px 18px;font-size:13.5px;color:var(--eds-color-text);vertical-align:middle}.cell-muted{color:var(--eds-color-text-muted)}.cell-mono code{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:12px;color:var(--eds-color-text-muted);background:var(--eds-color-surface-alt);padding:3px 7px;border-radius:4px}.cell-with-copy{display:inline-flex;align-items:center;gap:6px;max-width:100%}.cell-with-copy .cell-value{min-width:0;overflow:hidden;text-overflow:ellipsis}.empty-state{padding:48px 18px!important;text-align:center;color:var(--eds-color-text-soft);font-size:13px}.pagination{display:flex;align-items:center;justify-content:space-between;padding:14px 24px;border-top:1px solid var(--eds-color-border);font-size:13px;color:var(--eds-color-text-muted)}.pagination-btns{display:flex;gap:8px}.link-btn{background:none;border:none;padding:0;color:var(--eds-color-primary);font-size:13px;font-weight:500;cursor:pointer;text-decoration:none}.link-btn:hover{text-decoration:underline}.advanced-panel{width:100%;display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:12px;padding-top:4px}@media(max-width:920px){.list-toolbar{padding:16px 18px}}.tasks-page__header{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;margin-bottom:20px}.tasks-page__loading{padding:24px;margin:0}.tasks-page__row{cursor:pointer}.tasks-page__title-cell{font-weight:500;max-width:280px}\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: EdsBadgeComponent, selector: "eds-badge", inputs: ["tone"] }, { kind: "component", type: EdsButtonComponent, selector: "eds-button", inputs: ["variant", "type", "disabled"] }, { kind: "component", type: TaskDetailDrawerComponent, selector: "eds-task-detail-drawer", inputs: ["task"], outputs: ["closed", "statusChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
225
253
|
}
|
|
226
254
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: TasksPageComponent, decorators: [{
|
|
227
255
|
type: Component,
|
|
@@ -229,9 +257,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
229
257
|
DatePipe,
|
|
230
258
|
RouterLink,
|
|
231
259
|
EdsBadgeComponent,
|
|
260
|
+
EdsButtonComponent,
|
|
232
261
|
TaskDetailDrawerComponent,
|
|
233
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"eds-page tasks-page\">\n <header class=\"tasks-page__header\">\n <div>\n <h1 class=\"eds-h1\">Tasks & follow-ups</h1>\n <p class=\"eds-body-sm\">Action items from calls \u2014 all types, not just refills</p>\n </div>\n </header>\n\n <section class=\"list-section\">\n <div class=\"list-toolbar\">\n <div class=\"filter-group\">\n <label for=\"task-status\">Status</label>\n <select\n id=\"task-status\"\n class=\"filter-input\"\n [value]=\"statusFilter()\"\n (change)=\"setStatusFilter($any($event.target).value)\"\n >\n <option value=\"\">All</option>\n <option value=\"open\">Open</option>\n <option value=\"in_progress\">In progress</option>\n <option value=\"done\">Done</option>\n </select>\n </div>\n <div class=\"filter-group\">\n <label for=\"task-type\">Type</label>\n <select\n id=\"task-type\"\n class=\"filter-input\"\n [value]=\"typeFilter()\"\n (change)=\"setTypeFilter($any($event.target).value)\"\n >\n <option value=\"\">All types</option>\n @for (t of typeOptions; track t) {\n <option [value]=\"t\">{{ t }}</option>\n }\n </select>\n </div>\n <div class=\"filter-group\">\n <label for=\"task-source\">Source</label>\n <select\n id=\"task-source\"\n class=\"filter-input\"\n [value]=\"sourceFilter()\"\n (change)=\"setSourceFilter($any($event.target).value)\"\n >\n <option value=\"\">All sources</option>\n <option value=\"voice\">Voice</option>\n <option value=\"sync\">Sync</option>\n <option value=\"manual\">Manual</option>\n </select>\n </div>\n <div class=\"filter-group\">\n <label for=\"task-call\">Call ID</label>\n <input\n id=\"task-call\"\n type=\"text\"\n class=\"filter-input\"\n [value]=\"callIdFilter()\"\n placeholder=\"Filter by call\"\n (change)=\"setCallIdFilter($any($event.target).value)\"\n />\n </div>\n @if (hasActiveFilters()) {\n <button type=\"button\" class=\"link-btn\" (click)=\"clearFilters()\">Clear filters</button>\n }\n </div>\n\n @if (loading()) {\n <p class=\"eds-body-sm tasks-page__loading\">Loading tasks\u2026</p>\n } @else {\n <div class=\"table-wrap\">\n <table class=\"data-table\">\n <thead>\n <tr>\n <th>Created</th>\n <th>Title</th>\n <th>Type</th>\n <th>Patient</th>\n <th>Priority</th>\n <th>Status</th>\n <th>Source</th>\n <th>Call</th>\n </tr>\n </thead>\n <tbody>\n @for (task of tasks(); track task.id) {\n <tr class=\"tasks-page__row\" (click)=\"openTask(task)\">\n <td class=\"cell-muted\">{{ task.created | date: 'MM/dd/yy, h:mm a' }}</td>\n <td class=\"tasks-page__title-cell\">{{ task.title }}</td>\n <td><eds-badge [tone]=\"taskTypeTone(task.type)\">{{ task.type }}</eds-badge></td>\n <td>{{ task.patient }}</td>\n <td>\n <eds-badge [tone]=\"taskPriorityTone(task.priority)\">\n {{ task.priority === 'urgent' ? 'Urgent' : 'Normal' }}\n </eds-badge>\n </td>\n <td><eds-badge [tone]=\"taskStatusTone(task.status)\">{{ taskStatusLabel(task.status) }}</eds-badge></td>\n <td class=\"cell-muted\">{{ taskSourceLabel(task.source) }}</td>\n <td (click)=\"$event.stopPropagation()\">\n @if (task.callId) {\n <a [routerLink]=\"taskCallRoute(task.callId)\" class=\"link-btn\">{{ task.callId }}</a>\n } @else {\n <span class=\"cell-muted\">\u2014</span>\n }\n </td>\n </tr>\n } @empty {\n <tr>\n <td colspan=\"8\" class=\"empty-state\">No tasks match these filters.</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n </section>\n</div>\n\n@if (selectedTask(); as task) {\n <eds-task-detail-drawer\n [task]=\"task\"\n (closed)=\"closeDrawer()\"\n (statusChange)=\"onStatusChange($event)\"\n />\n}", styles: [".list-section{background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-lg);box-shadow:var(--shadow-card);overflow:hidden}.list-toolbar{padding:18px 24px;display:flex;flex-wrap:wrap;align-items:flex-end;gap:14px;border-bottom:1px solid var(--color-border)}.filter-group{display:flex;flex-direction:column;gap:5px}.filter-group label{font-size:12px;font-weight:500;color:var(--color-text-muted)}.filter-input{padding:8px 10px;font-size:13px;min-width:140px}.toolbar-actions{display:flex;align-items:center;gap:8px;margin-left:auto}.result-meta{font-size:12.5px;color:var(--color-text-soft);width:100%;margin-top:4px}.api-banner{margin:0 24px 12px;padding:10px 14px;border-radius:var(--radius-md);font-size:13px}.api-banner-error{background:var(--color-danger-soft);color:var(--color-danger);border:1px solid rgba(231,111,111,.25)}.table-wrap{overflow-x:auto}.data-table{width:100%;border-collapse:collapse;min-width:720px}.data-table thead th{text-align:left;font-size:12px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:var(--color-text-muted);padding:12px 18px;background:var(--color-surface-alt);border-bottom:1px solid var(--color-border);white-space:nowrap}.data-table tbody tr{transition:background .1s ease}.data-table tbody tr:hover{background:var(--color-surface-alt)}.data-table tbody tr+tr{border-top:1px solid var(--color-border)}.data-table tbody td{padding:14px 18px;font-size:13.5px;color:var(--color-text);vertical-align:middle}.cell-muted{color:var(--color-text-muted)}.cell-mono code{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:12px;color:var(--color-text-muted);background:var(--color-surface-alt);padding:3px 7px;border-radius:4px}.cell-with-copy{display:inline-flex;align-items:center;gap:6px;max-width:100%}.cell-with-copy .cell-value{min-width:0;overflow:hidden;text-overflow:ellipsis}.empty-state{padding:48px 18px!important;text-align:center;color:var(--color-text-soft);font-size:13px}.pagination{display:flex;align-items:center;justify-content:space-between;padding:14px 24px;border-top:1px solid var(--color-border);font-size:13px;color:var(--color-text-muted)}.pagination-btns{display:flex;gap:8px}.link-btn{background:none;border:none;padding:0;color:var(--color-primary);font-size:13px;font-weight:500;cursor:pointer;text-decoration:none}.link-btn:hover{text-decoration:underline}.advanced-panel{width:100%;display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:12px;padding-top:4px}@media(max-width:920px){.list-toolbar{padding:16px 18px}}.tasks-page__header{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;margin-bottom:20px}.tasks-page__loading{padding:24px;margin:0}.tasks-page__row{cursor:pointer}.tasks-page__title-cell{font-weight:500;max-width:280px}\n"] }]
|
|
262
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"eds-page tasks-page\">\n <header class=\"tasks-page__header\">\n <div>\n <h1 class=\"eds-h1\">Tasks & follow-ups</h1>\n <p class=\"eds-body-sm\">Action items from calls \u2014 all types, not just refills</p>\n </div>\n </header>\n\n <section class=\"list-section\">\n <div class=\"list-toolbar\">\n <div class=\"filter-group\">\n <label for=\"task-status\">Status</label>\n <select\n id=\"task-status\"\n class=\"filter-input\"\n [value]=\"statusFilter()\"\n (change)=\"setStatusFilter($any($event.target).value)\"\n >\n <option value=\"\">All</option>\n <option value=\"open\">Open</option>\n <option value=\"in_progress\">In progress</option>\n <option value=\"done\">Done</option>\n </select>\n </div>\n <div class=\"filter-group\">\n <label for=\"task-type\">Type</label>\n <select\n id=\"task-type\"\n class=\"filter-input\"\n [value]=\"typeFilter()\"\n (change)=\"setTypeFilter($any($event.target).value)\"\n >\n <option value=\"\">All types</option>\n @for (t of typeOptions; track t) {\n <option [value]=\"t\">{{ t }}</option>\n }\n </select>\n </div>\n <div class=\"filter-group\">\n <label for=\"task-source\">Source</label>\n <select\n id=\"task-source\"\n class=\"filter-input\"\n [value]=\"sourceFilter()\"\n (change)=\"setSourceFilter($any($event.target).value)\"\n >\n <option value=\"\">All sources</option>\n <option value=\"voice\">Voice</option>\n <option value=\"sync\">Sync</option>\n <option value=\"manual\">Manual</option>\n </select>\n </div>\n <div class=\"filter-group\">\n <label for=\"task-call\">Call ID</label>\n <input\n id=\"task-call\"\n type=\"text\"\n class=\"filter-input\"\n [value]=\"callIdFilter()\"\n placeholder=\"Filter by call\"\n (change)=\"setCallIdFilter($any($event.target).value)\"\n />\n </div>\n @if (hasActiveFilters()) {\n <button type=\"button\" class=\"link-btn\" (click)=\"clearFilters()\">Clear filters</button>\n }\n </div>\n\n @if (loading()) {\n <p class=\"eds-body-sm tasks-page__loading\">Loading tasks\u2026</p>\n } @else {\n <div class=\"table-wrap\">\n <table class=\"data-table\">\n <thead>\n <tr>\n <th>Created</th>\n <th>Title</th>\n <th>Type</th>\n <th>Patient</th>\n <th>Priority</th>\n <th>Status</th>\n <th>Source</th>\n <th>Call</th>\n </tr>\n </thead>\n <tbody>\n @for (task of tasks(); track task.id) {\n <tr class=\"tasks-page__row\" (click)=\"openTask(task)\">\n <td class=\"cell-muted\">{{ task.created | date: 'MM/dd/yy, h:mm a' }}</td>\n <td class=\"tasks-page__title-cell\">{{ task.title }}</td>\n <td><eds-badge [tone]=\"taskTypeTone(task.type)\">{{ task.type }}</eds-badge></td>\n <td>{{ task.patient }}</td>\n <td>\n <eds-badge [tone]=\"taskPriorityTone(task.priority)\">\n {{ task.priority === 'urgent' ? 'Urgent' : 'Normal' }}\n </eds-badge>\n </td>\n <td><eds-badge [tone]=\"taskStatusTone(task.status)\">{{ taskStatusLabel(task.status) }}</eds-badge></td>\n <td class=\"cell-muted\">{{ taskSourceLabel(task.source) }}</td>\n <td (click)=\"$event.stopPropagation()\">\n @if (task.callId) {\n <a [routerLink]=\"taskCallRoute(task.callId)\" class=\"link-btn\">{{ task.callId }}</a>\n } @else {\n <span class=\"cell-muted\">\u2014</span>\n }\n </td>\n </tr>\n } @empty {\n <tr>\n <td colspan=\"8\" class=\"empty-state\">No tasks match these filters.</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n\n <footer class=\"pagination\">\n <span>Page {{ page() }} of {{ totalPages() }} \u00B7 {{ total() }} total</span>\n <div class=\"pagination-btns\">\n <eds-button variant=\"secondary\" [disabled]=\"page() <= 1\" (click)=\"prevPage()\">Previous</eds-button>\n <eds-button variant=\"secondary\" [disabled]=\"page() >= totalPages()\" (click)=\"nextPage()\">Next</eds-button>\n </div>\n </footer>\n </section>\n</div>\n\n@if (selectedTask(); as task) {\n <eds-task-detail-drawer\n [task]=\"task\"\n (closed)=\"closeDrawer()\"\n (statusChange)=\"onStatusChange($event)\"\n />\n}", styles: [".list-section{background:var(--eds-color-surface);border:1px solid var(--eds-color-border);border-radius:var(--eds-radius-lg);box-shadow:var(--eds-shadow-card);overflow:hidden}.list-toolbar{padding:18px 24px;display:flex;flex-wrap:wrap;align-items:flex-end;gap:14px;border-bottom:1px solid var(--eds-color-border)}.filter-group{display:flex;flex-direction:column;gap:5px}.filter-group label{font-size:12px;font-weight:500;color:var(--eds-color-text-muted)}.filter-input{padding:8px 10px;font-size:13px;min-width:140px}.toolbar-actions{display:flex;align-items:center;gap:8px;margin-left:auto}.result-meta{font-size:12.5px;color:var(--eds-color-text-soft);width:100%;margin-top:4px}.api-banner{margin:0 24px 12px;padding:10px 14px;border-radius:var(--eds-radius-md);font-size:13px}.api-banner-error{background:var(--eds-color-danger-soft);color:var(--eds-color-danger);border:1px solid rgba(231,111,111,.25)}.table-wrap{overflow-x:auto}.data-table{width:100%;border-collapse:collapse;min-width:720px}.data-table thead th{text-align:left;font-size:12px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:var(--eds-color-text-muted);padding:12px 18px;background:var(--eds-color-surface-alt);border-bottom:1px solid var(--eds-color-border);white-space:nowrap}.data-table tbody tr{transition:background .1s ease}.data-table tbody tr:hover{background:var(--eds-color-surface-alt)}.data-table tbody tr+tr{border-top:1px solid var(--eds-color-border)}.data-table tbody td{padding:14px 18px;font-size:13.5px;color:var(--eds-color-text);vertical-align:middle}.cell-muted{color:var(--eds-color-text-muted)}.cell-mono code{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:12px;color:var(--eds-color-text-muted);background:var(--eds-color-surface-alt);padding:3px 7px;border-radius:4px}.cell-with-copy{display:inline-flex;align-items:center;gap:6px;max-width:100%}.cell-with-copy .cell-value{min-width:0;overflow:hidden;text-overflow:ellipsis}.empty-state{padding:48px 18px!important;text-align:center;color:var(--eds-color-text-soft);font-size:13px}.pagination{display:flex;align-items:center;justify-content:space-between;padding:14px 24px;border-top:1px solid var(--eds-color-border);font-size:13px;color:var(--eds-color-text-muted)}.pagination-btns{display:flex;gap:8px}.link-btn{background:none;border:none;padding:0;color:var(--eds-color-primary);font-size:13px;font-weight:500;cursor:pointer;text-decoration:none}.link-btn:hover{text-decoration:underline}.advanced-panel{width:100%;display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:12px;padding-top:4px}@media(max-width:920px){.list-toolbar{padding:16px 18px}}.tasks-page__header{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;margin-bottom:20px}.tasks-page__loading{padding:24px;margin:0}.tasks-page__row{cursor:pointer}.tasks-page__title-cell{font-weight:500;max-width:280px}\n"] }]
|
|
234
263
|
}] });
|
|
235
264
|
|
|
236
265
|
export { TasksPageComponent };
|
|
237
|
-
//# sourceMappingURL=edvak99-voice-receptionist-widget-tasks-page.component-
|
|
266
|
+
//# sourceMappingURL=edvak99-voice-receptionist-widget-tasks-page.component-DXxjMVUv.mjs.map
|