@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-outbound-purposes-page.component-CJ8NEjcj.mjs","sources":["../../../projects/voice-receptionist-widget/src/lib/components/outbound-purpose-form-modal/outbound-purpose-form-modal.component.ts","../../../projects/voice-receptionist-widget/src/lib/components/outbound-purpose-form-modal/outbound-purpose-form-modal.component.html","../../../projects/voice-receptionist-widget/src/lib/pages/outbound-purposes-page/outbound-purposes-page.component.ts","../../../projects/voice-receptionist-widget/src/lib/pages/outbound-purposes-page/outbound-purposes-page.component.html"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n EventEmitter,\n Input,\n OnChanges,\n Output,\n SimpleChanges,\n ViewChild,\n inject,\n signal,\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport {\n CreateOutboundPurposeRequest,\n OutboundPurpose,\n OutboundPurposePlaceholder,\n OutboundRequiredField,\n UpdateOutboundPurposeRequest,\n} from '../../models/outbound-purpose.types';\nimport { AiReceptionistApiService } from '../../services/ai-receptionist-api.service';\nimport {\n REQUIRED_FIELD_OPTIONS,\n renderOpeningPreview,\n} from '../../utils/outbound-purpose.util';\nimport { DEFAULT_PLACEHOLDERS } from '../../mocks/outbound-purpose.seed';\nimport { EdsButtonComponent } from '../../ui/eds-button.component';\nimport { ModalComponent } from '../../shared/modal.component';\n\n@Component({\n selector: 'eds-outbound-purpose-form-modal',\n imports: [FormsModule, ModalComponent, EdsButtonComponent],\n templateUrl: './outbound-purpose-form-modal.component.html',\n styleUrl: './outbound-purpose-form-modal.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class OutboundPurposeFormModalComponent implements OnChanges {\n private readonly api = inject(AiReceptionistApiService);\n\n @Input() open = false;\n @Input() purpose: OutboundPurpose | null = null;\n @Output() readonly closed = new EventEmitter<void>();\n @Output() readonly saved = new EventEmitter<OutboundPurpose>();\n\n @ViewChild('templateInput') templateInput?: ElementRef<HTMLTextAreaElement>;\n\n protected readonly fieldOptions = REQUIRED_FIELD_OPTIONS;\n protected readonly saving = signal(false);\n protected readonly error = signal<string | null>(null);\n\n protected label = '';\n protected description = '';\n protected sampleOpening = '';\n protected openingTemplate = '';\n protected agentContextHint = '';\n protected requiredFields = new Set<OutboundRequiredField>();\n protected allowsCustomScript = false;\n protected sortOrder = 1;\n protected isActive = true;\n protected placeholders: OutboundPurposePlaceholder[] = DEFAULT_PLACEHOLDERS;\n\n protected get isEdit(): boolean {\n return !!this.purpose;\n }\n\n protected get previewText(): string {\n return renderOpeningPreview(this.sampleOpening, this.openingTemplate, this.placeholders);\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes['open']?.currentValue || changes['purpose']) {\n this.resetForm();\n }\n }\n\n protected close(): void {\n this.closed.emit();\n }\n\n protected toggleRequired(field: OutboundRequiredField): void {\n const next = new Set(this.requiredFields);\n if (next.has(field)) next.delete(field);\n else next.add(field);\n this.requiredFields = next;\n }\n\n protected isRequiredSelected(field: OutboundRequiredField): boolean {\n return this.requiredFields.has(field);\n }\n\n protected insertPlaceholder(token: string): void {\n const el = this.templateInput?.nativeElement;\n if (!el) {\n this.openingTemplate += token;\n return;\n }\n const start = el.selectionStart ?? this.openingTemplate.length;\n const end = el.selectionEnd ?? start;\n this.openingTemplate =\n this.openingTemplate.slice(0, start) + token + this.openingTemplate.slice(end);\n const pos = start + token.length;\n requestAnimationFrame(() => {\n el.focus();\n el.setSelectionRange(pos, pos);\n });\n }\n\n protected submit(): void {\n this.error.set(null);\n const trimmedLabel = this.label.trim();\n const trimmedTemplate = this.openingTemplate.trim();\n if (!trimmedLabel) {\n this.error.set('Label is required.');\n return;\n }\n if (!trimmedTemplate) {\n this.error.set('Opening template is required.');\n return;\n }\n if (this.sampleOpening.length > 500) {\n this.error.set('Sample opening must be 500 characters or fewer.');\n return;\n }\n\n this.saving.set(true);\n const fields = [...this.requiredFields];\n\n if (this.isEdit && this.purpose) {\n const body: UpdateOutboundPurposeRequest = {\n label: trimmedLabel,\n description: this.description.trim(),\n sampleOpening: this.sampleOpening.trim(),\n openingTemplate: trimmedTemplate,\n agentContextHint: this.agentContextHint.trim() || null,\n requiredFields: fields,\n allowsCustomScript: this.allowsCustomScript,\n sortOrder: this.sortOrder,\n isActive: this.isActive,\n };\n this.api.updateOutboundPurpose(this.purpose.purposeId, body).subscribe({\n next: (updated) => {\n this.saving.set(false);\n this.saved.emit(updated);\n this.close();\n },\n error: () => {\n this.saving.set(false);\n this.error.set('Failed to save purpose template.');\n },\n });\n return;\n }\n\n const body: CreateOutboundPurposeRequest = {\n label: trimmedLabel,\n description: this.description.trim(),\n sampleOpening: this.sampleOpening.trim(),\n openingTemplate: trimmedTemplate,\n agentContextHint: this.agentContextHint.trim() || null,\n requiredFields: fields,\n allowsCustomScript: this.allowsCustomScript,\n sortOrder: this.sortOrder,\n };\n this.api.createOutboundPurpose(body).subscribe({\n next: (created) => {\n this.saving.set(false);\n this.saved.emit(created);\n this.close();\n },\n error: () => {\n this.saving.set(false);\n this.error.set('Failed to create purpose template.');\n },\n });\n }\n\n private resetForm(): void {\n this.error.set(null);\n this.saving.set(false);\n if (this.purpose) {\n this.label = this.purpose.label;\n this.description = this.purpose.description;\n this.sampleOpening = this.purpose.sampleOpening;\n this.openingTemplate = this.purpose.openingTemplate;\n this.agentContextHint = this.purpose.agentContextHint ?? '';\n this.requiredFields = new Set(this.purpose.requiredFields);\n this.allowsCustomScript = this.purpose.allowsCustomScript;\n this.sortOrder = this.purpose.sortOrder;\n this.isActive = this.purpose.isActive;\n this.placeholders = this.purpose.placeholders?.length\n ? [...this.purpose.placeholders]\n : [...DEFAULT_PLACEHOLDERS];\n } else {\n this.label = '';\n this.description = '';\n this.sampleOpening = '';\n this.openingTemplate = 'Hi {{patientName}}, this is {{practiceName}}.';\n this.agentContextHint = '';\n this.requiredFields = new Set();\n this.allowsCustomScript = false;\n this.sortOrder = 1;\n this.isActive = true;\n this.placeholders = [...DEFAULT_PLACEHOLDERS];\n }\n }\n}\n","@if (open) {\n <app-modal\n [title]=\"isEdit ? 'Edit outbound purpose' : 'New outbound purpose'\"\n subtitle=\"Configure dialer fields and AI opening script\"\n maxWidth=\"720px\"\n (closed)=\"close()\"\n >\n <form class=\"purpose-form\" (ngSubmit)=\"submit()\" novalidate>\n <div class=\"purpose-form__grid\">\n <label class=\"purpose-form__field purpose-form__field--full\">\n <span class=\"eds-label\">Label <span class=\"purpose-form__req\">*</span></span>\n <input type=\"text\" class=\"purpose-form__input\" [(ngModel)]=\"label\" name=\"label\" required />\n </label>\n\n <label class=\"purpose-form__field purpose-form__field--full\">\n <span class=\"eds-label\">Description</span>\n <input type=\"text\" class=\"purpose-form__input\" [(ngModel)]=\"description\" name=\"description\" />\n </label>\n\n <label class=\"purpose-form__field purpose-form__field--full\">\n <span class=\"eds-label\">Sample opening (plain preview, max 500)</span>\n <textarea\n class=\"purpose-form__textarea\"\n rows=\"3\"\n maxlength=\"500\"\n [(ngModel)]=\"sampleOpening\"\n name=\"sampleOpening\"\n ></textarea>\n <span class=\"purpose-form__hint\">{{ sampleOpening.length }}/500</span>\n </label>\n\n <div class=\"purpose-form__field purpose-form__field--full\">\n <span class=\"eds-label\">Opening template <span class=\"purpose-form__req\">*</span></span>\n <div class=\"purpose-form__chips\">\n @for (chip of placeholders; track chip.token) {\n <button type=\"button\" class=\"purpose-form__chip\" (click)=\"insertPlaceholder(chip.token)\">\n {{ chip.label }}\n </button>\n }\n </div>\n <textarea\n #templateInput\n class=\"purpose-form__textarea\"\n rows=\"4\"\n [(ngModel)]=\"openingTemplate\"\n name=\"openingTemplate\"\n required\n ></textarea>\n </div>\n\n <label class=\"purpose-form__field purpose-form__field--full\">\n <span class=\"eds-label\">Agent context hint</span>\n <textarea\n class=\"purpose-form__textarea\"\n rows=\"2\"\n [(ngModel)]=\"agentContextHint\"\n name=\"agentContextHint\"\n placeholder=\"Optional guidance for the AI after the opening\"\n ></textarea>\n </label>\n\n <fieldset class=\"purpose-form__field purpose-form__field--full\">\n <legend class=\"eds-label\">Required fields</legend>\n <div class=\"purpose-form__checks\">\n @for (opt of fieldOptions; track opt.value) {\n <label class=\"purpose-form__check\">\n <input\n type=\"checkbox\"\n [checked]=\"isRequiredSelected(opt.value)\"\n (change)=\"toggleRequired(opt.value)\"\n />\n {{ opt.label }}\n </label>\n }\n </div>\n </fieldset>\n\n <label class=\"purpose-form__check purpose-form__field--full\">\n <input type=\"checkbox\" [(ngModel)]=\"allowsCustomScript\" name=\"allowsCustomScript\" />\n Allows custom script (dialer shows free-text script field)\n </label>\n\n <label class=\"purpose-form__field\">\n <span class=\"eds-label\">Sort order</span>\n <input type=\"number\" class=\"purpose-form__input\" [(ngModel)]=\"sortOrder\" name=\"sortOrder\" min=\"0\" />\n </label>\n\n @if (isEdit) {\n <label class=\"purpose-form__check\">\n <input type=\"checkbox\" [(ngModel)]=\"isActive\" name=\"isActive\" />\n Active\n </label>\n }\n </div>\n\n <section class=\"purpose-form__preview eds-card\">\n <h3 class=\"eds-label\">Live preview</h3>\n <p class=\"purpose-form__preview-text\">{{ previewText }}</p>\n </section>\n\n @if (error()) {\n <p class=\"purpose-form__error\" role=\"alert\">{{ error() }}</p>\n }\n\n <footer class=\"purpose-form__footer\">\n <eds-button variant=\"secondary\" type=\"button\" (click)=\"close()\" [disabled]=\"saving()\">\n Cancel\n </eds-button>\n <eds-button variant=\"primary\" type=\"submit\" [disabled]=\"saving()\">\n {{ saving() ? 'Saving…' : isEdit ? 'Save changes' : 'Create purpose' }}\n </eds-button>\n </footer>\n </form>\n </app-modal>\n}\n","import { ChangeDetectionStrategy, Component, inject, OnInit, signal } from '@angular/core';\nimport { RouterLink } from '@angular/router';\n\nimport { OutboundPurpose } from '../../models/outbound-purpose.types';\nimport { AiReceptionistApiService } from '../../services/ai-receptionist-api.service';\nimport { formatRequiredFields } from '../../utils/outbound-purpose.util';\nimport { OutboundPurposeFormModalComponent } from '../../components/outbound-purpose-form-modal/outbound-purpose-form-modal.component';\nimport { EdsBadgeComponent } from '../../ui/eds-badge.component';\nimport { EdsButtonComponent } from '../../ui/eds-button.component';\nimport { EdsIconComponent } from '../../ui/eds-icon.component';\n\n@Component({\n selector: 'eds-outbound-purposes-page',\n imports: [\n RouterLink,\n EdsBadgeComponent,\n EdsButtonComponent,\n EdsIconComponent,\n OutboundPurposeFormModalComponent,\n ],\n templateUrl: './outbound-purposes-page.component.html',\n styleUrl: './outbound-purposes-page.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class OutboundPurposesPageComponent implements OnInit {\n private readonly api = inject(AiReceptionistApiService);\n\n protected readonly purposes = signal<OutboundPurpose[]>([]);\n protected readonly loading = signal(true);\n protected readonly error = signal<string | null>(null);\n protected readonly modalOpen = signal(false);\n protected readonly editing = signal<OutboundPurpose | null>(null);\n\n protected formatRequiredFields = formatRequiredFields;\n\n ngOnInit(): void {\n this.load();\n }\n\n protected load(): void {\n this.loading.set(true);\n this.error.set(null);\n this.api.getOutboundPurposes(true).subscribe({\n next: ({ purposes }) => {\n this.purposes.set(purposes);\n this.loading.set(false);\n },\n error: () => {\n this.loading.set(false);\n this.error.set('Failed to load outbound purposes.');\n },\n });\n }\n\n protected openCreate(): void {\n this.editing.set(null);\n this.modalOpen.set(true);\n }\n\n protected openEdit(purpose: OutboundPurpose): void {\n this.editing.set(purpose);\n this.modalOpen.set(true);\n }\n\n protected closeModal(): void {\n this.modalOpen.set(false);\n this.editing.set(null);\n }\n\n protected onSaved(): void {\n this.load();\n }\n\n protected toggleActive(purpose: OutboundPurpose, active: boolean): void {\n this.api.updateOutboundPurpose(purpose.purposeId, { isActive: active }).subscribe({\n next: (updated) => {\n this.purposes.update((list) =>\n list.map((p) => (p.purposeId === updated.purposeId ? updated : p)),\n );\n },\n error: () => this.load(),\n });\n }\n\n protected deletePurpose(purpose: OutboundPurpose): void {\n if (purpose.isSystem) {\n this.toggleActive(purpose, false);\n return;\n }\n if (!confirm(`Delete \"${purpose.label}\"? This cannot be undone.`)) return;\n this.api.deleteOutboundPurpose(purpose.purposeId).subscribe({\n next: () => this.load(),\n error: () => this.error.set('Failed to delete purpose.'),\n });\n }\n\n protected actionLabel(purpose: OutboundPurpose): string {\n return purpose.isSystem ? 'Deactivate' : 'Delete';\n }\n}\n","<div class=\"eds-page outbound-purposes-page\">\n <header class=\"outbound-purposes-page__header\">\n <div>\n <a routerLink=\"../settings\" class=\"outbound-purposes-page__back eds-body-sm\">\n <eds-icon name=\"arrow_back\" [size]=\"16\" /> Settings\n </a>\n <h1 class=\"eds-h1\">Outbound Call Purposes</h1>\n <p class=\"eds-body-sm\">Templates that drive outbound dialer fields and AI opening scripts</p>\n </div>\n <eds-button variant=\"primary\" (click)=\"openCreate()\">\n <eds-icon name=\"add\" [size]=\"18\" /> New purpose\n </eds-button>\n </header>\n\n @if (loading()) {\n <p class=\"eds-body-sm\">Loading purposes…</p>\n } @else if (error()) {\n <p class=\"outbound-purposes-page__error eds-body-sm\" role=\"alert\">{{ error() }}</p>\n } @else {\n <article class=\"eds-card outbound-purposes-page__table-card\">\n <table class=\"eds-table\">\n <thead>\n <tr>\n <th>Label</th>\n <th>Description</th>\n <th>Required fields</th>\n <th>System</th>\n <th>Active</th>\n <th>Sort</th>\n <th>Actions</th>\n </tr>\n </thead>\n <tbody>\n @for (p of purposes(); track p.purposeId) {\n <tr>\n <td class=\"eds-body-sm-bold\">{{ p.label }}</td>\n <td class=\"eds-body-sm\">{{ p.description || '—' }}</td>\n <td class=\"eds-body-sm\">{{ formatRequiredFields(p.requiredFields) }}</td>\n <td>\n @if (p.isSystem) {\n <eds-badge tone=\"brand\">System</eds-badge>\n } @else {\n <span class=\"eds-body-sm\">—</span>\n }\n </td>\n <td>\n <label class=\"outbound-purposes-page__toggle\">\n <input\n type=\"checkbox\"\n [checked]=\"p.isActive\"\n (change)=\"toggleActive(p, $any($event.target).checked)\"\n />\n </label>\n </td>\n <td class=\"eds-mono-sm\">{{ p.sortOrder }}</td>\n <td class=\"outbound-purposes-page__actions\">\n <button type=\"button\" class=\"outbound-purposes-page__link\" (click)=\"openEdit(p)\">\n Edit\n </button>\n <button type=\"button\" class=\"outbound-purposes-page__link\" (click)=\"deletePurpose(p)\">\n {{ actionLabel(p) }}\n </button>\n </td>\n </tr>\n } @empty {\n <tr>\n <td colspan=\"7\" class=\"eds-body-sm\">No outbound purposes configured.</td>\n </tr>\n }\n </tbody>\n </table>\n </article>\n }\n\n <eds-outbound-purpose-form-modal\n [open]=\"modalOpen()\"\n [purpose]=\"editing()\"\n (closed)=\"closeModal()\"\n (saved)=\"onSaved()\"\n />\n</div>\n"],"names":[],"mappings":";;;;;;;;MAsCa,iCAAiC,CAAA;AAP9C,IAAA,WAAA,GAAA;AAQmB,QAAA,IAAA,CAAA,GAAG,GAAG,MAAM,CAAC,wBAAwB,CAAC;QAE9C,IAAA,CAAA,IAAI,GAAG,KAAK;QACZ,IAAA,CAAA,OAAO,GAA2B,IAAI;AAC5B,QAAA,IAAA,CAAA,MAAM,GAAG,IAAI,YAAY,EAAQ;AACjC,QAAA,IAAA,CAAA,KAAK,GAAG,IAAI,YAAY,EAAmB;QAI3C,IAAA,CAAA,YAAY,GAAG,sBAAsB;AACrC,QAAA,IAAA,CAAA,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC;AACtB,QAAA,IAAA,CAAA,KAAK,GAAG,MAAM,CAAgB,IAAI,CAAC;QAE5C,IAAA,CAAA,KAAK,GAAG,EAAE;QACV,IAAA,CAAA,WAAW,GAAG,EAAE;QAChB,IAAA,CAAA,aAAa,GAAG,EAAE;QAClB,IAAA,CAAA,eAAe,GAAG,EAAE;QACpB,IAAA,CAAA,gBAAgB,GAAG,EAAE;AACrB,QAAA,IAAA,CAAA,cAAc,GAAG,IAAI,GAAG,EAAyB;QACjD,IAAA,CAAA,kBAAkB,GAAG,KAAK;QAC1B,IAAA,CAAA,SAAS,GAAG,CAAC;QACb,IAAA,CAAA,QAAQ,GAAG,IAAI;QACf,IAAA,CAAA,YAAY,GAAiC,oBAAoB;AAkJ5E,IAAA;AAhJC,IAAA,IAAc,MAAM,GAAA;AAClB,QAAA,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO;IACvB;AAEA,IAAA,IAAc,WAAW,GAAA;AACvB,QAAA,OAAO,oBAAoB,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,YAAY,CAAC;IAC1F;AAEA,IAAA,WAAW,CAAC,OAAsB,EAAA;AAChC,QAAA,IAAI,OAAO,CAAC,MAAM,CAAC,EAAE,YAAY,IAAI,OAAO,CAAC,SAAS,CAAC,EAAE;YACvD,IAAI,CAAC,SAAS,EAAE;QAClB;IACF;IAEU,KAAK,GAAA;AACb,QAAA,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;IACpB;AAEU,IAAA,cAAc,CAAC,KAA4B,EAAA;QACnD,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC;AACzC,QAAA,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;AAAE,YAAA,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;;AAClC,YAAA,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;AACpB,QAAA,IAAI,CAAC,cAAc,GAAG,IAAI;IAC5B;AAEU,IAAA,kBAAkB,CAAC,KAA4B,EAAA;QACvD,OAAO,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC;IACvC;AAEU,IAAA,iBAAiB,CAAC,KAAa,EAAA;AACvC,QAAA,MAAM,EAAE,GAAG,IAAI,CAAC,aAAa,EAAE,aAAa;QAC5C,IAAI,CAAC,EAAE,EAAE;AACP,YAAA,IAAI,CAAC,eAAe,IAAI,KAAK;YAC7B;QACF;QACA,MAAM,KAAK,GAAG,EAAE,CAAC,cAAc,IAAI,IAAI,CAAC,eAAe,CAAC,MAAM;AAC9D,QAAA,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,IAAI,KAAK;AACpC,QAAA,IAAI,CAAC,eAAe;YAClB,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,KAAK,GAAG,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC;AAChF,QAAA,MAAM,GAAG,GAAG,KAAK,GAAG,KAAK,CAAC,MAAM;QAChC,qBAAqB,CAAC,MAAK;YACzB,EAAE,CAAC,KAAK,EAAE;AACV,YAAA,EAAE,CAAC,iBAAiB,CAAC,GAAG,EAAE,GAAG,CAAC;AAChC,QAAA,CAAC,CAAC;IACJ;IAEU,MAAM,GAAA;AACd,QAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;QACpB,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE;QACtC,MAAM,eAAe,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE;QACnD,IAAI,CAAC,YAAY,EAAE;AACjB,YAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,oBAAoB,CAAC;YACpC;QACF;QACA,IAAI,CAAC,eAAe,EAAE;AACpB,YAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,+BAA+B,CAAC;YAC/C;QACF;QACA,IAAI,IAAI,CAAC,aAAa,CAAC,MAAM,GAAG,GAAG,EAAE;AACnC,YAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,iDAAiD,CAAC;YACjE;QACF;AAEA,QAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC;QACrB,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC,cAAc,CAAC;QAEvC,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,OAAO,EAAE;AAC/B,YAAA,MAAM,IAAI,GAAiC;AACzC,gBAAA,KAAK,EAAE,YAAY;AACnB,gBAAA,WAAW,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE;AACpC,gBAAA,aAAa,EAAE,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE;AACxC,gBAAA,eAAe,EAAE,eAAe;gBAChC,gBAAgB,EAAE,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAE,IAAI,IAAI;AACtD,gBAAA,cAAc,EAAE,MAAM;gBACtB,kBAAkB,EAAE,IAAI,CAAC,kBAAkB;gBAC3C,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,QAAQ,EAAE,IAAI,CAAC,QAAQ;aACxB;AACD,YAAA,IAAI,CAAC,GAAG,CAAC,qBAAqB,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,SAAS,CAAC;AACrE,gBAAA,IAAI,EAAE,CAAC,OAAO,KAAI;AAChB,oBAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AACtB,oBAAA,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC;oBACxB,IAAI,CAAC,KAAK,EAAE;gBACd,CAAC;gBACD,KAAK,EAAE,MAAK;AACV,oBAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AACtB,oBAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,kCAAkC,CAAC;gBACpD,CAAC;AACF,aAAA,CAAC;YACF;QACF;AAEA,QAAA,MAAM,IAAI,GAAiC;AACzC,YAAA,KAAK,EAAE,YAAY;AACnB,YAAA,WAAW,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE;AACpC,YAAA,aAAa,EAAE,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE;AACxC,YAAA,eAAe,EAAE,eAAe;YAChC,gBAAgB,EAAE,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAE,IAAI,IAAI;AACtD,YAAA,cAAc,EAAE,MAAM;YACtB,kBAAkB,EAAE,IAAI,CAAC,kBAAkB;YAC3C,SAAS,EAAE,IAAI,CAAC,SAAS;SAC1B;QACD,IAAI,CAAC,GAAG,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC;AAC7C,YAAA,IAAI,EAAE,CAAC,OAAO,KAAI;AAChB,gBAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AACtB,gBAAA,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC;gBACxB,IAAI,CAAC,KAAK,EAAE;YACd,CAAC;YACD,KAAK,EAAE,MAAK;AACV,gBAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AACtB,gBAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,oCAAoC,CAAC;YACtD,CAAC;AACF,SAAA,CAAC;IACJ;IAEQ,SAAS,GAAA;AACf,QAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;AACpB,QAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AACtB,QAAA,IAAI,IAAI,CAAC,OAAO,EAAE;YAChB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK;YAC/B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW;YAC3C,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa;YAC/C,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,OAAO,CAAC,eAAe;YACnD,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,OAAO,CAAC,gBAAgB,IAAI,EAAE;AAC3D,YAAA,IAAI,CAAC,cAAc,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC;YAC1D,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC,OAAO,CAAC,kBAAkB;YACzD,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS;YACvC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ;YACrC,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE;kBAC3C,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY;AAC/B,kBAAE,CAAC,GAAG,oBAAoB,CAAC;QAC/B;aAAO;AACL,YAAA,IAAI,CAAC,KAAK,GAAG,EAAE;AACf,YAAA,IAAI,CAAC,WAAW,GAAG,EAAE;AACrB,YAAA,IAAI,CAAC,aAAa,GAAG,EAAE;AACvB,YAAA,IAAI,CAAC,eAAe,GAAG,+CAA+C;AACtE,YAAA,IAAI,CAAC,gBAAgB,GAAG,EAAE;AAC1B,YAAA,IAAI,CAAC,cAAc,GAAG,IAAI,GAAG,EAAE;AAC/B,YAAA,IAAI,CAAC,kBAAkB,GAAG,KAAK;AAC/B,YAAA,IAAI,CAAC,SAAS,GAAG,CAAC;AAClB,YAAA,IAAI,CAAC,QAAQ,GAAG,IAAI;AACpB,YAAA,IAAI,CAAC,YAAY,GAAG,CAAC,GAAG,oBAAoB,CAAC;QAC/C;IACF;+GAxKW,iCAAiC,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;AAAjC,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,iCAAiC,6TCtC9C,ijJAmHA,EAAA,MAAA,EAAA,CAAA,ixCAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EDlFc,WAAW,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,aAAA,EAAA,QAAA,EAAA,8CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,oBAAA,EAAA,QAAA,EAAA,8MAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,mBAAA,EAAA,QAAA,EAAA,iGAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,4BAAA,EAAA,QAAA,EAAA,uGAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,eAAA,EAAA,QAAA,EAAA,2CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,oBAAA,EAAA,QAAA,EAAA,0FAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,iBAAA,EAAA,QAAA,EAAA,wIAAA,EAAA,MAAA,EAAA,CAAA,UAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,kBAAA,EAAA,QAAA,EAAA,4EAAA,EAAA,MAAA,EAAA,CAAA,WAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,YAAA,EAAA,QAAA,EAAA,gHAAA,EAAA,MAAA,EAAA,CAAA,KAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,OAAA,EAAA,QAAA,EAAA,qDAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,UAAA,EAAA,SAAA,EAAA,gBAAA,CAAA,EAAA,OAAA,EAAA,CAAA,eAAA,CAAA,EAAA,QAAA,EAAA,CAAA,SAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,MAAA,EAAA,QAAA,EAAA,wDAAA,EAAA,MAAA,EAAA,CAAA,eAAA,CAAA,EAAA,OAAA,EAAA,CAAA,UAAA,CAAA,EAAA,QAAA,EAAA,CAAA,QAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,cAAc,sHAAE,kBAAkB,EAAA,QAAA,EAAA,YAAA,EAAA,MAAA,EAAA,CAAA,SAAA,EAAA,MAAA,EAAA,UAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA,CAAA;;4FAKhD,iCAAiC,EAAA,UAAA,EAAA,CAAA;kBAP7C,SAAS;+BACI,iCAAiC,EAAA,OAAA,EAClC,CAAC,WAAW,EAAE,cAAc,EAAE,kBAAkB,CAAC,EAAA,eAAA,EAGzC,uBAAuB,CAAC,MAAM,EAAA,QAAA,EAAA,ijJAAA,EAAA,MAAA,EAAA,CAAA,ixCAAA,CAAA,EAAA;8BAKxC,IAAI,EAAA,CAAA;sBAAZ;gBACQ,OAAO,EAAA,CAAA;sBAAf;gBACkB,MAAM,EAAA,CAAA;sBAAxB;gBACkB,KAAK,EAAA,CAAA;sBAAvB;gBAE2B,aAAa,EAAA,CAAA;sBAAxC,SAAS;uBAAC,eAAe;;;MEtBf,6BAA6B,CAAA;AAb1C,IAAA,WAAA,GAAA;AAcmB,QAAA,IAAA,CAAA,GAAG,GAAG,MAAM,CAAC,wBAAwB,CAAC;AAEpC,QAAA,IAAA,CAAA,QAAQ,GAAG,MAAM,CAAoB,EAAE,CAAC;AACxC,QAAA,IAAA,CAAA,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC;AACtB,QAAA,IAAA,CAAA,KAAK,GAAG,MAAM,CAAgB,IAAI,CAAC;AACnC,QAAA,IAAA,CAAA,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC;AACzB,QAAA,IAAA,CAAA,OAAO,GAAG,MAAM,CAAyB,IAAI,CAAC;QAEvD,IAAA,CAAA,oBAAoB,GAAG,oBAAoB;AAkEtD,IAAA;IAhEC,QAAQ,GAAA;QACN,IAAI,CAAC,IAAI,EAAE;IACb;IAEU,IAAI,GAAA;AACZ,QAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;AACtB,QAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;QACpB,IAAI,CAAC,GAAG,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC;AAC3C,YAAA,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,KAAI;AACrB,gBAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC;AAC3B,gBAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;YACzB,CAAC;YACD,KAAK,EAAE,MAAK;AACV,gBAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;AACvB,gBAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,mCAAmC,CAAC;YACrD,CAAC;AACF,SAAA,CAAC;IACJ;IAEU,UAAU,GAAA;AAClB,QAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;AACtB,QAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;IAC1B;AAEU,IAAA,QAAQ,CAAC,OAAwB,EAAA;AACzC,QAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC;AACzB,QAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;IAC1B;IAEU,UAAU,GAAA;AAClB,QAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;AACzB,QAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;IACxB;IAEU,OAAO,GAAA;QACf,IAAI,CAAC,IAAI,EAAE;IACb;IAEU,YAAY,CAAC,OAAwB,EAAE,MAAe,EAAA;AAC9D,QAAA,IAAI,CAAC,GAAG,CAAC,qBAAqB,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,SAAS,CAAC;AAChF,YAAA,IAAI,EAAE,CAAC,OAAO,KAAI;AAChB,gBAAA,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,KACxB,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,KAAK,OAAO,CAAC,SAAS,GAAG,OAAO,GAAG,CAAC,CAAC,CAAC,CACnE;YACH,CAAC;AACD,YAAA,KAAK,EAAE,MAAM,IAAI,CAAC,IAAI,EAAE;AACzB,SAAA,CAAC;IACJ;AAEU,IAAA,aAAa,CAAC,OAAwB,EAAA;AAC9C,QAAA,IAAI,OAAO,CAAC,QAAQ,EAAE;AACpB,YAAA,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,KAAK,CAAC;YACjC;QACF;QACA,IAAI,CAAC,OAAO,CAAC,CAAA,QAAA,EAAW,OAAO,CAAC,KAAK,2BAA2B,CAAC;YAAE;QACnE,IAAI,CAAC,GAAG,CAAC,qBAAqB,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC;AAC1D,YAAA,IAAI,EAAE,MAAM,IAAI,CAAC,IAAI,EAAE;YACvB,KAAK,EAAE,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,2BAA2B,CAAC;AACzD,SAAA,CAAC;IACJ;AAEU,IAAA,WAAW,CAAC,OAAwB,EAAA;QAC5C,OAAO,OAAO,CAAC,QAAQ,GAAG,YAAY,GAAG,QAAQ;IACnD;+GA1EW,6BAA6B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;mGAA7B,6BAA6B,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,4BAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,ECxB1C,g8FAiFA,EAAA,MAAA,EAAA,CAAA,yoBAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EDnEQ,UAAU,EAAA,QAAA,EAAA,cAAA,EAAA,MAAA,EAAA,CAAA,QAAA,EAAA,aAAA,EAAA,UAAA,EAAA,qBAAA,EAAA,OAAA,EAAA,MAAA,EAAA,YAAA,EAAA,kBAAA,EAAA,oBAAA,EAAA,YAAA,EAAA,YAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACV,iBAAiB,EAAA,QAAA,EAAA,WAAA,EAAA,MAAA,EAAA,CAAA,MAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACjB,kBAAkB,EAAA,QAAA,EAAA,YAAA,EAAA,MAAA,EAAA,CAAA,SAAA,EAAA,MAAA,EAAA,UAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAClB,gBAAgB,EAAA,QAAA,EAAA,UAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,QAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAChB,iCAAiC,EAAA,QAAA,EAAA,iCAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,SAAA,CAAA,EAAA,OAAA,EAAA,CAAA,QAAA,EAAA,OAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA,CAAA;;4FAM5B,6BAA6B,EAAA,UAAA,EAAA,CAAA;kBAbzC,SAAS;AACI,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,4BAA4B,EAAA,OAAA,EAC7B;wBACL,UAAU;wBACV,iBAAiB;wBACjB,kBAAkB;wBAClB,gBAAgB;wBAChB,iCAAiC;qBACpC,EAAA,eAAA,EAGgB,uBAAuB,CAAC,MAAM,EAAA,QAAA,EAAA,g8FAAA,EAAA,MAAA,EAAA,CAAA,yoBAAA,CAAA,EAAA;;;;;"}
|
|
1
|
+
{"version":3,"file":"edvak99-voice-receptionist-widget-outbound-purposes-page.component-CYSZ832p.mjs","sources":["../../../projects/voice-receptionist-widget/src/lib/components/outbound-purpose-form-modal/outbound-purpose-form-modal.component.ts","../../../projects/voice-receptionist-widget/src/lib/components/outbound-purpose-form-modal/outbound-purpose-form-modal.component.html","../../../projects/voice-receptionist-widget/src/lib/pages/outbound-purposes-page/outbound-purposes-page.component.ts","../../../projects/voice-receptionist-widget/src/lib/pages/outbound-purposes-page/outbound-purposes-page.component.html"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n EventEmitter,\n Input,\n OnChanges,\n Output,\n SimpleChanges,\n ViewChild,\n inject,\n signal,\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport {\n CreateOutboundPurposeRequest,\n OutboundPurpose,\n OutboundPurposePlaceholder,\n OutboundRequiredField,\n UpdateOutboundPurposeRequest,\n} from '../../models/outbound-purpose.types';\nimport { AiReceptionistApiService } from '../../services/ai-receptionist-api.service';\nimport {\n REQUIRED_FIELD_OPTIONS,\n renderOpeningPreview,\n} from '../../utils/outbound-purpose.util';\nimport { DEFAULT_PLACEHOLDERS } from '../../mocks/outbound-purpose.seed';\nimport { EdsButtonComponent } from '../../ui/eds-button.component';\nimport { ModalComponent } from '../../shared/modal.component';\n\n@Component({\n selector: 'eds-outbound-purpose-form-modal',\n imports: [FormsModule, ModalComponent, EdsButtonComponent],\n templateUrl: './outbound-purpose-form-modal.component.html',\n styleUrl: './outbound-purpose-form-modal.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class OutboundPurposeFormModalComponent implements OnChanges {\n private readonly api = inject(AiReceptionistApiService);\n\n @Input() open = false;\n @Input() purpose: OutboundPurpose | null = null;\n @Output() readonly closed = new EventEmitter<void>();\n @Output() readonly saved = new EventEmitter<OutboundPurpose>();\n\n @ViewChild('templateInput') templateInput?: ElementRef<HTMLTextAreaElement>;\n\n protected readonly fieldOptions = REQUIRED_FIELD_OPTIONS;\n protected readonly saving = signal(false);\n protected readonly error = signal<string | null>(null);\n\n protected label = '';\n protected description = '';\n protected sampleOpening = '';\n protected openingTemplate = '';\n protected agentContextHint = '';\n protected requiredFields = new Set<OutboundRequiredField>();\n protected allowsCustomScript = false;\n protected sortOrder = 1;\n protected isActive = true;\n protected placeholders: OutboundPurposePlaceholder[] = DEFAULT_PLACEHOLDERS;\n\n protected get isEdit(): boolean {\n return !!this.purpose;\n }\n\n protected get previewText(): string {\n return renderOpeningPreview(this.sampleOpening, this.openingTemplate, this.placeholders);\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes['open']?.currentValue || changes['purpose']) {\n this.resetForm();\n }\n }\n\n protected close(): void {\n this.closed.emit();\n }\n\n protected toggleRequired(field: OutboundRequiredField): void {\n const next = new Set(this.requiredFields);\n if (next.has(field)) next.delete(field);\n else next.add(field);\n this.requiredFields = next;\n }\n\n protected isRequiredSelected(field: OutboundRequiredField): boolean {\n return this.requiredFields.has(field);\n }\n\n protected insertPlaceholder(token: string): void {\n const el = this.templateInput?.nativeElement;\n if (!el) {\n this.openingTemplate += token;\n return;\n }\n const start = el.selectionStart ?? this.openingTemplate.length;\n const end = el.selectionEnd ?? start;\n this.openingTemplate =\n this.openingTemplate.slice(0, start) + token + this.openingTemplate.slice(end);\n const pos = start + token.length;\n requestAnimationFrame(() => {\n el.focus();\n el.setSelectionRange(pos, pos);\n });\n }\n\n protected submit(): void {\n this.error.set(null);\n const trimmedLabel = this.label.trim();\n const trimmedTemplate = this.openingTemplate.trim();\n if (!trimmedLabel) {\n this.error.set('Label is required.');\n return;\n }\n if (!trimmedTemplate) {\n this.error.set('Opening template is required.');\n return;\n }\n if (this.sampleOpening.length > 500) {\n this.error.set('Sample opening must be 500 characters or fewer.');\n return;\n }\n\n this.saving.set(true);\n const fields = [...this.requiredFields];\n\n if (this.isEdit && this.purpose) {\n const body: UpdateOutboundPurposeRequest = {\n label: trimmedLabel,\n description: this.description.trim(),\n sampleOpening: this.sampleOpening.trim(),\n openingTemplate: trimmedTemplate,\n agentContextHint: this.agentContextHint.trim() || null,\n requiredFields: fields,\n allowsCustomScript: this.allowsCustomScript,\n sortOrder: this.sortOrder,\n isActive: this.isActive,\n };\n this.api.updateOutboundPurpose(this.purpose.purposeId, body).subscribe({\n next: (updated) => {\n this.saving.set(false);\n this.saved.emit(updated);\n this.close();\n },\n error: () => {\n this.saving.set(false);\n this.error.set('Failed to save purpose template.');\n },\n });\n return;\n }\n\n const body: CreateOutboundPurposeRequest = {\n label: trimmedLabel,\n description: this.description.trim(),\n sampleOpening: this.sampleOpening.trim(),\n openingTemplate: trimmedTemplate,\n agentContextHint: this.agentContextHint.trim() || null,\n requiredFields: fields,\n allowsCustomScript: this.allowsCustomScript,\n sortOrder: this.sortOrder,\n };\n this.api.createOutboundPurpose(body).subscribe({\n next: (created) => {\n this.saving.set(false);\n this.saved.emit(created);\n this.close();\n },\n error: () => {\n this.saving.set(false);\n this.error.set('Failed to create purpose template.');\n },\n });\n }\n\n private resetForm(): void {\n this.error.set(null);\n this.saving.set(false);\n if (this.purpose) {\n this.label = this.purpose.label;\n this.description = this.purpose.description;\n this.sampleOpening = this.purpose.sampleOpening;\n this.openingTemplate = this.purpose.openingTemplate;\n this.agentContextHint = this.purpose.agentContextHint ?? '';\n this.requiredFields = new Set(this.purpose.requiredFields);\n this.allowsCustomScript = this.purpose.allowsCustomScript;\n this.sortOrder = this.purpose.sortOrder;\n this.isActive = this.purpose.isActive;\n this.placeholders = this.purpose.placeholders?.length\n ? [...this.purpose.placeholders]\n : [...DEFAULT_PLACEHOLDERS];\n } else {\n this.label = '';\n this.description = '';\n this.sampleOpening = '';\n this.openingTemplate = 'Hi {{patientName}}, this is {{practiceName}}.';\n this.agentContextHint = '';\n this.requiredFields = new Set();\n this.allowsCustomScript = false;\n this.sortOrder = 1;\n this.isActive = true;\n this.placeholders = [...DEFAULT_PLACEHOLDERS];\n }\n }\n}\n","@if (open) {\n <app-modal\n [title]=\"isEdit ? 'Edit outbound purpose' : 'New outbound purpose'\"\n subtitle=\"Configure dialer fields and AI opening script\"\n maxWidth=\"720px\"\n (closed)=\"close()\"\n >\n <form class=\"purpose-form\" (ngSubmit)=\"submit()\" novalidate>\n <div class=\"purpose-form__grid\">\n <label class=\"purpose-form__field purpose-form__field--full\">\n <span class=\"eds-label\">Label <span class=\"purpose-form__req\">*</span></span>\n <input type=\"text\" class=\"purpose-form__input\" [(ngModel)]=\"label\" name=\"label\" required />\n </label>\n\n <label class=\"purpose-form__field purpose-form__field--full\">\n <span class=\"eds-label\">Description</span>\n <input type=\"text\" class=\"purpose-form__input\" [(ngModel)]=\"description\" name=\"description\" />\n </label>\n\n <label class=\"purpose-form__field purpose-form__field--full\">\n <span class=\"eds-label\">Sample opening (plain preview, max 500)</span>\n <textarea\n class=\"purpose-form__textarea\"\n rows=\"3\"\n maxlength=\"500\"\n [(ngModel)]=\"sampleOpening\"\n name=\"sampleOpening\"\n ></textarea>\n <span class=\"purpose-form__hint\">{{ sampleOpening.length }}/500</span>\n </label>\n\n <div class=\"purpose-form__field purpose-form__field--full\">\n <span class=\"eds-label\">Opening template <span class=\"purpose-form__req\">*</span></span>\n <div class=\"purpose-form__chips\">\n @for (chip of placeholders; track chip.token) {\n <button type=\"button\" class=\"purpose-form__chip\" (click)=\"insertPlaceholder(chip.token)\">\n {{ chip.label }}\n </button>\n }\n </div>\n <textarea\n #templateInput\n class=\"purpose-form__textarea\"\n rows=\"4\"\n [(ngModel)]=\"openingTemplate\"\n name=\"openingTemplate\"\n required\n ></textarea>\n </div>\n\n <label class=\"purpose-form__field purpose-form__field--full\">\n <span class=\"eds-label\">Agent context hint</span>\n <textarea\n class=\"purpose-form__textarea\"\n rows=\"2\"\n [(ngModel)]=\"agentContextHint\"\n name=\"agentContextHint\"\n placeholder=\"Optional guidance for the AI after the opening\"\n ></textarea>\n </label>\n\n <fieldset class=\"purpose-form__field purpose-form__field--full\">\n <legend class=\"eds-label\">Required fields</legend>\n <div class=\"purpose-form__checks\">\n @for (opt of fieldOptions; track opt.value) {\n <label class=\"purpose-form__check\">\n <input\n type=\"checkbox\"\n [checked]=\"isRequiredSelected(opt.value)\"\n (change)=\"toggleRequired(opt.value)\"\n />\n {{ opt.label }}\n </label>\n }\n </div>\n </fieldset>\n\n <label class=\"purpose-form__check purpose-form__field--full\">\n <input type=\"checkbox\" [(ngModel)]=\"allowsCustomScript\" name=\"allowsCustomScript\" />\n Allows custom script (dialer shows free-text script field)\n </label>\n\n <label class=\"purpose-form__field\">\n <span class=\"eds-label\">Sort order</span>\n <input type=\"number\" class=\"purpose-form__input\" [(ngModel)]=\"sortOrder\" name=\"sortOrder\" min=\"0\" />\n </label>\n\n @if (isEdit) {\n <label class=\"purpose-form__check\">\n <input type=\"checkbox\" [(ngModel)]=\"isActive\" name=\"isActive\" />\n Active\n </label>\n }\n </div>\n\n <section class=\"purpose-form__preview eds-card\">\n <h3 class=\"eds-label\">Live preview</h3>\n <p class=\"purpose-form__preview-text\">{{ previewText }}</p>\n </section>\n\n @if (error()) {\n <p class=\"purpose-form__error\" role=\"alert\">{{ error() }}</p>\n }\n\n <footer class=\"purpose-form__footer\">\n <eds-button variant=\"secondary\" type=\"button\" (click)=\"close()\" [disabled]=\"saving()\">\n Cancel\n </eds-button>\n <eds-button variant=\"primary\" type=\"submit\" [disabled]=\"saving()\">\n {{ saving() ? 'Saving…' : isEdit ? 'Save changes' : 'Create purpose' }}\n </eds-button>\n </footer>\n </form>\n </app-modal>\n}\n","import { ChangeDetectionStrategy, Component, inject, OnInit, signal } from '@angular/core';\nimport { RouterLink } from '@angular/router';\n\nimport { OutboundPurpose } from '../../models/outbound-purpose.types';\nimport { AiReceptionistApiService } from '../../services/ai-receptionist-api.service';\nimport { formatRequiredFields } from '../../utils/outbound-purpose.util';\nimport { OutboundPurposeFormModalComponent } from '../../components/outbound-purpose-form-modal/outbound-purpose-form-modal.component';\nimport { EdsBadgeComponent } from '../../ui/eds-badge.component';\nimport { EdsButtonComponent } from '../../ui/eds-button.component';\nimport { EdsIconComponent } from '../../ui/eds-icon.component';\n\n@Component({\n selector: 'eds-outbound-purposes-page',\n imports: [\n RouterLink,\n EdsBadgeComponent,\n EdsButtonComponent,\n EdsIconComponent,\n OutboundPurposeFormModalComponent,\n ],\n templateUrl: './outbound-purposes-page.component.html',\n styleUrl: './outbound-purposes-page.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class OutboundPurposesPageComponent implements OnInit {\n private readonly api = inject(AiReceptionistApiService);\n\n protected readonly purposes = signal<OutboundPurpose[]>([]);\n protected readonly loading = signal(true);\n protected readonly error = signal<string | null>(null);\n protected readonly modalOpen = signal(false);\n protected readonly editing = signal<OutboundPurpose | null>(null);\n\n protected formatRequiredFields = formatRequiredFields;\n\n ngOnInit(): void {\n this.load();\n }\n\n protected load(): void {\n this.loading.set(true);\n this.error.set(null);\n this.api.getOutboundPurposes(true).subscribe({\n next: ({ purposes }) => {\n this.purposes.set(purposes);\n this.loading.set(false);\n },\n error: () => {\n this.loading.set(false);\n this.error.set('Failed to load outbound purposes.');\n },\n });\n }\n\n protected openCreate(): void {\n this.editing.set(null);\n this.modalOpen.set(true);\n }\n\n protected openEdit(purpose: OutboundPurpose): void {\n this.editing.set(purpose);\n this.modalOpen.set(true);\n }\n\n protected closeModal(): void {\n this.modalOpen.set(false);\n this.editing.set(null);\n }\n\n protected onSaved(): void {\n this.load();\n }\n\n protected toggleActive(purpose: OutboundPurpose, active: boolean): void {\n this.api.updateOutboundPurpose(purpose.purposeId, { isActive: active }).subscribe({\n next: (updated) => {\n this.purposes.update((list) =>\n list.map((p) => (p.purposeId === updated.purposeId ? updated : p)),\n );\n },\n error: () => this.load(),\n });\n }\n\n protected deletePurpose(purpose: OutboundPurpose): void {\n if (purpose.isSystem) {\n this.toggleActive(purpose, false);\n return;\n }\n if (!confirm(`Delete \"${purpose.label}\"? This cannot be undone.`)) return;\n this.api.deleteOutboundPurpose(purpose.purposeId).subscribe({\n next: () => this.load(),\n error: () => this.error.set('Failed to delete purpose.'),\n });\n }\n\n protected actionLabel(purpose: OutboundPurpose): string {\n return purpose.isSystem ? 'Deactivate' : 'Delete';\n }\n}\n","<div class=\"eds-page outbound-purposes-page\">\n <header class=\"outbound-purposes-page__header\">\n <div>\n <a routerLink=\"../settings\" class=\"outbound-purposes-page__back eds-body-sm\">\n <eds-icon name=\"arrow_back\" [size]=\"16\" /> Settings\n </a>\n <h1 class=\"eds-h1\">Outbound Call Purposes</h1>\n <p class=\"eds-body-sm\">Templates that drive outbound dialer fields and AI opening scripts</p>\n </div>\n <eds-button variant=\"primary\" (click)=\"openCreate()\">\n <eds-icon name=\"add\" [size]=\"18\" /> New purpose\n </eds-button>\n </header>\n\n @if (loading()) {\n <p class=\"eds-body-sm\">Loading purposes…</p>\n } @else if (error()) {\n <p class=\"outbound-purposes-page__error eds-body-sm\" role=\"alert\">{{ error() }}</p>\n } @else {\n <article class=\"eds-card outbound-purposes-page__table-card\">\n <table class=\"eds-table\">\n <thead>\n <tr>\n <th>Label</th>\n <th>Description</th>\n <th>Required fields</th>\n <th>System</th>\n <th>Active</th>\n <th>Sort</th>\n <th>Actions</th>\n </tr>\n </thead>\n <tbody>\n @for (p of purposes(); track p.purposeId) {\n <tr>\n <td class=\"eds-body-sm-bold\">{{ p.label }}</td>\n <td class=\"eds-body-sm\">{{ p.description || '—' }}</td>\n <td class=\"eds-body-sm\">{{ formatRequiredFields(p.requiredFields) }}</td>\n <td>\n @if (p.isSystem) {\n <eds-badge tone=\"brand\">System</eds-badge>\n } @else {\n <span class=\"eds-body-sm\">—</span>\n }\n </td>\n <td>\n <label class=\"outbound-purposes-page__toggle\">\n <input\n type=\"checkbox\"\n [checked]=\"p.isActive\"\n (change)=\"toggleActive(p, $any($event.target).checked)\"\n />\n </label>\n </td>\n <td class=\"eds-mono-sm\">{{ p.sortOrder }}</td>\n <td class=\"outbound-purposes-page__actions\">\n <button type=\"button\" class=\"outbound-purposes-page__link\" (click)=\"openEdit(p)\">\n Edit\n </button>\n <button type=\"button\" class=\"outbound-purposes-page__link\" (click)=\"deletePurpose(p)\">\n {{ actionLabel(p) }}\n </button>\n </td>\n </tr>\n } @empty {\n <tr>\n <td colspan=\"7\" class=\"eds-body-sm\">No outbound purposes configured.</td>\n </tr>\n }\n </tbody>\n </table>\n </article>\n }\n\n <eds-outbound-purpose-form-modal\n [open]=\"modalOpen()\"\n [purpose]=\"editing()\"\n (closed)=\"closeModal()\"\n (saved)=\"onSaved()\"\n />\n</div>\n"],"names":[],"mappings":"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"}
|
|
@@ -3,7 +3,7 @@ import { inject, signal, computed, ChangeDetectionStrategy, Component } from '@a
|
|
|
3
3
|
import * as i1 from '@angular/forms';
|
|
4
4
|
import { FormsModule } from '@angular/forms';
|
|
5
5
|
import { RouterLink } from '@angular/router';
|
|
6
|
-
import { A as AiReceptionistApiService, T as ToastService, W as WELCOME_MESSAGE_MAX,
|
|
6
|
+
import { A as AiReceptionistApiService, T as ToastService, W as WELCOME_MESSAGE_MAX, g as buildAutoWelcomeTemplate, h as resolveWelcomePreview, a as EdsBadgeComponent, E as EdsButtonComponent, b as EdsIconComponent } from './edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-Dn0GrZ6_.mjs';
|
|
7
7
|
|
|
8
8
|
/** Curated ElevenLabs voices — keep in sync with backend `tts-voice-presets.ts`. */
|
|
9
9
|
const DEFAULT_TTS_VOICE_ID = '7EzWGsX10sAS4c9m9cPf';
|
|
@@ -498,12 +498,12 @@ class SettingsPageComponent {
|
|
|
498
498
|
}
|
|
499
499
|
}
|
|
500
500
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SettingsPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
501
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: SettingsPageComponent, isStandalone: true, selector: "eds-settings-page", ngImport: i0, template: "<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\u2026' : 'Save changes' }}\n </eds-button>\n </div>\n </header>\n\n @if (loading()) {\n <p class=\"settings-page__loading\">Loading settings\u2026</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 \u2014 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\">\u201C{{ welcomePreview() }}\u201D</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\u2026' : 'Preview voice' }}\n </eds-button>\n <span class=\"settings-page__field-desc\">\n Plays a short sample in the browser \u2014 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", styles: [".settings-page__header{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;margin-bottom:24px}.settings-page__subtitle,.settings-page__loading{margin:6px 0 0;font-size:15px;line-height:1.5;color:var(--color-text-muted, #64748b)}.settings-page__save-row{display:flex;align-items:center;gap:12px;flex-shrink:0}.settings-page__saved{color:var(--color-success, #22c55e);font-weight:600;font-size:14px}.settings-page__layout{display:grid;grid-template-columns:240px minmax(0,1fr);gap:20px;align-items:start}.settings-page__sidebar{padding:8px;display:flex;flex-direction:column;gap:2px;position:sticky;top:16px;max-height:calc(100vh - 120px);overflow-y:auto}.settings-page__nav-item{display:flex;align-items:center;gap:10px;padding:11px 14px;border:none;background:none;border-radius:var(--radius-md, 8px);font-size:14px;font-weight:500;text-align:left;cursor:pointer;color:var(--color-text-muted, #64748b);width:100%;line-height:1.3}.settings-page__nav-item:hover{background:var(--surface-l1, #f9fafb);color:var(--color-text, #0f172a)}.settings-page__nav-item--active{background:var(--color-primary-light, #eaf2ff);color:var(--color-primary, #3681f4);font-weight:600}.settings-page__nav-item--disabled,.settings-page__nav-item:disabled{opacity:.45;cursor:not-allowed;color:var(--color-text-muted, #94a3b8)}.settings-page__nav-item--disabled:hover,.settings-page__nav-item:disabled:hover{background:none;color:var(--color-text-muted, #94a3b8)}.settings-page__nav-disabled-badge{margin-left:auto;font-size:11px;font-weight:600;letter-spacing:.02em;text-transform:uppercase;color:var(--color-text-muted, #94a3b8)}.settings-page__panel{padding:28px 32px;min-height:420px}.settings-page__panel-head{margin-bottom:24px;padding-bottom:16px;border-bottom:1px solid var(--color-border, #e2e8f0)}.settings-page__panel-title{margin:0 0 8px;font-size:22px;font-weight:600;color:var(--color-text, #0f172a);letter-spacing:-.01em}.settings-page__panel-desc{margin:0;font-size:15px;line-height:1.55;color:var(--color-text-muted, #64748b);max-width:640px}.settings-page__quick-link{display:flex;align-items:center;gap:14px;padding:16px 18px;margin-bottom:24px;text-decoration:none;color:inherit;border:1px solid var(--color-border, #e2e8f0);border-radius:var(--radius-md, 8px);background:var(--color-surface-alt, #f8fafc);transition:border-color .15s ease,box-shadow .15s ease}.settings-page__quick-link div{flex:1;min-width:0;display:flex;flex-direction:column;gap:4px}.settings-page__quick-link:hover{border-color:var(--color-primary, #3681f4);box-shadow:var(--shadow-sm)}.settings-page__quick-link-title{font-size:15px;font-weight:600;color:var(--color-text, #0f172a)}.settings-page__quick-link-desc{font-size:14px;line-height:1.45;color:var(--color-text-muted, #64748b)}.settings-page__fields{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:20px 28px}.settings-page__field{display:flex;flex-direction:column;gap:6px}.settings-page__field-label{display:flex;flex-wrap:wrap;align-items:center;gap:8px;font-size:14px;font-weight:600;color:var(--color-text, #0f172a);line-height:1.35}.settings-page__readonly-badge{display:inline-flex;align-items:center;padding:2px 8px;border-radius:999px;font-size:11px;font-weight:600;letter-spacing:.02em;text-transform:uppercase;color:var(--color-text-muted, #64748b);background:var(--color-surface-alt, #f1f5f9);border:1px solid var(--color-border, #e2e8f0)}.settings-page__readonly-banner{display:flex;align-items:center;gap:10px;margin:0 0 20px;padding:12px 14px;border-radius:var(--radius-md, 8px);font-size:14px;line-height:1.45;color:var(--color-text-muted, #64748b);background:var(--color-surface-alt, #f8fafc);border:1px solid var(--color-border, #e2e8f0)}.settings-page__field--readonly .settings-page__field-desc{color:var(--color-text-soft, #94a3b8)}.settings-page__input--readonly,.settings-page__input:disabled{color:var(--color-text-muted, #64748b);background:var(--color-surface-alt, #f1f5f9);border-color:var(--color-border, #e2e8f0);cursor:not-allowed;opacity:1}.settings-page__toggle-row--readonly{cursor:default;opacity:.92}.settings-page__toggle-row--readonly .settings-page__checkbox:disabled{cursor:not-allowed}.settings-page__field-desc{font-size:13px;line-height:1.45;color:var(--color-text-muted, #64748b);margin-bottom:2px}.settings-page__field--full{grid-column:1/-1}.settings-page__textarea{width:100%;padding:10px 12px;border:1px solid var(--color-border-strong, #cbd5e1);border-radius:var(--radius-md, 8px);font-size:15px;line-height:1.5;color:var(--color-text, #0f172a);font-family:inherit;resize:vertical;min-height:96px}.settings-page__textarea:focus{outline:2px solid rgba(54,129,244,.35);outline-offset:1px;border-color:var(--color-primary, #3681f4)}.settings-page__char-count{font-size:12px;color:var(--color-text-muted, #64748b);text-align:right}.settings-page__recording-hint{margin:4px 0 0;font-size:13px;line-height:1.45;color:var(--color-warning, #f59e0b)}.settings-page__welcome{grid-column:1/-1;display:flex;flex-direction:column;gap:14px;padding:18px;border:1px solid var(--color-border, #e2e8f0);border-radius:var(--radius-md, 8px);background:var(--color-surface-alt, #f8fafc)}.settings-page__welcome-preview{padding:14px 16px;background:#fff}.settings-page__welcome-preview-head{display:flex;align-items:center;gap:8px;margin-bottom:10px}.settings-page__welcome-preview-text{margin:0;font-size:15px;line-height:1.55;color:var(--color-text, #0f172a);font-style:italic}.settings-page__fields--general{margin-top:0}.settings-page__input{width:100%;padding:10px 12px;border:1px solid var(--color-border-strong, #cbd5e1);border-radius:var(--radius-md, 8px);font-size:15px;line-height:1.4;color:var(--color-text, #0f172a);background:#fff}.settings-page__input:focus{outline:2px solid rgba(54,129,244,.35);outline-offset:1px;border-color:var(--color-primary, #3681f4)}.settings-page__input::placeholder{color:var(--color-text-soft, #94a3b8)}.settings-page__select{appearance:auto;cursor:pointer}.settings-page__voice-preview-row{display:flex;flex-wrap:wrap;align-items:center;gap:12px;margin-top:10px}.settings-page__toggle-row{grid-column:1/-1;display:flex;align-items:center;justify-content:space-between;gap:16px;padding:16px 18px;border:1px solid var(--color-border, #e2e8f0);border-radius:var(--radius-md, 8px);background:var(--color-surface-alt, #f8fafc);cursor:pointer}.settings-page__toggle-copy{display:flex;flex-direction:column;gap:4px;min-width:0}.settings-page__checkbox{width:18px;height:18px;flex-shrink:0;accent-color:var(--color-primary, #3681f4);cursor:pointer}.settings-page__safety{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:12px}.settings-page__safety li{display:flex;align-items:center;gap:12px;padding:16px 18px;background:var(--color-surface-alt, #f8fafc);border:1px solid var(--color-border, #e2e8f0);border-radius:var(--radius-md, 8px)}.settings-page__safety-label{flex:1;font-size:15px;font-weight:500;color:var(--color-text, #0f172a);line-height:1.4}@media(max-width:960px){.settings-page__layout{grid-template-columns:1fr}.settings-page__sidebar{position:static;max-height:none;flex-direction:row;flex-wrap:wrap}.settings-page__nav-item{width:auto;flex:1 1 auto}.settings-page__fields{grid-template-columns:1fr}.settings-page__panel{padding:20px}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: EdsBadgeComponent, selector: "eds-badge", inputs: ["tone"] }, { kind: "component", type: EdsButtonComponent, selector: "eds-button", inputs: ["variant", "type", "disabled"] }, { kind: "component", type: EdsIconComponent, selector: "eds-icon", inputs: ["name", "size", "fill", "weight"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
501
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: SettingsPageComponent, isStandalone: true, selector: "eds-settings-page", ngImport: i0, template: "<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\u2026' : 'Save changes' }}\n </eds-button>\n </div>\n </header>\n\n @if (loading()) {\n <p class=\"settings-page__loading\">Loading settings\u2026</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 \u2014 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\">\u201C{{ welcomePreview() }}\u201D</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\u2026' : 'Preview voice' }}\n </eds-button>\n <span class=\"settings-page__field-desc\">\n Plays a short sample in the browser \u2014 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", styles: [".settings-page__header{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;margin-bottom:24px}.settings-page__subtitle,.settings-page__loading{margin:6px 0 0;font-size:15px;line-height:1.5;color:var(--eds-color-text-muted, #64748b)}.settings-page__save-row{display:flex;align-items:center;gap:12px;flex-shrink:0}.settings-page__saved{color:var(--eds-color-success, #22c55e);font-weight:600;font-size:14px}.settings-page__layout{display:grid;grid-template-columns:240px minmax(0,1fr);gap:20px;align-items:start}.settings-page__sidebar{padding:8px;display:flex;flex-direction:column;gap:2px;position:sticky;top:16px;max-height:calc(100vh - 120px);overflow-y:auto}.settings-page__nav-item{display:flex;align-items:center;gap:10px;padding:11px 14px;border:none;background:none;border-radius:var(--eds-radius-md, 8px);font-size:14px;font-weight:500;text-align:left;cursor:pointer;color:var(--eds-color-text-muted, #64748b);width:100%;line-height:1.3}.settings-page__nav-item:hover{background:var(--eds-surface-l1, #f9fafb);color:var(--eds-color-text, #0f172a)}.settings-page__nav-item--active{background:var(--eds-color-primary-light, #eaf2ff);color:var(--eds-color-primary, #3681f4);font-weight:600}.settings-page__nav-item--disabled,.settings-page__nav-item:disabled{opacity:.45;cursor:not-allowed;color:var(--eds-color-text-muted, #94a3b8)}.settings-page__nav-item--disabled:hover,.settings-page__nav-item:disabled:hover{background:none;color:var(--eds-color-text-muted, #94a3b8)}.settings-page__nav-disabled-badge{margin-left:auto;font-size:11px;font-weight:600;letter-spacing:.02em;text-transform:uppercase;color:var(--eds-color-text-muted, #94a3b8)}.settings-page__panel{padding:28px 32px;min-height:420px}.settings-page__panel-head{margin-bottom:24px;padding-bottom:16px;border-bottom:1px solid var(--eds-color-border, #e2e8f0)}.settings-page__panel-title{margin:0 0 8px;font-size:22px;font-weight:600;color:var(--eds-color-text, #0f172a);letter-spacing:-.01em}.settings-page__panel-desc{margin:0;font-size:15px;line-height:1.55;color:var(--eds-color-text-muted, #64748b);max-width:640px}.settings-page__quick-link{display:flex;align-items:center;gap:14px;padding:16px 18px;margin-bottom:24px;text-decoration:none;color:inherit;border:1px solid var(--eds-color-border, #e2e8f0);border-radius:var(--eds-radius-md, 8px);background:var(--eds-color-surface-alt, #f8fafc);transition:border-color .15s ease,box-shadow .15s ease}.settings-page__quick-link div{flex:1;min-width:0;display:flex;flex-direction:column;gap:4px}.settings-page__quick-link:hover{border-color:var(--eds-color-primary, #3681f4);box-shadow:var(--eds-shadow-sm)}.settings-page__quick-link-title{font-size:15px;font-weight:600;color:var(--eds-color-text, #0f172a)}.settings-page__quick-link-desc{font-size:14px;line-height:1.45;color:var(--eds-color-text-muted, #64748b)}.settings-page__fields{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:20px 28px}.settings-page__field{display:flex;flex-direction:column;gap:6px}.settings-page__field-label{display:flex;flex-wrap:wrap;align-items:center;gap:8px;font-size:14px;font-weight:600;color:var(--eds-color-text, #0f172a);line-height:1.35}.settings-page__readonly-badge{display:inline-flex;align-items:center;padding:2px 8px;border-radius:999px;font-size:11px;font-weight:600;letter-spacing:.02em;text-transform:uppercase;color:var(--eds-color-text-muted, #64748b);background:var(--eds-color-surface-alt, #f1f5f9);border:1px solid var(--eds-color-border, #e2e8f0)}.settings-page__readonly-banner{display:flex;align-items:center;gap:10px;margin:0 0 20px;padding:12px 14px;border-radius:var(--eds-radius-md, 8px);font-size:14px;line-height:1.45;color:var(--eds-color-text-muted, #64748b);background:var(--eds-color-surface-alt, #f8fafc);border:1px solid var(--eds-color-border, #e2e8f0)}.settings-page__field--readonly .settings-page__field-desc{color:var(--eds-color-text-soft, #94a3b8)}.settings-page__input--readonly,.settings-page__input:disabled{color:var(--eds-color-text-muted, #64748b);background:var(--eds-color-surface-alt, #f1f5f9);border-color:var(--eds-color-border, #e2e8f0);cursor:not-allowed;opacity:1}.settings-page__toggle-row--readonly{cursor:default;opacity:.92}.settings-page__toggle-row--readonly .settings-page__checkbox:disabled{cursor:not-allowed}.settings-page__field-desc{font-size:13px;line-height:1.45;color:var(--eds-color-text-muted, #64748b);margin-bottom:2px}.settings-page__field--full{grid-column:1/-1}.settings-page__textarea{width:100%;padding:10px 12px;border:1px solid var(--eds-color-border-strong, #cbd5e1);border-radius:var(--eds-radius-md, 8px);font-size:15px;line-height:1.5;color:var(--eds-color-text, #0f172a);font-family:inherit;resize:vertical;min-height:96px}.settings-page__textarea:focus{outline:2px solid rgba(54,129,244,.35);outline-offset:1px;border-color:var(--eds-color-primary, #3681f4)}.settings-page__char-count{font-size:12px;color:var(--eds-color-text-muted, #64748b);text-align:right}.settings-page__recording-hint{margin:4px 0 0;font-size:13px;line-height:1.45;color:var(--eds-color-warning, #f59e0b)}.settings-page__welcome{grid-column:1/-1;display:flex;flex-direction:column;gap:14px;padding:18px;border:1px solid var(--eds-color-border, #e2e8f0);border-radius:var(--eds-radius-md, 8px);background:var(--eds-color-surface-alt, #f8fafc)}.settings-page__welcome-preview{padding:14px 16px;background:#fff}.settings-page__welcome-preview-head{display:flex;align-items:center;gap:8px;margin-bottom:10px}.settings-page__welcome-preview-text{margin:0;font-size:15px;line-height:1.55;color:var(--eds-color-text, #0f172a);font-style:italic}.settings-page__fields--general{margin-top:0}.settings-page__input{width:100%;padding:10px 12px;border:1px solid var(--eds-color-border-strong, #cbd5e1);border-radius:var(--eds-radius-md, 8px);font-size:15px;line-height:1.4;color:var(--eds-color-text, #0f172a);background:#fff}.settings-page__input:focus{outline:2px solid rgba(54,129,244,.35);outline-offset:1px;border-color:var(--eds-color-primary, #3681f4)}.settings-page__input::placeholder{color:var(--eds-color-text-soft, #94a3b8)}.settings-page__select{appearance:auto;cursor:pointer}.settings-page__voice-preview-row{display:flex;flex-wrap:wrap;align-items:center;gap:12px;margin-top:10px}.settings-page__toggle-row{grid-column:1/-1;display:flex;align-items:center;justify-content:space-between;gap:16px;padding:16px 18px;border:1px solid var(--eds-color-border, #e2e8f0);border-radius:var(--eds-radius-md, 8px);background:var(--eds-color-surface-alt, #f8fafc);cursor:pointer}.settings-page__toggle-copy{display:flex;flex-direction:column;gap:4px;min-width:0}.settings-page__checkbox{width:18px;height:18px;flex-shrink:0;accent-color:var(--eds-color-primary, #3681f4);cursor:pointer}.settings-page__safety{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:12px}.settings-page__safety li{display:flex;align-items:center;gap:12px;padding:16px 18px;background:var(--eds-color-surface-alt, #f8fafc);border:1px solid var(--eds-color-border, #e2e8f0);border-radius:var(--eds-radius-md, 8px)}.settings-page__safety-label{flex:1;font-size:15px;font-weight:500;color:var(--eds-color-text, #0f172a);line-height:1.4}@media(max-width:960px){.settings-page__layout{grid-template-columns:1fr}.settings-page__sidebar{position:static;max-height:none;flex-direction:row;flex-wrap:wrap}.settings-page__nav-item{width:auto;flex:1 1 auto}.settings-page__fields{grid-template-columns:1fr}.settings-page__panel{padding:20px}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: EdsBadgeComponent, selector: "eds-badge", inputs: ["tone"] }, { kind: "component", type: EdsButtonComponent, selector: "eds-button", inputs: ["variant", "type", "disabled"] }, { kind: "component", type: EdsIconComponent, selector: "eds-icon", inputs: ["name", "size", "fill", "weight"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
502
502
|
}
|
|
503
503
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SettingsPageComponent, decorators: [{
|
|
504
504
|
type: Component,
|
|
505
|
-
args: [{ selector: 'eds-settings-page', imports: [FormsModule, RouterLink, EdsBadgeComponent, EdsButtonComponent, EdsIconComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<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\u2026' : 'Save changes' }}\n </eds-button>\n </div>\n </header>\n\n @if (loading()) {\n <p class=\"settings-page__loading\">Loading settings\u2026</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 \u2014 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\">\u201C{{ welcomePreview() }}\u201D</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\u2026' : 'Preview voice' }}\n </eds-button>\n <span class=\"settings-page__field-desc\">\n Plays a short sample in the browser \u2014 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", styles: [".settings-page__header{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;margin-bottom:24px}.settings-page__subtitle,.settings-page__loading{margin:6px 0 0;font-size:15px;line-height:1.5;color:var(--color-text-muted, #64748b)}.settings-page__save-row{display:flex;align-items:center;gap:12px;flex-shrink:0}.settings-page__saved{color:var(--color-success, #22c55e);font-weight:600;font-size:14px}.settings-page__layout{display:grid;grid-template-columns:240px minmax(0,1fr);gap:20px;align-items:start}.settings-page__sidebar{padding:8px;display:flex;flex-direction:column;gap:2px;position:sticky;top:16px;max-height:calc(100vh - 120px);overflow-y:auto}.settings-page__nav-item{display:flex;align-items:center;gap:10px;padding:11px 14px;border:none;background:none;border-radius:var(--radius-md, 8px);font-size:14px;font-weight:500;text-align:left;cursor:pointer;color:var(--color-text-muted, #64748b);width:100%;line-height:1.3}.settings-page__nav-item:hover{background:var(--surface-l1, #f9fafb);color:var(--color-text, #0f172a)}.settings-page__nav-item--active{background:var(--color-primary-light, #eaf2ff);color:var(--color-primary, #3681f4);font-weight:600}.settings-page__nav-item--disabled,.settings-page__nav-item:disabled{opacity:.45;cursor:not-allowed;color:var(--color-text-muted, #94a3b8)}.settings-page__nav-item--disabled:hover,.settings-page__nav-item:disabled:hover{background:none;color:var(--color-text-muted, #94a3b8)}.settings-page__nav-disabled-badge{margin-left:auto;font-size:11px;font-weight:600;letter-spacing:.02em;text-transform:uppercase;color:var(--color-text-muted, #94a3b8)}.settings-page__panel{padding:28px 32px;min-height:420px}.settings-page__panel-head{margin-bottom:24px;padding-bottom:16px;border-bottom:1px solid var(--color-border, #e2e8f0)}.settings-page__panel-title{margin:0 0 8px;font-size:22px;font-weight:600;color:var(--color-text, #0f172a);letter-spacing:-.01em}.settings-page__panel-desc{margin:0;font-size:15px;line-height:1.55;color:var(--color-text-muted, #64748b);max-width:640px}.settings-page__quick-link{display:flex;align-items:center;gap:14px;padding:16px 18px;margin-bottom:24px;text-decoration:none;color:inherit;border:1px solid var(--color-border, #e2e8f0);border-radius:var(--radius-md, 8px);background:var(--color-surface-alt, #f8fafc);transition:border-color .15s ease,box-shadow .15s ease}.settings-page__quick-link div{flex:1;min-width:0;display:flex;flex-direction:column;gap:4px}.settings-page__quick-link:hover{border-color:var(--color-primary, #3681f4);box-shadow:var(--shadow-sm)}.settings-page__quick-link-title{font-size:15px;font-weight:600;color:var(--color-text, #0f172a)}.settings-page__quick-link-desc{font-size:14px;line-height:1.45;color:var(--color-text-muted, #64748b)}.settings-page__fields{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:20px 28px}.settings-page__field{display:flex;flex-direction:column;gap:6px}.settings-page__field-label{display:flex;flex-wrap:wrap;align-items:center;gap:8px;font-size:14px;font-weight:600;color:var(--color-text, #0f172a);line-height:1.35}.settings-page__readonly-badge{display:inline-flex;align-items:center;padding:2px 8px;border-radius:999px;font-size:11px;font-weight:600;letter-spacing:.02em;text-transform:uppercase;color:var(--color-text-muted, #64748b);background:var(--color-surface-alt, #f1f5f9);border:1px solid var(--color-border, #e2e8f0)}.settings-page__readonly-banner{display:flex;align-items:center;gap:10px;margin:0 0 20px;padding:12px 14px;border-radius:var(--radius-md, 8px);font-size:14px;line-height:1.45;color:var(--color-text-muted, #64748b);background:var(--color-surface-alt, #f8fafc);border:1px solid var(--color-border, #e2e8f0)}.settings-page__field--readonly .settings-page__field-desc{color:var(--color-text-soft, #94a3b8)}.settings-page__input--readonly,.settings-page__input:disabled{color:var(--color-text-muted, #64748b);background:var(--color-surface-alt, #f1f5f9);border-color:var(--color-border, #e2e8f0);cursor:not-allowed;opacity:1}.settings-page__toggle-row--readonly{cursor:default;opacity:.92}.settings-page__toggle-row--readonly .settings-page__checkbox:disabled{cursor:not-allowed}.settings-page__field-desc{font-size:13px;line-height:1.45;color:var(--color-text-muted, #64748b);margin-bottom:2px}.settings-page__field--full{grid-column:1/-1}.settings-page__textarea{width:100%;padding:10px 12px;border:1px solid var(--color-border-strong, #cbd5e1);border-radius:var(--radius-md, 8px);font-size:15px;line-height:1.5;color:var(--color-text, #0f172a);font-family:inherit;resize:vertical;min-height:96px}.settings-page__textarea:focus{outline:2px solid rgba(54,129,244,.35);outline-offset:1px;border-color:var(--color-primary, #3681f4)}.settings-page__char-count{font-size:12px;color:var(--color-text-muted, #64748b);text-align:right}.settings-page__recording-hint{margin:4px 0 0;font-size:13px;line-height:1.45;color:var(--color-warning, #f59e0b)}.settings-page__welcome{grid-column:1/-1;display:flex;flex-direction:column;gap:14px;padding:18px;border:1px solid var(--color-border, #e2e8f0);border-radius:var(--radius-md, 8px);background:var(--color-surface-alt, #f8fafc)}.settings-page__welcome-preview{padding:14px 16px;background:#fff}.settings-page__welcome-preview-head{display:flex;align-items:center;gap:8px;margin-bottom:10px}.settings-page__welcome-preview-text{margin:0;font-size:15px;line-height:1.55;color:var(--color-text, #0f172a);font-style:italic}.settings-page__fields--general{margin-top:0}.settings-page__input{width:100%;padding:10px 12px;border:1px solid var(--color-border-strong, #cbd5e1);border-radius:var(--radius-md, 8px);font-size:15px;line-height:1.4;color:var(--color-text, #0f172a);background:#fff}.settings-page__input:focus{outline:2px solid rgba(54,129,244,.35);outline-offset:1px;border-color:var(--color-primary, #3681f4)}.settings-page__input::placeholder{color:var(--color-text-soft, #94a3b8)}.settings-page__select{appearance:auto;cursor:pointer}.settings-page__voice-preview-row{display:flex;flex-wrap:wrap;align-items:center;gap:12px;margin-top:10px}.settings-page__toggle-row{grid-column:1/-1;display:flex;align-items:center;justify-content:space-between;gap:16px;padding:16px 18px;border:1px solid var(--color-border, #e2e8f0);border-radius:var(--radius-md, 8px);background:var(--color-surface-alt, #f8fafc);cursor:pointer}.settings-page__toggle-copy{display:flex;flex-direction:column;gap:4px;min-width:0}.settings-page__checkbox{width:18px;height:18px;flex-shrink:0;accent-color:var(--color-primary, #3681f4);cursor:pointer}.settings-page__safety{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:12px}.settings-page__safety li{display:flex;align-items:center;gap:12px;padding:16px 18px;background:var(--color-surface-alt, #f8fafc);border:1px solid var(--color-border, #e2e8f0);border-radius:var(--radius-md, 8px)}.settings-page__safety-label{flex:1;font-size:15px;font-weight:500;color:var(--color-text, #0f172a);line-height:1.4}@media(max-width:960px){.settings-page__layout{grid-template-columns:1fr}.settings-page__sidebar{position:static;max-height:none;flex-direction:row;flex-wrap:wrap}.settings-page__nav-item{width:auto;flex:1 1 auto}.settings-page__fields{grid-template-columns:1fr}.settings-page__panel{padding:20px}}\n"] }]
|
|
505
|
+
args: [{ selector: 'eds-settings-page', imports: [FormsModule, RouterLink, EdsBadgeComponent, EdsButtonComponent, EdsIconComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<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\u2026' : 'Save changes' }}\n </eds-button>\n </div>\n </header>\n\n @if (loading()) {\n <p class=\"settings-page__loading\">Loading settings\u2026</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 \u2014 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\">\u201C{{ welcomePreview() }}\u201D</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\u2026' : 'Preview voice' }}\n </eds-button>\n <span class=\"settings-page__field-desc\">\n Plays a short sample in the browser \u2014 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", styles: [".settings-page__header{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;margin-bottom:24px}.settings-page__subtitle,.settings-page__loading{margin:6px 0 0;font-size:15px;line-height:1.5;color:var(--eds-color-text-muted, #64748b)}.settings-page__save-row{display:flex;align-items:center;gap:12px;flex-shrink:0}.settings-page__saved{color:var(--eds-color-success, #22c55e);font-weight:600;font-size:14px}.settings-page__layout{display:grid;grid-template-columns:240px minmax(0,1fr);gap:20px;align-items:start}.settings-page__sidebar{padding:8px;display:flex;flex-direction:column;gap:2px;position:sticky;top:16px;max-height:calc(100vh - 120px);overflow-y:auto}.settings-page__nav-item{display:flex;align-items:center;gap:10px;padding:11px 14px;border:none;background:none;border-radius:var(--eds-radius-md, 8px);font-size:14px;font-weight:500;text-align:left;cursor:pointer;color:var(--eds-color-text-muted, #64748b);width:100%;line-height:1.3}.settings-page__nav-item:hover{background:var(--eds-surface-l1, #f9fafb);color:var(--eds-color-text, #0f172a)}.settings-page__nav-item--active{background:var(--eds-color-primary-light, #eaf2ff);color:var(--eds-color-primary, #3681f4);font-weight:600}.settings-page__nav-item--disabled,.settings-page__nav-item:disabled{opacity:.45;cursor:not-allowed;color:var(--eds-color-text-muted, #94a3b8)}.settings-page__nav-item--disabled:hover,.settings-page__nav-item:disabled:hover{background:none;color:var(--eds-color-text-muted, #94a3b8)}.settings-page__nav-disabled-badge{margin-left:auto;font-size:11px;font-weight:600;letter-spacing:.02em;text-transform:uppercase;color:var(--eds-color-text-muted, #94a3b8)}.settings-page__panel{padding:28px 32px;min-height:420px}.settings-page__panel-head{margin-bottom:24px;padding-bottom:16px;border-bottom:1px solid var(--eds-color-border, #e2e8f0)}.settings-page__panel-title{margin:0 0 8px;font-size:22px;font-weight:600;color:var(--eds-color-text, #0f172a);letter-spacing:-.01em}.settings-page__panel-desc{margin:0;font-size:15px;line-height:1.55;color:var(--eds-color-text-muted, #64748b);max-width:640px}.settings-page__quick-link{display:flex;align-items:center;gap:14px;padding:16px 18px;margin-bottom:24px;text-decoration:none;color:inherit;border:1px solid var(--eds-color-border, #e2e8f0);border-radius:var(--eds-radius-md, 8px);background:var(--eds-color-surface-alt, #f8fafc);transition:border-color .15s ease,box-shadow .15s ease}.settings-page__quick-link div{flex:1;min-width:0;display:flex;flex-direction:column;gap:4px}.settings-page__quick-link:hover{border-color:var(--eds-color-primary, #3681f4);box-shadow:var(--eds-shadow-sm)}.settings-page__quick-link-title{font-size:15px;font-weight:600;color:var(--eds-color-text, #0f172a)}.settings-page__quick-link-desc{font-size:14px;line-height:1.45;color:var(--eds-color-text-muted, #64748b)}.settings-page__fields{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:20px 28px}.settings-page__field{display:flex;flex-direction:column;gap:6px}.settings-page__field-label{display:flex;flex-wrap:wrap;align-items:center;gap:8px;font-size:14px;font-weight:600;color:var(--eds-color-text, #0f172a);line-height:1.35}.settings-page__readonly-badge{display:inline-flex;align-items:center;padding:2px 8px;border-radius:999px;font-size:11px;font-weight:600;letter-spacing:.02em;text-transform:uppercase;color:var(--eds-color-text-muted, #64748b);background:var(--eds-color-surface-alt, #f1f5f9);border:1px solid var(--eds-color-border, #e2e8f0)}.settings-page__readonly-banner{display:flex;align-items:center;gap:10px;margin:0 0 20px;padding:12px 14px;border-radius:var(--eds-radius-md, 8px);font-size:14px;line-height:1.45;color:var(--eds-color-text-muted, #64748b);background:var(--eds-color-surface-alt, #f8fafc);border:1px solid var(--eds-color-border, #e2e8f0)}.settings-page__field--readonly .settings-page__field-desc{color:var(--eds-color-text-soft, #94a3b8)}.settings-page__input--readonly,.settings-page__input:disabled{color:var(--eds-color-text-muted, #64748b);background:var(--eds-color-surface-alt, #f1f5f9);border-color:var(--eds-color-border, #e2e8f0);cursor:not-allowed;opacity:1}.settings-page__toggle-row--readonly{cursor:default;opacity:.92}.settings-page__toggle-row--readonly .settings-page__checkbox:disabled{cursor:not-allowed}.settings-page__field-desc{font-size:13px;line-height:1.45;color:var(--eds-color-text-muted, #64748b);margin-bottom:2px}.settings-page__field--full{grid-column:1/-1}.settings-page__textarea{width:100%;padding:10px 12px;border:1px solid var(--eds-color-border-strong, #cbd5e1);border-radius:var(--eds-radius-md, 8px);font-size:15px;line-height:1.5;color:var(--eds-color-text, #0f172a);font-family:inherit;resize:vertical;min-height:96px}.settings-page__textarea:focus{outline:2px solid rgba(54,129,244,.35);outline-offset:1px;border-color:var(--eds-color-primary, #3681f4)}.settings-page__char-count{font-size:12px;color:var(--eds-color-text-muted, #64748b);text-align:right}.settings-page__recording-hint{margin:4px 0 0;font-size:13px;line-height:1.45;color:var(--eds-color-warning, #f59e0b)}.settings-page__welcome{grid-column:1/-1;display:flex;flex-direction:column;gap:14px;padding:18px;border:1px solid var(--eds-color-border, #e2e8f0);border-radius:var(--eds-radius-md, 8px);background:var(--eds-color-surface-alt, #f8fafc)}.settings-page__welcome-preview{padding:14px 16px;background:#fff}.settings-page__welcome-preview-head{display:flex;align-items:center;gap:8px;margin-bottom:10px}.settings-page__welcome-preview-text{margin:0;font-size:15px;line-height:1.55;color:var(--eds-color-text, #0f172a);font-style:italic}.settings-page__fields--general{margin-top:0}.settings-page__input{width:100%;padding:10px 12px;border:1px solid var(--eds-color-border-strong, #cbd5e1);border-radius:var(--eds-radius-md, 8px);font-size:15px;line-height:1.4;color:var(--eds-color-text, #0f172a);background:#fff}.settings-page__input:focus{outline:2px solid rgba(54,129,244,.35);outline-offset:1px;border-color:var(--eds-color-primary, #3681f4)}.settings-page__input::placeholder{color:var(--eds-color-text-soft, #94a3b8)}.settings-page__select{appearance:auto;cursor:pointer}.settings-page__voice-preview-row{display:flex;flex-wrap:wrap;align-items:center;gap:12px;margin-top:10px}.settings-page__toggle-row{grid-column:1/-1;display:flex;align-items:center;justify-content:space-between;gap:16px;padding:16px 18px;border:1px solid var(--eds-color-border, #e2e8f0);border-radius:var(--eds-radius-md, 8px);background:var(--eds-color-surface-alt, #f8fafc);cursor:pointer}.settings-page__toggle-copy{display:flex;flex-direction:column;gap:4px;min-width:0}.settings-page__checkbox{width:18px;height:18px;flex-shrink:0;accent-color:var(--eds-color-primary, #3681f4);cursor:pointer}.settings-page__safety{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:12px}.settings-page__safety li{display:flex;align-items:center;gap:12px;padding:16px 18px;background:var(--eds-color-surface-alt, #f8fafc);border:1px solid var(--eds-color-border, #e2e8f0);border-radius:var(--eds-radius-md, 8px)}.settings-page__safety-label{flex:1;font-size:15px;font-weight:500;color:var(--eds-color-text, #0f172a);line-height:1.4}@media(max-width:960px){.settings-page__layout{grid-template-columns:1fr}.settings-page__sidebar{position:static;max-height:none;flex-direction:row;flex-wrap:wrap}.settings-page__nav-item{width:auto;flex:1 1 auto}.settings-page__fields{grid-template-columns:1fr}.settings-page__panel{padding:20px}}\n"] }]
|
|
506
506
|
}] });
|
|
507
507
|
|
|
508
508
|
export { SettingsPageComponent };
|
|
509
|
-
//# sourceMappingURL=edvak99-voice-receptionist-widget-settings-page.component-
|
|
509
|
+
//# sourceMappingURL=edvak99-voice-receptionist-widget-settings-page.component-B9nv6wtB.mjs.map
|