@edvak99/voice-receptionist-widget 1.1.21 → 1.1.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/fesm2022/edvak99-voice-receptionist-widget-activities-page.component-dcDXT2KG.mjs +533 -0
  2. package/fesm2022/edvak99-voice-receptionist-widget-activities-page.component-dcDXT2KG.mjs.map +1 -0
  3. package/fesm2022/{edvak99-voice-receptionist-widget-analytics-page.component-CmImX5FN.mjs → edvak99-voice-receptionist-widget-analytics-page.component-B25yZJZz.mjs} +2 -2
  4. package/fesm2022/{edvak99-voice-receptionist-widget-analytics-page.component-CmImX5FN.mjs.map → edvak99-voice-receptionist-widget-analytics-page.component-B25yZJZz.mjs.map} +1 -1
  5. package/fesm2022/edvak99-voice-receptionist-widget-audit-page.component-Df-dtgR3.mjs +96 -0
  6. package/fesm2022/edvak99-voice-receptionist-widget-audit-page.component-Df-dtgR3.mjs.map +1 -0
  7. package/fesm2022/{edvak99-voice-receptionist-widget-call-history-detail-page.component-BT4clUO-.mjs → edvak99-voice-receptionist-widget-call-history-detail-page.component-BJGzgVxG.mjs} +21 -10
  8. package/fesm2022/edvak99-voice-receptionist-widget-call-history-detail-page.component-BJGzgVxG.mjs.map +1 -0
  9. package/fesm2022/edvak99-voice-receptionist-widget-call-history-page.component-CcwwO5SO.mjs +254 -0
  10. package/fesm2022/edvak99-voice-receptionist-widget-call-history-page.component-CcwwO5SO.mjs.map +1 -0
  11. package/fesm2022/{edvak99-voice-receptionist-widget-call-recording-player.component-4fL-zUWy.mjs → edvak99-voice-receptionist-widget-call-recording-player.component-BepxNLNQ.mjs} +2 -2
  12. package/fesm2022/{edvak99-voice-receptionist-widget-call-recording-player.component-4fL-zUWy.mjs.map → edvak99-voice-receptionist-widget-call-recording-player.component-BepxNLNQ.mjs.map} +1 -1
  13. package/fesm2022/{edvak99-voice-receptionist-widget-call-review.service-BhbCmB1S.mjs → edvak99-voice-receptionist-widget-call-review.service-nFqc30t3.mjs} +2 -2
  14. package/fesm2022/{edvak99-voice-receptionist-widget-call-review.service-BhbCmB1S.mjs.map → edvak99-voice-receptionist-widget-call-review.service-nFqc30t3.mjs.map} +1 -1
  15. package/fesm2022/edvak99-voice-receptionist-widget-dashboard-page.component-CMgOu0aw.mjs +311 -0
  16. package/fesm2022/edvak99-voice-receptionist-widget-dashboard-page.component-CMgOu0aw.mjs.map +1 -0
  17. package/fesm2022/{edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-DDS7VdnD.mjs → edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-CJ1L6QeE.mjs} +54 -25
  18. package/fesm2022/edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-CJ1L6QeE.mjs.map +1 -0
  19. package/fesm2022/{edvak99-voice-receptionist-widget-live-calls-page.component-4LtgT4lS.mjs → edvak99-voice-receptionist-widget-live-calls-page.component-MnBMu8iA.mjs} +4 -4
  20. package/fesm2022/edvak99-voice-receptionist-widget-live-calls-page.component-MnBMu8iA.mjs.map +1 -0
  21. package/fesm2022/{edvak99-voice-receptionist-widget-live-monitor-page.component-B1lKfw-j.mjs → edvak99-voice-receptionist-widget-live-monitor-page.component-BzvMkbC4.mjs} +10 -7
  22. package/fesm2022/edvak99-voice-receptionist-widget-live-monitor-page.component-BzvMkbC4.mjs.map +1 -0
  23. package/fesm2022/edvak99-voice-receptionist-widget-outbound-purposes-page.component-Aws6TaaE.mjs +273 -0
  24. package/fesm2022/edvak99-voice-receptionist-widget-outbound-purposes-page.component-Aws6TaaE.mjs.map +1 -0
  25. package/fesm2022/{edvak99-voice-receptionist-widget-task-detail-drawer.component-aDTKTV79.mjs → edvak99-voice-receptionist-widget-task-detail-drawer.component-DVWdArqj.mjs} +14 -6
  26. package/fesm2022/edvak99-voice-receptionist-widget-task-detail-drawer.component-DVWdArqj.mjs.map +1 -0
  27. package/fesm2022/{edvak99-voice-receptionist-widget-tasks-page.component-Dj1nWx6V.mjs → edvak99-voice-receptionist-widget-tasks-page.component-CBDmGLol.mjs} +11 -7
  28. package/fesm2022/edvak99-voice-receptionist-widget-tasks-page.component-CBDmGLol.mjs.map +1 -0
  29. package/fesm2022/{edvak99-voice-receptionist-widget-wizard-page.component-CQttbEzW.mjs → edvak99-voice-receptionist-widget-wizard-page.component-C-hdBQIV.mjs} +2 -2
  30. package/fesm2022/{edvak99-voice-receptionist-widget-wizard-page.component-CQttbEzW.mjs.map → edvak99-voice-receptionist-widget-wizard-page.component-C-hdBQIV.mjs.map} +1 -1
  31. package/fesm2022/edvak99-voice-receptionist-widget.mjs +1 -1
  32. package/lib/components/call-tasks-panel/call-tasks-panel.component.d.ts +3 -0
  33. package/lib/components/patient-profile-drawer/patient-profile-drawer.component.d.ts +3 -0
  34. package/lib/components/task-detail-drawer/task-detail-drawer.component.d.ts +3 -0
  35. package/lib/pages/activities-page/activities-page.component.d.ts +5 -2
  36. package/lib/pages/audit-page/audit-page.component.d.ts +3 -0
  37. package/lib/pages/call-history-detail-page/call-history-detail-page.component.d.ts +2 -0
  38. package/lib/pages/call-history-page/call-history-page.component.d.ts +1 -0
  39. package/lib/pages/dashboard-page/dashboard-page.component.d.ts +4 -0
  40. package/lib/pages/live-monitor-page/live-monitor-page.component.d.ts +2 -0
  41. package/lib/pages/outbound-purposes-page/outbound-purposes-page.component.d.ts +3 -0
  42. package/lib/pages/settings-page/settings-page.component.d.ts +1 -0
  43. package/lib/pages/tasks-page/tasks-page.component.d.ts +2 -0
  44. package/lib/services/ai-receptionist-api.service.d.ts +1 -0
  45. package/package.json +1 -1
  46. package/src/assets/css/_tables.scss +12 -0
  47. package/styles/embed.scss +27 -0
  48. package/fesm2022/edvak99-voice-receptionist-widget-activities-page.component-CpXa1J9-.mjs +0 -510
  49. package/fesm2022/edvak99-voice-receptionist-widget-activities-page.component-CpXa1J9-.mjs.map +0 -1
  50. package/fesm2022/edvak99-voice-receptionist-widget-audit-page.component-DTAB2WTX.mjs +0 -78
  51. package/fesm2022/edvak99-voice-receptionist-widget-audit-page.component-DTAB2WTX.mjs.map +0 -1
  52. package/fesm2022/edvak99-voice-receptionist-widget-call-history-detail-page.component-BT4clUO-.mjs.map +0 -1
  53. package/fesm2022/edvak99-voice-receptionist-widget-call-history-page.component-BACON4uq.mjs +0 -247
  54. package/fesm2022/edvak99-voice-receptionist-widget-call-history-page.component-BACON4uq.mjs.map +0 -1
  55. package/fesm2022/edvak99-voice-receptionist-widget-dashboard-page.component-CxNYLBbg.mjs +0 -291
  56. package/fesm2022/edvak99-voice-receptionist-widget-dashboard-page.component-CxNYLBbg.mjs.map +0 -1
  57. package/fesm2022/edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-DDS7VdnD.mjs.map +0 -1
  58. package/fesm2022/edvak99-voice-receptionist-widget-live-calls-page.component-4LtgT4lS.mjs.map +0 -1
  59. package/fesm2022/edvak99-voice-receptionist-widget-live-monitor-page.component-B1lKfw-j.mjs.map +0 -1
  60. package/fesm2022/edvak99-voice-receptionist-widget-outbound-purposes-page.component-BkIHblSu.mjs +0 -269
  61. package/fesm2022/edvak99-voice-receptionist-widget-outbound-purposes-page.component-BkIHblSu.mjs.map +0 -1
  62. package/fesm2022/edvak99-voice-receptionist-widget-task-detail-drawer.component-aDTKTV79.mjs.map +0 -1
  63. package/fesm2022/edvak99-voice-receptionist-widget-tasks-page.component-Dj1nWx6V.mjs.map +0 -1
@@ -1,269 +0,0 @@
1
- import * as i0 from '@angular/core';
2
- import { inject, EventEmitter, signal, ViewChild, Output, Input, ChangeDetectionStrategy, Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
3
- import { RouterLink } from '@angular/router';
4
- import { A as AiReceptionistApiService, v as DEFAULT_PLACEHOLDERS, M as ModalComponent, f as EdButtonComponent, I as IconComponent, g as EdSkeletonComponent } from './edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-DDS7VdnD.mjs';
5
- import { R as REQUIRED_FIELD_OPTIONS, d as renderOpeningPreview, e as formatRequiredFields } from './edvak99-voice-receptionist-widget-outbound-purpose.util-Bdh4QfFe.mjs';
6
- import { S as SmartTooltipDirective } from './edvak99-voice-receptionist-widget-smart-tooltip.directive-ChEdIem3.mjs';
7
- import { T as TABLE_SKELETON_ROWS } from './edvak99-voice-receptionist-widget-table-skeleton.constants-C1Dg9Z_2.mjs';
8
- import * as i1 from '@angular/forms';
9
- import { FormsModule } from '@angular/forms';
10
-
11
- class OutboundPurposeFormModalComponent {
12
- constructor() {
13
- this.api = inject(AiReceptionistApiService);
14
- this.open = false;
15
- this.purpose = null;
16
- this.closed = new EventEmitter();
17
- this.saved = new EventEmitter();
18
- this.fieldOptions = REQUIRED_FIELD_OPTIONS;
19
- this.saving = signal(false);
20
- this.error = signal(null);
21
- this.label = '';
22
- this.description = '';
23
- this.sampleOpening = '';
24
- this.openingTemplate = '';
25
- this.agentContextHint = '';
26
- this.requiredFields = new Set();
27
- this.allowsCustomScript = false;
28
- this.sortOrder = 1;
29
- this.isActive = true;
30
- this.placeholders = DEFAULT_PLACEHOLDERS;
31
- }
32
- get isEdit() {
33
- return !!this.purpose;
34
- }
35
- get previewText() {
36
- return renderOpeningPreview(this.sampleOpening, this.openingTemplate, this.placeholders);
37
- }
38
- ngOnChanges(changes) {
39
- if (changes['open']?.currentValue || changes['purpose']) {
40
- this.resetForm();
41
- }
42
- }
43
- close() {
44
- this.closed.emit();
45
- }
46
- toggleRequired(field) {
47
- const next = new Set(this.requiredFields);
48
- if (next.has(field))
49
- next.delete(field);
50
- else
51
- next.add(field);
52
- this.requiredFields = next;
53
- }
54
- isRequiredSelected(field) {
55
- return this.requiredFields.has(field);
56
- }
57
- insertPlaceholder(token) {
58
- const el = this.templateInput?.nativeElement;
59
- if (!el) {
60
- this.openingTemplate += token;
61
- return;
62
- }
63
- const start = el.selectionStart ?? this.openingTemplate.length;
64
- const end = el.selectionEnd ?? start;
65
- this.openingTemplate =
66
- this.openingTemplate.slice(0, start) + token + this.openingTemplate.slice(end);
67
- const pos = start + token.length;
68
- requestAnimationFrame(() => {
69
- el.focus();
70
- el.setSelectionRange(pos, pos);
71
- });
72
- }
73
- submit() {
74
- this.error.set(null);
75
- const trimmedLabel = this.label.trim();
76
- const trimmedTemplate = this.openingTemplate.trim();
77
- if (!trimmedLabel) {
78
- this.error.set('Label is required.');
79
- return;
80
- }
81
- if (!trimmedTemplate) {
82
- this.error.set('Opening template is required.');
83
- return;
84
- }
85
- if (this.sampleOpening.length > 500) {
86
- this.error.set('Sample opening must be 500 characters or fewer.');
87
- return;
88
- }
89
- this.saving.set(true);
90
- const fields = [...this.requiredFields];
91
- if (this.isEdit && this.purpose) {
92
- const body = {
93
- label: trimmedLabel,
94
- description: this.description.trim(),
95
- sampleOpening: this.sampleOpening.trim(),
96
- openingTemplate: trimmedTemplate,
97
- agentContextHint: this.agentContextHint.trim() || null,
98
- requiredFields: fields,
99
- allowsCustomScript: this.allowsCustomScript,
100
- sortOrder: this.sortOrder,
101
- isActive: this.isActive,
102
- };
103
- this.api.updateOutboundPurpose(this.purpose.purposeId, body).subscribe({
104
- next: (updated) => {
105
- this.saving.set(false);
106
- this.saved.emit(updated);
107
- this.close();
108
- },
109
- error: () => {
110
- this.saving.set(false);
111
- this.error.set('Failed to save purpose template.');
112
- },
113
- });
114
- return;
115
- }
116
- const body = {
117
- label: trimmedLabel,
118
- description: this.description.trim(),
119
- sampleOpening: this.sampleOpening.trim(),
120
- openingTemplate: trimmedTemplate,
121
- agentContextHint: this.agentContextHint.trim() || null,
122
- requiredFields: fields,
123
- allowsCustomScript: this.allowsCustomScript,
124
- sortOrder: this.sortOrder,
125
- };
126
- this.api.createOutboundPurpose(body).subscribe({
127
- next: (created) => {
128
- this.saving.set(false);
129
- this.saved.emit(created);
130
- this.close();
131
- },
132
- error: () => {
133
- this.saving.set(false);
134
- this.error.set('Failed to create purpose template.');
135
- },
136
- });
137
- }
138
- resetForm() {
139
- this.error.set(null);
140
- this.saving.set(false);
141
- if (this.purpose) {
142
- this.label = this.purpose.label;
143
- this.description = this.purpose.description;
144
- this.sampleOpening = this.purpose.sampleOpening;
145
- this.openingTemplate = this.purpose.openingTemplate;
146
- this.agentContextHint = this.purpose.agentContextHint ?? '';
147
- this.requiredFields = new Set(this.purpose.requiredFields);
148
- this.allowsCustomScript = this.purpose.allowsCustomScript;
149
- this.sortOrder = this.purpose.sortOrder;
150
- this.isActive = this.purpose.isActive;
151
- this.placeholders = this.purpose.placeholders?.length
152
- ? [...this.purpose.placeholders]
153
- : [...DEFAULT_PLACEHOLDERS];
154
- }
155
- else {
156
- this.label = '';
157
- this.description = '';
158
- this.sampleOpening = '';
159
- this.openingTemplate = 'Hi {{patientName}}, this is {{practiceName}}.';
160
- this.agentContextHint = '';
161
- this.requiredFields = new Set();
162
- this.allowsCustomScript = false;
163
- this.sortOrder = 1;
164
- this.isActive = true;
165
- this.placeholders = [...DEFAULT_PLACEHOLDERS];
166
- }
167
- }
168
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: OutboundPurposeFormModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
169
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: OutboundPurposeFormModalComponent, isStandalone: true, selector: "eds-outbound-purpose-form-modal", inputs: { open: "open", purpose: "purpose" }, outputs: { closed: "closed", saved: "saved" }, viewQueries: [{ propertyName: "templateInput", first: true, predicate: ["templateInput"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "@if (open) {\n <app-modal\n [title]=\"isEdit ? 'Edit outbound purpose' : 'New outbound purpose'\"\n subtitle=\"Configure dialer fields and AI opening script\"\n maxWidth=\"720px\"\n (closed)=\"close()\"\n >\n <form id=\"outbound-purpose-form\" class=\"flex flex-col gap-4\" (ngSubmit)=\"submit()\" novalidate autocomplete=\"off\">\n <div class=\"grid grid-cols-2 gap-3\">\n <div class=\"mb-sm col-span-full\">\n <label>Label<span required>*</span></label>\n <input class=\"form-input\" type=\"text\" [(ngModel)]=\"label\" name=\"label\" required autocomplete=\"off\" />\n </div>\n\n <div class=\"mb-sm col-span-full\">\n <label>Description</label>\n <input class=\"form-input\" type=\"text\" [(ngModel)]=\"description\" name=\"description\" autocomplete=\"off\" />\n </div>\n\n <div class=\"mb-sm col-span-full\">\n <label>Sample opening (plain preview, max 500)</label>\n <textarea\n class=\"form-textarea min-h-[72px]\"\n rows=\"3\"\n maxlength=\"500\"\n [(ngModel)]=\"sampleOpening\"\n name=\"sampleOpening\"\n autocomplete=\"off\"\n ></textarea>\n <span class=\"text-xs text-light\">{{ sampleOpening.length }}/500</span>\n </div>\n\n <div class=\"mb-sm col-span-full\">\n <label>Opening template<span required>*</span></label>\n <div class=\"mb-2 flex flex-wrap gap-2\">\n @for (chip of placeholders; track chip.token) {\n <button type=\"button\" class=\"cursor-pointer rounded-full border border-base bg-lighter px-3 py-1 text-xs hover:border-primary\" (click)=\"insertPlaceholder(chip.token)\">\n {{ chip.label }}\n </button>\n }\n </div>\n <textarea\n #templateInput\n class=\"form-textarea min-h-[72px]\"\n rows=\"4\"\n [(ngModel)]=\"openingTemplate\"\n name=\"openingTemplate\"\n required\n autocomplete=\"off\"\n ></textarea>\n </div>\n\n <div class=\"mb-sm col-span-full\">\n <label>Agent context hint</label>\n <textarea\n class=\"form-textarea min-h-[72px]\"\n rows=\"2\"\n [(ngModel)]=\"agentContextHint\"\n name=\"agentContextHint\"\n placeholder=\"Optional guidance for the AI after the opening\"\n autocomplete=\"off\"\n ></textarea>\n </div>\n\n <fieldset class=\"col-span-full flex flex-col gap-2\">\n <legend>Required fields</legend>\n <div class=\"grid grid-cols-2 gap-2\">\n @for (opt of fieldOptions; track opt.value) {\n <label class=\"flex items-center gap-2 text-[13px]\">\n <input\n type=\"checkbox\"\n [checked]=\"isRequiredSelected(opt.value)\"\n (change)=\"toggleRequired(opt.value)\"\n autocomplete=\"off\"\n />\n {{ opt.label }}\n </label>\n }\n </div>\n </fieldset>\n\n <label class=\"col-span-full flex items-center gap-2 text-[13px]\">\n <input type=\"checkbox\" [(ngModel)]=\"allowsCustomScript\" name=\"allowsCustomScript\" autocomplete=\"off\" />\n Allows custom script (dialer shows free-text script field)\n </label>\n\n <div class=\"mb-sm\">\n <label>Sort order</label>\n <input class=\"form-input\" type=\"number\" [(ngModel)]=\"sortOrder\" name=\"sortOrder\" min=\"0\" autocomplete=\"off\" />\n </div>\n\n @if (isEdit) {\n <label class=\"flex items-center gap-2 text-[13px]\">\n <input type=\"checkbox\" [(ngModel)]=\"isActive\" name=\"isActive\" autocomplete=\"off\" />\n Active\n </label>\n }\n </div>\n\n <section class=\"rounded-lg border border-base bg-lighter-2 p-3 shadow-sm\">\n <h3 class=\"fs-sm font-semibold text-light\">Live preview</h3>\n <p class=\"mt-2 whitespace-pre-wrap text-sm leading-normal\">{{ previewText }}</p>\n </section>\n\n @if (error()) {\n <p class=\"m-0 text-[13px] text-[#b91c1c]\" role=\"alert\">{{ error() }}</p>\n }\n </form>\n\n <div modalFooter class=\"border-t border-base bg-white px-6 py-4\">\n <div class=\"flex justify-end gap-2\">\n <ed-button variant=\"secondary\" outline size=\"sm\" (click$)=\"close()\" [disabled]=\"saving()\">\n Cancel\n </ed-button>\n <ed-button\n type=\"button\"\n variant=\"primary\"\n fill\n size=\"sm\"\n [disabled]=\"saving()\"\n (click$)=\"submit()\"\n >\n {{ saving() ? 'Saving\u2026' : isEdit ? 'Save changes' : 'Create purpose' }}\n </ed-button>\n </div>\n </div>\n </app-modal>\n}\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: ModalComponent, selector: "app-modal", inputs: ["title", "subtitle", "maxWidth"], outputs: ["closed"] }, { kind: "component", type: EdButtonComponent, selector: "ed-button", inputs: ["variant", "size", "disabled", "ghost", "outline", "subtle", "fill", "loading", "block", "elevated", "shape", "type", "href", "routerLink", "rel", "target", "download", "ariaLabel"], outputs: ["click$"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
170
- }
171
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: OutboundPurposeFormModalComponent, decorators: [{
172
- type: Component,
173
- args: [{ selector: 'eds-outbound-purpose-form-modal', imports: [FormsModule, ModalComponent, EdButtonComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (open) {\n <app-modal\n [title]=\"isEdit ? 'Edit outbound purpose' : 'New outbound purpose'\"\n subtitle=\"Configure dialer fields and AI opening script\"\n maxWidth=\"720px\"\n (closed)=\"close()\"\n >\n <form id=\"outbound-purpose-form\" class=\"flex flex-col gap-4\" (ngSubmit)=\"submit()\" novalidate autocomplete=\"off\">\n <div class=\"grid grid-cols-2 gap-3\">\n <div class=\"mb-sm col-span-full\">\n <label>Label<span required>*</span></label>\n <input class=\"form-input\" type=\"text\" [(ngModel)]=\"label\" name=\"label\" required autocomplete=\"off\" />\n </div>\n\n <div class=\"mb-sm col-span-full\">\n <label>Description</label>\n <input class=\"form-input\" type=\"text\" [(ngModel)]=\"description\" name=\"description\" autocomplete=\"off\" />\n </div>\n\n <div class=\"mb-sm col-span-full\">\n <label>Sample opening (plain preview, max 500)</label>\n <textarea\n class=\"form-textarea min-h-[72px]\"\n rows=\"3\"\n maxlength=\"500\"\n [(ngModel)]=\"sampleOpening\"\n name=\"sampleOpening\"\n autocomplete=\"off\"\n ></textarea>\n <span class=\"text-xs text-light\">{{ sampleOpening.length }}/500</span>\n </div>\n\n <div class=\"mb-sm col-span-full\">\n <label>Opening template<span required>*</span></label>\n <div class=\"mb-2 flex flex-wrap gap-2\">\n @for (chip of placeholders; track chip.token) {\n <button type=\"button\" class=\"cursor-pointer rounded-full border border-base bg-lighter px-3 py-1 text-xs hover:border-primary\" (click)=\"insertPlaceholder(chip.token)\">\n {{ chip.label }}\n </button>\n }\n </div>\n <textarea\n #templateInput\n class=\"form-textarea min-h-[72px]\"\n rows=\"4\"\n [(ngModel)]=\"openingTemplate\"\n name=\"openingTemplate\"\n required\n autocomplete=\"off\"\n ></textarea>\n </div>\n\n <div class=\"mb-sm col-span-full\">\n <label>Agent context hint</label>\n <textarea\n class=\"form-textarea min-h-[72px]\"\n rows=\"2\"\n [(ngModel)]=\"agentContextHint\"\n name=\"agentContextHint\"\n placeholder=\"Optional guidance for the AI after the opening\"\n autocomplete=\"off\"\n ></textarea>\n </div>\n\n <fieldset class=\"col-span-full flex flex-col gap-2\">\n <legend>Required fields</legend>\n <div class=\"grid grid-cols-2 gap-2\">\n @for (opt of fieldOptions; track opt.value) {\n <label class=\"flex items-center gap-2 text-[13px]\">\n <input\n type=\"checkbox\"\n [checked]=\"isRequiredSelected(opt.value)\"\n (change)=\"toggleRequired(opt.value)\"\n autocomplete=\"off\"\n />\n {{ opt.label }}\n </label>\n }\n </div>\n </fieldset>\n\n <label class=\"col-span-full flex items-center gap-2 text-[13px]\">\n <input type=\"checkbox\" [(ngModel)]=\"allowsCustomScript\" name=\"allowsCustomScript\" autocomplete=\"off\" />\n Allows custom script (dialer shows free-text script field)\n </label>\n\n <div class=\"mb-sm\">\n <label>Sort order</label>\n <input class=\"form-input\" type=\"number\" [(ngModel)]=\"sortOrder\" name=\"sortOrder\" min=\"0\" autocomplete=\"off\" />\n </div>\n\n @if (isEdit) {\n <label class=\"flex items-center gap-2 text-[13px]\">\n <input type=\"checkbox\" [(ngModel)]=\"isActive\" name=\"isActive\" autocomplete=\"off\" />\n Active\n </label>\n }\n </div>\n\n <section class=\"rounded-lg border border-base bg-lighter-2 p-3 shadow-sm\">\n <h3 class=\"fs-sm font-semibold text-light\">Live preview</h3>\n <p class=\"mt-2 whitespace-pre-wrap text-sm leading-normal\">{{ previewText }}</p>\n </section>\n\n @if (error()) {\n <p class=\"m-0 text-[13px] text-[#b91c1c]\" role=\"alert\">{{ error() }}</p>\n }\n </form>\n\n <div modalFooter class=\"border-t border-base bg-white px-6 py-4\">\n <div class=\"flex justify-end gap-2\">\n <ed-button variant=\"secondary\" outline size=\"sm\" (click$)=\"close()\" [disabled]=\"saving()\">\n Cancel\n </ed-button>\n <ed-button\n type=\"button\"\n variant=\"primary\"\n fill\n size=\"sm\"\n [disabled]=\"saving()\"\n (click$)=\"submit()\"\n >\n {{ saving() ? 'Saving\u2026' : isEdit ? 'Save changes' : 'Create purpose' }}\n </ed-button>\n </div>\n </div>\n </app-modal>\n}\n" }]
174
- }], propDecorators: { open: [{
175
- type: Input
176
- }], purpose: [{
177
- type: Input
178
- }], closed: [{
179
- type: Output
180
- }], saved: [{
181
- type: Output
182
- }], templateInput: [{
183
- type: ViewChild,
184
- args: ['templateInput']
185
- }] } });
186
-
187
- class OutboundPurposesPageComponent {
188
- constructor() {
189
- this.api = inject(AiReceptionistApiService);
190
- this.purposes = signal([]);
191
- this.loading = signal(true);
192
- this.skeletonRows = TABLE_SKELETON_ROWS;
193
- this.error = signal(null);
194
- this.modalOpen = signal(false);
195
- this.editing = signal(null);
196
- this.formatRequiredFields = formatRequiredFields;
197
- }
198
- ngOnInit() {
199
- this.load();
200
- }
201
- load() {
202
- this.loading.set(true);
203
- this.error.set(null);
204
- this.api.getOutboundPurposes(true).subscribe({
205
- next: ({ purposes }) => {
206
- this.purposes.set(purposes);
207
- this.loading.set(false);
208
- },
209
- error: () => {
210
- this.loading.set(false);
211
- this.error.set('Failed to load outbound purposes.');
212
- },
213
- });
214
- }
215
- openCreate() {
216
- this.editing.set(null);
217
- this.modalOpen.set(true);
218
- }
219
- openEdit(purpose) {
220
- this.editing.set(purpose);
221
- this.modalOpen.set(true);
222
- }
223
- closeModal() {
224
- this.modalOpen.set(false);
225
- this.editing.set(null);
226
- }
227
- onSaved() {
228
- this.load();
229
- }
230
- toggleActive(purpose, active) {
231
- this.api.updateOutboundPurpose(purpose.purposeId, { isActive: active }).subscribe({
232
- next: (updated) => {
233
- this.purposes.update((list) => list.map((p) => (p.purposeId === updated.purposeId ? updated : p)));
234
- },
235
- error: () => this.load(),
236
- });
237
- }
238
- deletePurpose(purpose) {
239
- if (purpose.isSystem) {
240
- this.toggleActive(purpose, false);
241
- return;
242
- }
243
- if (!confirm(`Delete "${purpose.label}"? This cannot be undone.`))
244
- return;
245
- this.api.deleteOutboundPurpose(purpose.purposeId).subscribe({
246
- next: () => this.load(),
247
- error: () => this.error.set('Failed to delete purpose.'),
248
- });
249
- }
250
- actionLabel(purpose) {
251
- return purpose.isSystem ? 'Deactivate' : 'Delete';
252
- }
253
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: OutboundPurposesPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
254
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: OutboundPurposesPageComponent, isStandalone: true, selector: "eds-outbound-purposes-page", host: { classAttribute: "block h-full min-h-0" }, ngImport: i0, template: "<div class=\"flex h-full min-h-0 flex-col overflow-hidden bg-lighter p-base outbound-purposes-page\">\n <header class=\"relative z-10 mb-base flex shrink-0 items-start justify-between gap-base bg-lighter\">\n <div>\n <a routerLink=\"../settings\" class=\"fs-sm text-light mb-2 inline-flex items-center gap-1 no-underline\">\n <ed-icon name=\"arrow_back\" [size]=\"16\" /> Settings\n </a>\n <h4>Outbound Call Purposes</h4>\n <p class=\"fs-sm text-light\">Templates that drive outbound dialer fields and AI opening scripts</p>\n </div>\n <ed-button variant=\"primary\" fill size=\"sm\" (click$)=\"openCreate()\">\n <ed-icon slot=\"prefix\" name=\"add\" [size]=\"16\" />\n New purpose\n </ed-button>\n </header>\n\n @if (error()) {\n <p class=\"fs-sm text-light text-red-700\" role=\"alert\">{{ error() }}</p>\n } @else {\n <article class=\"flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden rounded-md bg-white p-base\">\n <div class=\"eds-table-scroll min-h-0 min-w-0 flex-1\">\n <table class=\"table-default eds-sticky-table w-full\" aria-label=\"Outbound purposes\">\n <thead>\n <tr>\n <th class=\"bg-light\">Label</th>\n <th class=\"bg-light\">Description</th>\n <th class=\"bg-light\">Required fields</th>\n <th class=\"bg-light\">System</th>\n <th class=\"bg-light\">Active</th>\n <th class=\"bg-light\">Sort</th>\n <th class=\"bg-light\">Actions</th>\n </tr>\n </thead>\n @if (loading()) {\n <tbody aria-busy=\"true\">\n @for (_ of skeletonRows; track _) {\n <tr>\n <td><ed-skeleton class=\"h-3 w-32\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-3 w-48\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-3 w-40\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-5 w-16 !rounded-full\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-4 w-4 !rounded-sm\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-3 w-8\"></ed-skeleton></td>\n <td>\n <div class=\"flex gap-3\">\n <ed-skeleton class=\"h-3 w-10\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-12\"></ed-skeleton>\n </div>\n </td>\n </tr>\n }\n </tbody>\n } @else {\n <tbody>\n @for (p of purposes(); track p.purposeId) {\n <tr>\n <td>\n <span\n class=\"inline-block min-w-0 max-w-56 truncate fs-sm font-semibold text-dark\"\n [smartTooltip]=\"p.label\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ p.label }}</span>\n </td>\n <td>\n <span\n class=\"inline-block min-w-0 max-w-72 truncate fs-sm text-light\"\n [smartTooltip]=\"p.description || '\u2014'\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ p.description || '\u2014' }}</span>\n </td>\n <td>\n <span\n class=\"inline-block min-w-0 max-w-64 truncate fs-sm text-light\"\n [smartTooltip]=\"formatRequiredFields(p.requiredFields)\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ formatRequiredFields(p.requiredFields) }}</span>\n </td>\n <td>\n @if (p.isSystem) {\n <ed-badge-2 variant=\"primary\">System</ed-badge-2>\n } @else {\n <span class=\"fs-sm text-light\">\u2014</span>\n }\n </td>\n <td>\n <label>\n <input\n type=\"checkbox\"\n class=\"h-4 w-4\"\n [checked]=\"p.isActive\"\n (change)=\"toggleActive(p, $any($event.target).checked)\" autocomplete=\"off\" />\n </label>\n </td>\n <td class=\"font-['IBM_Plex_Mono'] fs-sm text-light\">{{ p.sortOrder }}</td>\n <td class=\"flex gap-3 whitespace-nowrap\">\n <button type=\"button\" class=\"text-primary fs-sm cursor-pointer border-none bg-transparent p-0\" (click)=\"openEdit(p)\">\n Edit\n </button>\n <button type=\"button\" class=\"text-primary fs-sm cursor-pointer border-none bg-transparent p-0\" (click)=\"deletePurpose(p)\">\n {{ actionLabel(p) }}\n </button>\n </td>\n </tr>\n } @empty {\n <tr class=\"empty-row\">\n <td colspan=\"7\" class=\"py-lg text-center fs-sm text-light\">No outbound purposes configured.</td>\n </tr>\n }\n </tbody>\n }\n </table>\n </div>\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", dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: IconComponent, selector: "ed-icon", inputs: ["name", "size", "color", "cssClass", "decorative", "ariaHidden", "ariaLabel", "title", "desc", "focusable", "tabIndex"] }, { kind: "component", type: OutboundPurposeFormModalComponent, selector: "eds-outbound-purpose-form-modal", inputs: ["open", "purpose"], outputs: ["closed", "saved"] }, { kind: "directive", type: SmartTooltipDirective, selector: "[smartTooltip]", inputs: ["smartTooltip", "tooltipAllowHtml", "tooltipTemplate", "tooltipTemplateContext", "tooltipPlacement", "tooltipTrigger", "tooltipDelayShow", "tooltipDelayHide", "tooltipOffset", "tooltipMaxWidth", "tooltipZIndex", "tooltipClass", "tooltipDisabled", "tooltipArrow", "tooltipHoverIntentMs", "tooltipHoverIntentRadius", "tooltipId", "tooltipRole", "tooltipAnimEnterMs", "tooltipAnimExitMs", "tooltipAnimEasing", "tooltipHoverable", "tooltipHandoffMs", "tooltipOpen", "tooltipOnlyWhenTruncated"] }, { kind: "component", type: EdSkeletonComponent, selector: "ed-skeleton", inputs: ["class"] }, { kind: "component", type: EdButtonComponent, selector: "ed-button", inputs: ["variant", "size", "disabled", "ghost", "outline", "subtle", "fill", "loading", "block", "elevated", "shape", "type", "href", "routerLink", "rel", "target", "download", "ariaLabel"], outputs: ["click$"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
255
- }
256
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: OutboundPurposesPageComponent, decorators: [{
257
- type: Component,
258
- args: [{ selector: 'eds-outbound-purposes-page', imports: [
259
- RouterLink,
260
- IconComponent,
261
- OutboundPurposeFormModalComponent,
262
- SmartTooltipDirective,
263
- EdSkeletonComponent,
264
- EdButtonComponent,
265
- ], changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'block h-full min-h-0' }, schemas: [CUSTOM_ELEMENTS_SCHEMA], template: "<div class=\"flex h-full min-h-0 flex-col overflow-hidden bg-lighter p-base outbound-purposes-page\">\n <header class=\"relative z-10 mb-base flex shrink-0 items-start justify-between gap-base bg-lighter\">\n <div>\n <a routerLink=\"../settings\" class=\"fs-sm text-light mb-2 inline-flex items-center gap-1 no-underline\">\n <ed-icon name=\"arrow_back\" [size]=\"16\" /> Settings\n </a>\n <h4>Outbound Call Purposes</h4>\n <p class=\"fs-sm text-light\">Templates that drive outbound dialer fields and AI opening scripts</p>\n </div>\n <ed-button variant=\"primary\" fill size=\"sm\" (click$)=\"openCreate()\">\n <ed-icon slot=\"prefix\" name=\"add\" [size]=\"16\" />\n New purpose\n </ed-button>\n </header>\n\n @if (error()) {\n <p class=\"fs-sm text-light text-red-700\" role=\"alert\">{{ error() }}</p>\n } @else {\n <article class=\"flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden rounded-md bg-white p-base\">\n <div class=\"eds-table-scroll min-h-0 min-w-0 flex-1\">\n <table class=\"table-default eds-sticky-table w-full\" aria-label=\"Outbound purposes\">\n <thead>\n <tr>\n <th class=\"bg-light\">Label</th>\n <th class=\"bg-light\">Description</th>\n <th class=\"bg-light\">Required fields</th>\n <th class=\"bg-light\">System</th>\n <th class=\"bg-light\">Active</th>\n <th class=\"bg-light\">Sort</th>\n <th class=\"bg-light\">Actions</th>\n </tr>\n </thead>\n @if (loading()) {\n <tbody aria-busy=\"true\">\n @for (_ of skeletonRows; track _) {\n <tr>\n <td><ed-skeleton class=\"h-3 w-32\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-3 w-48\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-3 w-40\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-5 w-16 !rounded-full\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-4 w-4 !rounded-sm\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-3 w-8\"></ed-skeleton></td>\n <td>\n <div class=\"flex gap-3\">\n <ed-skeleton class=\"h-3 w-10\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-12\"></ed-skeleton>\n </div>\n </td>\n </tr>\n }\n </tbody>\n } @else {\n <tbody>\n @for (p of purposes(); track p.purposeId) {\n <tr>\n <td>\n <span\n class=\"inline-block min-w-0 max-w-56 truncate fs-sm font-semibold text-dark\"\n [smartTooltip]=\"p.label\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ p.label }}</span>\n </td>\n <td>\n <span\n class=\"inline-block min-w-0 max-w-72 truncate fs-sm text-light\"\n [smartTooltip]=\"p.description || '\u2014'\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ p.description || '\u2014' }}</span>\n </td>\n <td>\n <span\n class=\"inline-block min-w-0 max-w-64 truncate fs-sm text-light\"\n [smartTooltip]=\"formatRequiredFields(p.requiredFields)\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ formatRequiredFields(p.requiredFields) }}</span>\n </td>\n <td>\n @if (p.isSystem) {\n <ed-badge-2 variant=\"primary\">System</ed-badge-2>\n } @else {\n <span class=\"fs-sm text-light\">\u2014</span>\n }\n </td>\n <td>\n <label>\n <input\n type=\"checkbox\"\n class=\"h-4 w-4\"\n [checked]=\"p.isActive\"\n (change)=\"toggleActive(p, $any($event.target).checked)\" autocomplete=\"off\" />\n </label>\n </td>\n <td class=\"font-['IBM_Plex_Mono'] fs-sm text-light\">{{ p.sortOrder }}</td>\n <td class=\"flex gap-3 whitespace-nowrap\">\n <button type=\"button\" class=\"text-primary fs-sm cursor-pointer border-none bg-transparent p-0\" (click)=\"openEdit(p)\">\n Edit\n </button>\n <button type=\"button\" class=\"text-primary fs-sm cursor-pointer border-none bg-transparent p-0\" (click)=\"deletePurpose(p)\">\n {{ actionLabel(p) }}\n </button>\n </td>\n </tr>\n } @empty {\n <tr class=\"empty-row\">\n <td colspan=\"7\" class=\"py-lg text-center fs-sm text-light\">No outbound purposes configured.</td>\n </tr>\n }\n </tbody>\n }\n </table>\n </div>\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" }]
266
- }] });
267
-
268
- export { OutboundPurposesPageComponent };
269
- //# sourceMappingURL=edvak99-voice-receptionist-widget-outbound-purposes-page.component-BkIHblSu.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"edvak99-voice-receptionist-widget-outbound-purposes-page.component-BkIHblSu.mjs","sources":["../../../src/lib/components/outbound-purpose-form-modal/outbound-purpose-form-modal.component.ts","../../../src/lib/components/outbound-purpose-form-modal/outbound-purpose-form-modal.component.html","../../../src/lib/pages/outbound-purposes-page/outbound-purposes-page.component.ts","../../../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 { EdButtonComponent } from '../../ui/ed-button.component';\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 { ModalComponent } from '../../shared/modal.component';\n\n@Component({\n selector: 'eds-outbound-purpose-form-modal',\n imports: [FormsModule, ModalComponent, EdButtonComponent],\n templateUrl: './outbound-purpose-form-modal.component.html',\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 id=\"outbound-purpose-form\" class=\"flex flex-col gap-4\" (ngSubmit)=\"submit()\" novalidate autocomplete=\"off\">\n <div class=\"grid grid-cols-2 gap-3\">\n <div class=\"mb-sm col-span-full\">\n <label>Label<span required>*</span></label>\n <input class=\"form-input\" type=\"text\" [(ngModel)]=\"label\" name=\"label\" required autocomplete=\"off\" />\n </div>\n\n <div class=\"mb-sm col-span-full\">\n <label>Description</label>\n <input class=\"form-input\" type=\"text\" [(ngModel)]=\"description\" name=\"description\" autocomplete=\"off\" />\n </div>\n\n <div class=\"mb-sm col-span-full\">\n <label>Sample opening (plain preview, max 500)</label>\n <textarea\n class=\"form-textarea min-h-[72px]\"\n rows=\"3\"\n maxlength=\"500\"\n [(ngModel)]=\"sampleOpening\"\n name=\"sampleOpening\"\n autocomplete=\"off\"\n ></textarea>\n <span class=\"text-xs text-light\">{{ sampleOpening.length }}/500</span>\n </div>\n\n <div class=\"mb-sm col-span-full\">\n <label>Opening template<span required>*</span></label>\n <div class=\"mb-2 flex flex-wrap gap-2\">\n @for (chip of placeholders; track chip.token) {\n <button type=\"button\" class=\"cursor-pointer rounded-full border border-base bg-lighter px-3 py-1 text-xs hover:border-primary\" (click)=\"insertPlaceholder(chip.token)\">\n {{ chip.label }}\n </button>\n }\n </div>\n <textarea\n #templateInput\n class=\"form-textarea min-h-[72px]\"\n rows=\"4\"\n [(ngModel)]=\"openingTemplate\"\n name=\"openingTemplate\"\n required\n autocomplete=\"off\"\n ></textarea>\n </div>\n\n <div class=\"mb-sm col-span-full\">\n <label>Agent context hint</label>\n <textarea\n class=\"form-textarea min-h-[72px]\"\n rows=\"2\"\n [(ngModel)]=\"agentContextHint\"\n name=\"agentContextHint\"\n placeholder=\"Optional guidance for the AI after the opening\"\n autocomplete=\"off\"\n ></textarea>\n </div>\n\n <fieldset class=\"col-span-full flex flex-col gap-2\">\n <legend>Required fields</legend>\n <div class=\"grid grid-cols-2 gap-2\">\n @for (opt of fieldOptions; track opt.value) {\n <label class=\"flex items-center gap-2 text-[13px]\">\n <input\n type=\"checkbox\"\n [checked]=\"isRequiredSelected(opt.value)\"\n (change)=\"toggleRequired(opt.value)\"\n autocomplete=\"off\"\n />\n {{ opt.label }}\n </label>\n }\n </div>\n </fieldset>\n\n <label class=\"col-span-full flex items-center gap-2 text-[13px]\">\n <input type=\"checkbox\" [(ngModel)]=\"allowsCustomScript\" name=\"allowsCustomScript\" autocomplete=\"off\" />\n Allows custom script (dialer shows free-text script field)\n </label>\n\n <div class=\"mb-sm\">\n <label>Sort order</label>\n <input class=\"form-input\" type=\"number\" [(ngModel)]=\"sortOrder\" name=\"sortOrder\" min=\"0\" autocomplete=\"off\" />\n </div>\n\n @if (isEdit) {\n <label class=\"flex items-center gap-2 text-[13px]\">\n <input type=\"checkbox\" [(ngModel)]=\"isActive\" name=\"isActive\" autocomplete=\"off\" />\n Active\n </label>\n }\n </div>\n\n <section class=\"rounded-lg border border-base bg-lighter-2 p-3 shadow-sm\">\n <h3 class=\"fs-sm font-semibold text-light\">Live preview</h3>\n <p class=\"mt-2 whitespace-pre-wrap text-sm leading-normal\">{{ previewText }}</p>\n </section>\n\n @if (error()) {\n <p class=\"m-0 text-[13px] text-[#b91c1c]\" role=\"alert\">{{ error() }}</p>\n }\n </form>\n\n <div modalFooter class=\"border-t border-base bg-white px-6 py-4\">\n <div class=\"flex justify-end gap-2\">\n <ed-button variant=\"secondary\" outline size=\"sm\" (click$)=\"close()\" [disabled]=\"saving()\">\n Cancel\n </ed-button>\n <ed-button\n type=\"button\"\n variant=\"primary\"\n fill\n size=\"sm\"\n [disabled]=\"saving()\"\n (click$)=\"submit()\"\n >\n {{ saving() ? 'Saving…' : isEdit ? 'Save changes' : 'Create purpose' }}\n </ed-button>\n </div>\n </div>\n </app-modal>\n}\n","import { ChangeDetectionStrategy, Component, CUSTOM_ELEMENTS_SCHEMA, 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 { EdButtonComponent } from '../../ui/ed-button.component';\nimport { EdSkeletonComponent } from '../../ui/ed-skeleton.component';\n\nimport { SmartTooltipDirective } from '../../shared/smart-tooltip.directive';\nimport { TABLE_SKELETON_ROWS } from '../../shared/table-skeleton.constants';\nimport { OutboundPurposeFormModalComponent } from '../../components/outbound-purpose-form-modal/outbound-purpose-form-modal.component';\nimport { IconComponent } from '../../ui/ed-icon.component';\n\n@Component({\n selector: 'eds-outbound-purposes-page',\n imports: [\n RouterLink,\n IconComponent,\n OutboundPurposeFormModalComponent,\n SmartTooltipDirective,\n EdSkeletonComponent,\n EdButtonComponent,\n ],\n templateUrl: './outbound-purposes-page.component.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: { class: 'block h-full min-h-0' },\n schemas: [CUSTOM_ELEMENTS_SCHEMA],\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 skeletonRows = TABLE_SKELETON_ROWS;\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=\"flex h-full min-h-0 flex-col overflow-hidden bg-lighter p-base outbound-purposes-page\">\n <header class=\"relative z-10 mb-base flex shrink-0 items-start justify-between gap-base bg-lighter\">\n <div>\n <a routerLink=\"../settings\" class=\"fs-sm text-light mb-2 inline-flex items-center gap-1 no-underline\">\n <ed-icon name=\"arrow_back\" [size]=\"16\" /> Settings\n </a>\n <h4>Outbound Call Purposes</h4>\n <p class=\"fs-sm text-light\">Templates that drive outbound dialer fields and AI opening scripts</p>\n </div>\n <ed-button variant=\"primary\" fill size=\"sm\" (click$)=\"openCreate()\">\n <ed-icon slot=\"prefix\" name=\"add\" [size]=\"16\" />\n New purpose\n </ed-button>\n </header>\n\n @if (error()) {\n <p class=\"fs-sm text-light text-red-700\" role=\"alert\">{{ error() }}</p>\n } @else {\n <article class=\"flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden rounded-md bg-white p-base\">\n <div class=\"eds-table-scroll min-h-0 min-w-0 flex-1\">\n <table class=\"table-default eds-sticky-table w-full\" aria-label=\"Outbound purposes\">\n <thead>\n <tr>\n <th class=\"bg-light\">Label</th>\n <th class=\"bg-light\">Description</th>\n <th class=\"bg-light\">Required fields</th>\n <th class=\"bg-light\">System</th>\n <th class=\"bg-light\">Active</th>\n <th class=\"bg-light\">Sort</th>\n <th class=\"bg-light\">Actions</th>\n </tr>\n </thead>\n @if (loading()) {\n <tbody aria-busy=\"true\">\n @for (_ of skeletonRows; track _) {\n <tr>\n <td><ed-skeleton class=\"h-3 w-32\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-3 w-48\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-3 w-40\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-5 w-16 !rounded-full\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-4 w-4 !rounded-sm\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-3 w-8\"></ed-skeleton></td>\n <td>\n <div class=\"flex gap-3\">\n <ed-skeleton class=\"h-3 w-10\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-12\"></ed-skeleton>\n </div>\n </td>\n </tr>\n }\n </tbody>\n } @else {\n <tbody>\n @for (p of purposes(); track p.purposeId) {\n <tr>\n <td>\n <span\n class=\"inline-block min-w-0 max-w-56 truncate fs-sm font-semibold text-dark\"\n [smartTooltip]=\"p.label\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ p.label }}</span>\n </td>\n <td>\n <span\n class=\"inline-block min-w-0 max-w-72 truncate fs-sm text-light\"\n [smartTooltip]=\"p.description || '—'\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ p.description || '—' }}</span>\n </td>\n <td>\n <span\n class=\"inline-block min-w-0 max-w-64 truncate fs-sm text-light\"\n [smartTooltip]=\"formatRequiredFields(p.requiredFields)\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ formatRequiredFields(p.requiredFields) }}</span>\n </td>\n <td>\n @if (p.isSystem) {\n <ed-badge-2 variant=\"primary\">System</ed-badge-2>\n } @else {\n <span class=\"fs-sm text-light\">—</span>\n }\n </td>\n <td>\n <label>\n <input\n type=\"checkbox\"\n class=\"h-4 w-4\"\n [checked]=\"p.isActive\"\n (change)=\"toggleActive(p, $any($event.target).checked)\" autocomplete=\"off\" />\n </label>\n </td>\n <td class=\"font-['IBM_Plex_Mono'] fs-sm text-light\">{{ p.sortOrder }}</td>\n <td class=\"flex gap-3 whitespace-nowrap\">\n <button type=\"button\" class=\"text-primary fs-sm cursor-pointer border-none bg-transparent p-0\" (click)=\"openEdit(p)\">\n Edit\n </button>\n <button type=\"button\" class=\"text-primary fs-sm cursor-pointer border-none bg-transparent p-0\" (click)=\"deletePurpose(p)\">\n {{ actionLabel(p) }}\n </button>\n </td>\n </tr>\n } @empty {\n <tr class=\"empty-row\">\n <td colspan=\"7\" class=\"py-lg text-center fs-sm text-light\">No outbound purposes configured.</td>\n </tr>\n }\n </tbody>\n }\n </table>\n </div>\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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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"edvak99-voice-receptionist-widget-task-detail-drawer.component-aDTKTV79.mjs","sources":["../../../src/lib/shared/copy-button.component.ts","../../../src/lib/utils/task.util.ts","../../../src/lib/components/task-detail-drawer/task-detail-drawer.component.ts","../../../src/lib/components/task-detail-drawer/task-detail-drawer.component.html"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n Input,\n inject,\n signal,\n} from '@angular/core';\n\nimport { ToastService } from './toast.service';\n\n@Component({\n selector: 'app-copy-btn',\n standalone: true,\n template: `\n @if (copyValue) {\n <button\n type=\"button\"\n class=\"inline-flex h-[22px] w-[22px] shrink-0 cursor-pointer items-center justify-center rounded border border-base bg-white p-0 text-light transition hover:border-dark hover:bg-lighter hover:text-primary focus-visible:outline focus-visible:outline-2 focus-visible:outline-primary focus-visible:outline-offset-1\"\n (click)=\"onCopy($event)\"\n [attr.aria-label]=\"ariaLabel\"\n [title]=\"copied() ? 'Copied' : 'Copy to clipboard'\"\n >\n @if (copied()) {\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n } @else {\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\" />\n <path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\" />\n </svg>\n }\n </button>\n }\n `,\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class CopyButtonComponent {\n /** Raw value to copy (full ID / phone / etc.) */\n @Input() value: string | null | undefined = '';\n /** Accessible label, e.g. \"patient ID\" */\n @Input() label = 'value';\n\n private readonly toast = inject(ToastService);\n\n protected readonly copied = signal(false);\n\n protected get copyValue(): string {\n const v = this.value?.trim();\n return v && v !== '—' ? v : '';\n }\n\n protected get ariaLabel(): string {\n return this.copied() ? 'Copied' : `Copy ${this.label}`;\n }\n\n async onCopy(event: MouseEvent): Promise<void> {\n event.stopPropagation();\n const text = this.copyValue;\n if (!text) return;\n\n try {\n await navigator.clipboard.writeText(text);\n this.copied.set(true);\n setTimeout(() => this.copied.set(false), 1500);\n } catch {\n this.toast.show('Could not copy — clipboard unavailable', 'error', 2500);\n }\n }\n}\n","import { BadgeTone } from '../ui/eds-badge.component';\nimport { TaskPriority, TaskSource, TaskStatus } from '../models/ai-receptionist.types';\n\nexport const TASK_TYPE_OPTIONS = [\n 'Refill request',\n 'Callback',\n 'Billing',\n 'Scheduling',\n 'Clinical',\n 'Other',\n] as const;\n\nexport function taskStatusLabel(status: TaskStatus): string {\n if (status === 'in_progress') return 'In progress';\n if (status === 'done') return 'Done';\n return 'Open';\n}\n\nexport function taskStatusTone(status: TaskStatus): BadgeTone {\n const map: Record<TaskStatus, BadgeTone> = {\n open: 'primary',\n in_progress: 'warning',\n done: 'success',\n };\n return map[status];\n}\n\nexport function taskPriorityTone(priority: TaskPriority): BadgeTone {\n return priority === 'urgent' ? 'danger' : 'light';\n}\n\nexport function taskPriorityLabel(priority: TaskPriority): string {\n return priority === 'urgent' ? 'Urgent' : 'Normal';\n}\n\nexport function taskSourceLabel(source: TaskSource): string {\n if (source === 'voice') return 'Voice';\n if (source === 'sync') return 'Sync';\n return 'Manual';\n}\n\nexport function taskTypeTone(type: string): BadgeTone {\n const key = type.toLowerCase();\n if (key.includes('refill')) return 'opened';\n if (key.includes('callback')) return 'primary';\n if (key.includes('billing')) return 'warning';\n return 'light';\n}\n\nexport function taskCallRoute(callId: string): string[] {\n return callId.startsWith('LC') ? ['../live', callId] : ['../history', callId];\n}\n","import { DatePipe } from '@angular/common';\nimport {\n ChangeDetectionStrategy,\n Component,\n CUSTOM_ELEMENTS_SCHEMA,\n input,\n output,\n} from '@angular/core';\nimport { RouterLink } from '@angular/router';\n\nimport { EdButtonComponent } from '../../ui/ed-button.component';\n\nimport { TaskItem, TaskStatus } from '../../models/ai-receptionist.types';\nimport { CopyButtonComponent } from '../../shared/copy-button.component';\nimport { ViewportPortalDirective } from '../../shared/viewport-portal.directive';\nimport { EdIconButtonComponent } from '../../ui/ed-icon-button.component';\nimport { IconComponent } from '../../ui/ed-icon.component';\nimport {\n taskCallRoute,\n taskPriorityLabel,\n taskPriorityTone,\n taskSourceLabel,\n taskStatusLabel,\n taskStatusTone,\n taskTypeTone,\n} from '../../utils/task.util';\n\n@Component({\n selector: 'eds-task-detail-drawer',\n imports: [\n DatePipe,\n RouterLink,\n CopyButtonComponent,\n EdButtonComponent,\n EdIconButtonComponent,\n IconComponent,\n ViewportPortalDirective,\n ],\n templateUrl: './task-detail-drawer.component.html',\n styleUrl: './task-detail-drawer.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n schemas: [CUSTOM_ELEMENTS_SCHEMA],\n})\nexport class TaskDetailDrawerComponent {\n readonly task = input.required<TaskItem>();\n\n readonly closed = output<void>();\n readonly statusChange = output<TaskStatus>();\n\n protected readonly taskStatusLabel = taskStatusLabel;\n protected readonly taskStatusTone = taskStatusTone;\n protected readonly taskPriorityLabel = taskPriorityLabel;\n protected readonly taskPriorityTone = taskPriorityTone;\n protected readonly taskSourceLabel = taskSourceLabel;\n protected readonly taskTypeTone = taskTypeTone;\n protected readonly taskCallRoute = taskCallRoute;\n\n protected assigneeInitials(): string {\n const name = this.task().assignee?.trim();\n if (!name || name === '—') return '?';\n const parts = name.split(/\\s+/).filter(Boolean);\n if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();\n return `${parts[0][0] ?? ''}${parts[parts.length - 1][0] ?? ''}`.toUpperCase();\n }\n\n protected close(): void {\n this.closed.emit();\n }\n\n protected markDone(): void {\n const t = this.task();\n this.statusChange.emit(t.status === 'done' ? 'open' : 'done');\n }\n\n protected onBackdropClick(event: MouseEvent): void {\n if (event.target === event.currentTarget) this.close();\n }\n}\n","<div\n edsViewportPortal\n class=\"eds-drawer-backdrop fixed left-0 top-0 z-[100100] flex h-[100vh] w-[100vw] justify-end\"\n (click)=\"onBackdropClick($event)\"\n role=\"presentation\"\n>\n <ed-drawer\n size=\"base\"\n class=\"slide-in-rtl ed-main-sidepanel h-full bg-[#f7f8fa]\"\n role=\"dialog\"\n aria-modal=\"true\"\n [attr.aria-label]=\"task().title\"\n >\n <ed-drawer-header class=\"gap-3 border-b border-zinc-200 bg-white px-4 py-3 shadow-none\">\n <ed-button\n class=\"mr-auto\"\n variant=\"primary\"\n fill\n size=\"sm\"\n (click$)=\"markDone()\"\n >\n <ed-icon slot=\"prefix\" name=\"check\" [size]=\"16\" />\n {{ task().status === 'done' ? 'Reopen task' : 'Mark as completed' }}\n </ed-button>\n <ed-icon-button\n name=\"close\"\n label=\"Close\"\n size=\"sm\"\n ghost\n (click$)=\"close()\"\n />\n </ed-drawer-header>\n\n <ed-drawer-body class=\"flex min-h-0 flex-1 flex-col gap-3 overflow-y-auto\">\n <section class=\"rounded-xl border border-zinc-200 bg-white p-4\">\n <h4>{{ task().title }}</h4>\n\n <div class=\"mt-4\">\n <h3 class=\"m-0 text-sm font-semibold text-zinc-800\">Description</h3>\n <p class=\"mt-2 mb-0 whitespace-pre-wrap text-sm leading-relaxed text-zinc-600\">\n {{ task().description || '—' }}\n </p>\n </div>\n\n <div class=\"mt-5 flex flex-wrap items-center gap-x-5 gap-y-3 border-t border-zinc-100 pt-4 text-sm\">\n <div class=\"inline-flex items-center gap-2 font-medium\" [class.text-red-600]=\"task().priority === 'urgent'\" [class.text-zinc-700]=\"task().priority !== 'urgent'\">\n <span\n class=\"h-2.5 w-2.5 shrink-0 rotate-45 rounded-sm\"\n [class.bg-red-600]=\"task().priority === 'urgent'\"\n [class.bg-amber-500]=\"task().priority !== 'urgent'\"\n aria-hidden=\"true\"\n ></span>\n {{ task().priority === 'urgent' ? 'High Priority' : taskPriorityLabel(task().priority) }}\n </div>\n\n <div class=\"inline-flex items-center gap-2 text-zinc-700\">\n <span class=\"inline-flex h-7 w-7 items-center justify-center rounded-full bg-teal-100 text-[11px] font-bold text-teal-800\">\n {{ assigneeInitials() }}\n </span>\n <span class=\"text-zinc-500\">{{ task().assignee || 'Unassigned' }}</span>\n </div>\n\n <div class=\"inline-flex items-center gap-1.5 text-zinc-500\">\n <ed-icon name=\"schedule\" [size]=\"16\" />\n Created: {{ task().created | date: 'MM-dd-yyyy' }}\n </div>\n </div>\n </section>\n\n <section class=\"rounded-xl border border-zinc-200 bg-white px-4 py-3\">\n <div class=\"flex items-center justify-between gap-3\">\n <span class=\"text-sm font-medium text-zinc-800\">Patient</span>\n <span class=\"text-sm text-zinc-600\">{{ task().patient || '—' }}</span>\n </div>\n </section>\n\n <section class=\"rounded-xl border border-zinc-200 bg-white px-4 py-3\">\n <div class=\"flex items-center justify-between gap-3\">\n <span class=\"text-sm font-medium text-zinc-800\">Status</span>\n <ed-badge-2 [attr.variant]=\"taskStatusTone(task().status)\">{{ taskStatusLabel(task().status) }}</ed-badge-2>\n </div>\n </section>\n\n <section class=\"rounded-xl border border-zinc-200 bg-white px-4 py-3\">\n <div class=\"flex items-center justify-between gap-3\">\n <span class=\"text-sm font-medium text-zinc-800\">Source</span>\n <span class=\"text-sm text-zinc-600\">{{ taskSourceLabel(task().source) }}</span>\n </div>\n </section>\n\n @if (task().callId) {\n <section class=\"rounded-xl border border-zinc-200 bg-white px-4 py-3\">\n <div class=\"flex items-center justify-between gap-3\">\n <span class=\"text-sm font-medium text-zinc-800\">Call</span>\n <a\n [routerLink]=\"taskCallRoute(task().callId!)\"\n class=\"text-sm font-medium text-blue-600 no-underline hover:underline\"\n >\n {{ task().callId }}\n </a>\n </div>\n </section>\n }\n\n @if (task().edvakTaskId || task().edvakStatus || task().medicationName || task().medicationId) {\n <section class=\"rounded-xl border border-zinc-200 bg-white p-4\">\n <h3 class=\"m-0 mb-3 text-sm font-semibold text-zinc-800\">Edvak / refill details</h3>\n <dl class=\"m-0 grid grid-cols-2 gap-4\">\n @if (task().edvakTaskId) {\n <div>\n <dt class=\"fs-sm font-semibold text-light mb-1\">Edvak task ID</dt>\n <dd class=\"inline-flex items-center gap-2 text-sm\">\n <code class=\"rounded bg-zinc-100 px-2 py-1 font-mono text-xs\">{{ task().edvakTaskId }}</code>\n <app-copy-btn [value]=\"task().edvakTaskId\" label=\"Edvak task ID\" />\n </dd>\n </div>\n }\n @if (task().edvakStatus) {\n <div>\n <dt class=\"fs-sm font-semibold text-light mb-1\">Edvak status</dt>\n <dd class=\"m-0 text-sm\"><ed-badge-2 variant=\"primary\">{{ task().edvakStatus }}</ed-badge-2></dd>\n </div>\n }\n @if (task().medicationName) {\n <div>\n <dt class=\"fs-sm font-semibold text-light mb-1\">Medication</dt>\n <dd class=\"m-0 text-sm text-zinc-700\">{{ task().medicationName }}</dd>\n </div>\n }\n @if (task().medicationId) {\n <div>\n <dt class=\"fs-sm font-semibold text-light mb-1\">Medication ID</dt>\n <dd class=\"inline-flex items-center gap-2 text-sm\">\n <code class=\"rounded bg-zinc-100 px-2 py-1 font-mono text-xs\">{{ task().medicationId }}</code>\n <app-copy-btn [value]=\"task().medicationId\" label=\"medication ID\" />\n </dd>\n </div>\n }\n </dl>\n </section>\n }\n </ed-drawer-body>\n </ed-drawer>\n</div>\n"],"names":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"edvak99-voice-receptionist-widget-tasks-page.component-Dj1nWx6V.mjs","sources":["../../../src/lib/pages/tasks-page/tasks-page.component.ts","../../../src/lib/pages/tasks-page/tasks-page.component.html"],"sourcesContent":["import { DatePipe } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, CUSTOM_ELEMENTS_SCHEMA, computed, inject, OnInit, signal } from '@angular/core';\nimport { ActivatedRoute, RouterLink } from '@angular/router';\n\nimport { EdButtonComponent } from '../../ui/ed-button.component';\nimport { EdSkeletonComponent } from '../../ui/ed-skeleton.component';\n\nimport { TaskDetailDrawerComponent } from '../../components/task-detail-drawer/task-detail-drawer.component';\n\nimport { SmartTooltipDirective } from '../../shared/smart-tooltip.directive';\nimport { TABLE_SKELETON_ROWS } from '../../shared/table-skeleton.constants';\nimport {\n TaskFilters,\n TaskItem,\n TaskSource,\n TaskStatus,\n} from '../../models/ai-receptionist.types';\nimport { DEFAULT_PAGE_SIZE, totalPages as calcTotalPages } from '../../models/pagination';\nimport { AiReceptionistApiService } from '../../services/ai-receptionist-api.service';\nimport {\n TASK_TYPE_OPTIONS,\n taskCallRoute,\n taskPriorityTone,\n taskSourceLabel,\n taskStatusLabel,\n taskStatusTone,\n taskTypeTone,\n} from '../../utils/task.util';\n\n@Component({\n selector: 'eds-tasks-page',\n imports: [\n DatePipe,\n RouterLink,\n EdButtonComponent,\n TaskDetailDrawerComponent,\n SmartTooltipDirective,\n EdSkeletonComponent,\n ],\n templateUrl: './tasks-page.component.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: { class: 'block h-full min-h-0' },\n schemas: [CUSTOM_ELEMENTS_SCHEMA],\n})\nexport class TasksPageComponent implements OnInit {\n private readonly api = inject(AiReceptionistApiService);\n private readonly route = inject(ActivatedRoute);\n\n protected readonly pageSize = DEFAULT_PAGE_SIZE;\n protected readonly tasks = signal<TaskItem[]>([]);\n protected readonly total = signal(0);\n protected readonly page = signal(1);\n protected readonly loading = signal(true);\n protected readonly skeletonRows = TABLE_SKELETON_ROWS;\n protected readonly selectedTask = signal<TaskItem | null>(null);\n\n /** Default to Open so staff see actionable work; Done tab for completed. */\n protected readonly statusFilter = signal<'' | TaskStatus>('open');\n protected readonly typeFilter = signal('');\n protected readonly sourceFilter = signal<'' | TaskSource>('');\n protected readonly callIdFilter = signal('');\n\n protected readonly statusTabs: { id: '' | TaskStatus; label: string }[] = [\n { id: 'open', label: 'Open' },\n { id: 'in_progress', label: 'In progress' },\n { id: 'done', label: 'Done' },\n { id: '', label: 'All' },\n ];\n\n protected readonly typeOptions = TASK_TYPE_OPTIONS;\n protected readonly taskStatusLabel = taskStatusLabel;\n protected readonly taskStatusTone = taskStatusTone;\n protected readonly taskPriorityTone = taskPriorityTone;\n protected readonly taskSourceLabel = taskSourceLabel;\n protected readonly taskTypeTone = taskTypeTone;\n protected readonly taskCallRoute = taskCallRoute;\n\n protected readonly hasActiveFilters = computed(\n () =>\n !!this.typeFilter() ||\n !!this.sourceFilter() ||\n !!this.callIdFilter(),\n );\n\n ngOnInit(): void {\n const callId = this.route.snapshot.queryParamMap.get('callId') ?? '';\n if (callId) this.callIdFilter.set(callId);\n this.load();\n }\n\n protected setStatusFilter(value: string): void {\n this.statusFilter.set(value as '' | TaskStatus);\n this.page.set(1);\n this.load();\n }\n\n protected setTypeFilter(value: string): void {\n this.typeFilter.set(value);\n this.page.set(1);\n this.load();\n }\n\n protected setSourceFilter(value: string): void {\n this.sourceFilter.set(value as '' | TaskSource);\n this.page.set(1);\n this.load();\n }\n\n protected setCallIdFilter(value: string): void {\n this.callIdFilter.set(value);\n this.page.set(1);\n this.load();\n }\n\n protected clearFilters(): void {\n this.statusFilter.set('open');\n this.typeFilter.set('');\n this.sourceFilter.set('');\n this.callIdFilter.set('');\n this.page.set(1);\n this.load();\n }\n\n protected openTask(task: TaskItem): void {\n this.selectedTask.set(task);\n }\n\n protected closeDrawer(): void {\n this.selectedTask.set(null);\n }\n\n protected onStatusChange(status: TaskStatus): void {\n const task = this.selectedTask();\n if (!task) return;\n this.api.patchTask(task.id, status).subscribe(({ data }) => {\n if (data) {\n this.selectedTask.set(data);\n // Refresh list so Open/Done tabs stay accurate after status change.\n this.load();\n }\n });\n }\n\n protected totalPages(): number {\n return calcTotalPages(this.total(), DEFAULT_PAGE_SIZE);\n }\n\n protected prevPage(): void {\n if (this.page() <= 1) return;\n this.page.update((p) => p - 1);\n this.load();\n }\n\n protected nextPage(): void {\n if (this.page() >= this.totalPages()) return;\n this.page.update((p) => p + 1);\n this.load();\n }\n\n private load(): void {\n this.loading.set(true);\n const filters: TaskFilters = {\n page: this.page(),\n limit: DEFAULT_PAGE_SIZE,\n };\n if (this.statusFilter()) filters.status = this.statusFilter() as TaskStatus;\n if (this.typeFilter()) filters.type = this.typeFilter();\n if (this.sourceFilter()) filters.source = this.sourceFilter() as TaskSource;\n if (this.callIdFilter().trim()) filters.callId = this.callIdFilter().trim();\n\n this.api.getTasks(filters).subscribe({\n next: ({ items, total, page }) => {\n this.tasks.set(items);\n this.total.set(total);\n this.page.set(page);\n this.loading.set(false);\n },\n error: () => this.loading.set(false),\n });\n }\n}\n","<div class=\"flex h-full min-h-0 flex-col overflow-hidden bg-lighter p-base tasks-page\">\n <header class=\"relative z-10 mb-base flex shrink-0 items-start justify-between gap-base bg-lighter\">\n <div>\n <h4>Tasks & follow-ups</h4>\n <p class=\"fs-sm text-light\">Action items from calls — all types, not just refills</p>\n </div>\n </header>\n\n <nav class=\"mb-4 flex flex-wrap gap-2\" aria-label=\"Task status\">\n @for (tab of statusTabs; track tab.id) {\n <button\n type=\"button\"\n [class]=\"\n statusFilter() === tab.id\n ? 'cursor-pointer rounded-full border-none bg-blue-50 px-4 py-2 text-sm font-medium text-blue-600 transition-colors'\n : 'cursor-pointer rounded-full border-none bg-transparent px-4 py-2 text-sm font-medium text-zinc-500 transition-colors hover:bg-white hover:text-zinc-700'\n \"\n (click)=\"setStatusFilter(tab.id)\"\n >\n {{ tab.label }}\n </button>\n }\n </nav>\n\n <section class=\"flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden rounded-lg border border-base bg-white shadow-sm\">\n <div class=\"flex flex-wrap items-end gap-4 border-b border-zinc-200 px-6 py-4 max-[920px]:px-4 max-[920px]:py-4\">\n <div class=\"mb-sm\">\n <label for=\"task-type\">Type</label>\n <select\n id=\"task-type\"\n class=\"form-select min-w-36\"\n [value]=\"typeFilter()\"\n (change)=\"setTypeFilter($any($event.target).value)\"\n autocomplete=\"off\"\n >\n <option value=\"\">All types</option>\n @for (t of typeOptions; track t) {\n <option [value]=\"t\">{{ t }}</option>\n }\n </select>\n </div>\n <div class=\"mb-sm\">\n <label for=\"task-source\">Source</label>\n <select\n id=\"task-source\"\n class=\"form-select min-w-36\"\n [value]=\"sourceFilter()\"\n (change)=\"setSourceFilter($any($event.target).value)\"\n autocomplete=\"off\"\n >\n <option value=\"\">All sources</option>\n <option value=\"voice\">Voice</option>\n <option value=\"sync\">Sync</option>\n <option value=\"manual\">Manual</option>\n </select>\n </div>\n <div class=\"mb-sm\">\n <label for=\"task-call\">Call ID</label>\n <input\n id=\"task-call\"\n class=\"form-input\"\n type=\"text\"\n [value]=\"callIdFilter()\"\n placeholder=\"Filter by call\"\n (change)=\"setCallIdFilter($any($event.target).value)\"\n autocomplete=\"off\"\n />\n </div>\n @if (hasActiveFilters()) {\n <button\n type=\"button\"\n class=\"cursor-pointer border-none bg-transparent p-0 text-sm font-medium text-blue-600 hover:underline\"\n (click)=\"clearFilters()\"\n >\n Clear filters\n </button>\n }\n </div>\n\n <div class=\"eds-table-scroll min-h-0 min-w-0 flex-1\">\n <table class=\"table-default eds-sticky-table min-w-3xl w-full\">\n <thead>\n <tr>\n <th>Created</th>\n <th>Title</th>\n <th>Type</th>\n <th>Patient</th>\n <th>Priority</th>\n <th>Status</th>\n <th>Source</th>\n <th>Call</th>\n </tr>\n </thead>\n @if (loading()) {\n <tbody aria-busy=\"true\">\n @for (_ of skeletonRows; track _) {\n <tr>\n <td><ed-skeleton class=\"h-3 w-24\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-3 w-48\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-5 w-20 !rounded-full\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-3 w-28\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-5 w-16 !rounded-full\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-5 w-20 !rounded-full\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-3 w-16\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-3 w-20\"></ed-skeleton></td>\n </tr>\n }\n </tbody>\n } @else {\n <tbody>\n @for (task of tasks(); track task.id) {\n <tr tabindex=\"0\" (click)=\"openTask(task)\" (keyup.enter)=\"openTask(task)\">\n <td class=\"fs-sm text-light\">{{ task.created | date: 'MM/dd/yy, h:mm a' }}</td>\n <td>\n <span\n class=\"inline-block min-w-0 max-w-72 truncate font-medium text-dark\"\n [smartTooltip]=\"task.title\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ task.title }}</span>\n </td>\n <td><ed-badge-2 [attr.variant]=\"taskTypeTone(task.type)\">{{ task.type }}</ed-badge-2></td>\n <td>\n <span\n class=\"inline-block min-w-0 max-w-56 truncate\"\n [smartTooltip]=\"task.patient\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ task.patient }}</span>\n </td>\n <td>\n <ed-badge-2 [attr.variant]=\"taskPriorityTone(task.priority)\">\n {{ task.priority === 'urgent' ? 'Urgent' : 'Normal' }}\n </ed-badge-2>\n </td>\n <td><ed-badge-2 [attr.variant]=\"taskStatusTone(task.status)\">{{ taskStatusLabel(task.status) }}</ed-badge-2></td>\n <td class=\"fs-sm text-light\">{{ taskSourceLabel(task.source) }}</td>\n <td (click)=\"$event.stopPropagation()\">\n @if (task.callId) {\n <a\n [routerLink]=\"taskCallRoute(task.callId)\"\n class=\"text-sm font-medium text-blue-600 no-underline hover:underline\"\n >{{ task.callId }}</a>\n } @else {\n <span class=\"text-zinc-500\">—</span>\n }\n </td>\n </tr>\n } @empty {\n <tr>\n <td colspan=\"8\" class=\"fs-sm text-light p-8 text-center\">No tasks match these filters.</td>\n </tr>\n }\n </tbody>\n }\n </table>\n </div>\n\n <footer class=\"flex items-center justify-between border-t border-zinc-200 px-6 py-4 text-sm text-zinc-500\">\n <span>Page {{ page() }} of {{ totalPages() }} · {{ total() }} total</span>\n <div class=\"flex gap-2\">\n <ed-button variant=\"secondary\" outline size=\"sm\" [disabled]=\"page() <= 1\" (click$)=\"prevPage()\">Previous</ed-button>\n <ed-button variant=\"secondary\" outline size=\"sm\" [disabled]=\"page() >= totalPages()\" (click$)=\"nextPage()\">Next</ed-button>\n </div>\n </footer>\n </section>\n</div>\n\n@if (selectedTask(); as task) {\n <eds-task-detail-drawer\n [task]=\"task\"\n (closed)=\"closeDrawer()\"\n (statusChange)=\"onStatusChange($event)\"\n />\n}\n"],"names":["calcTotalPages"],"mappings":";;;;;;;;;MA4Ca,kBAAkB,CAAA;AAf/B,IAAA,WAAA,GAAA;AAgBmB,QAAA,IAAA,CAAA,GAAG,GAAG,MAAM,CAAC,wBAAwB,CAAC;AACtC,QAAA,IAAA,CAAA,KAAK,GAAG,MAAM,CAAC,cAAc,CAAC;QAE5B,IAAA,CAAA,QAAQ,GAAG,iBAAiB;AAC5B,QAAA,IAAA,CAAA,KAAK,GAAG,MAAM,CAAa,EAAE,CAAC;AAC9B,QAAA,IAAA,CAAA,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC;AACjB,QAAA,IAAA,CAAA,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC;AAChB,QAAA,IAAA,CAAA,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC;QACtB,IAAA,CAAA,YAAY,GAAG,mBAAmB;AAClC,QAAA,IAAA,CAAA,YAAY,GAAG,MAAM,CAAkB,IAAI,CAAC;;AAG5C,QAAA,IAAA,CAAA,YAAY,GAAG,MAAM,CAAkB,MAAM,CAAC;AAC9C,QAAA,IAAA,CAAA,UAAU,GAAG,MAAM,CAAC,EAAE,CAAC;AACvB,QAAA,IAAA,CAAA,YAAY,GAAG,MAAM,CAAkB,EAAE,CAAC;AAC1C,QAAA,IAAA,CAAA,YAAY,GAAG,MAAM,CAAC,EAAE,CAAC;AAEzB,QAAA,IAAA,CAAA,UAAU,GAA6C;AACxE,YAAA,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE;AAC7B,YAAA,EAAE,EAAE,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,EAAE;AAC3C,YAAA,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE;AAC7B,YAAA,EAAE,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE;SACzB;QAEkB,IAAA,CAAA,WAAW,GAAG,iBAAiB;QAC/B,IAAA,CAAA,eAAe,GAAG,eAAe;QACjC,IAAA,CAAA,cAAc,GAAG,cAAc;QAC/B,IAAA,CAAA,gBAAgB,GAAG,gBAAgB;QACnC,IAAA,CAAA,eAAe,GAAG,eAAe;QACjC,IAAA,CAAA,YAAY,GAAG,YAAY;QAC3B,IAAA,CAAA,aAAa,GAAG,aAAa;QAE7B,IAAA,CAAA,gBAAgB,GAAG,QAAQ,CAC5C,MACE,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE;AACnB,YAAA,CAAC,CAAC,IAAI,CAAC,YAAY,EAAE;AACrB,YAAA,CAAC,CAAC,IAAI,CAAC,YAAY,EAAE,CACxB;AAkGF,IAAA;IAhGC,QAAQ,GAAA;AACN,QAAA,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE;AACpE,QAAA,IAAI,MAAM;AAAE,YAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC;QACzC,IAAI,CAAC,IAAI,EAAE;IACb;AAEU,IAAA,eAAe,CAAC,KAAa,EAAA;AACrC,QAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,KAAwB,CAAC;AAC/C,QAAA,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QAChB,IAAI,CAAC,IAAI,EAAE;IACb;AAEU,IAAA,aAAa,CAAC,KAAa,EAAA;AACnC,QAAA,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC;AAC1B,QAAA,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QAChB,IAAI,CAAC,IAAI,EAAE;IACb;AAEU,IAAA,eAAe,CAAC,KAAa,EAAA;AACrC,QAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,KAAwB,CAAC;AAC/C,QAAA,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QAChB,IAAI,CAAC,IAAI,EAAE;IACb;AAEU,IAAA,eAAe,CAAC,KAAa,EAAA;AACrC,QAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC;AAC5B,QAAA,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QAChB,IAAI,CAAC,IAAI,EAAE;IACb;IAEU,YAAY,GAAA;AACpB,QAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC;AAC7B,QAAA,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;AACvB,QAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC;AACzB,QAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC;AACzB,QAAA,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QAChB,IAAI,CAAC,IAAI,EAAE;IACb;AAEU,IAAA,QAAQ,CAAC,IAAc,EAAA;AAC/B,QAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC;IAC7B;IAEU,WAAW,GAAA;AACnB,QAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC;IAC7B;AAEU,IAAA,cAAc,CAAC,MAAkB,EAAA;AACzC,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,YAAY,EAAE;AAChC,QAAA,IAAI,CAAC,IAAI;YAAE;AACX,QAAA,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,KAAI;YACzD,IAAI,IAAI,EAAE;AACR,gBAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC;;gBAE3B,IAAI,CAAC,IAAI,EAAE;YACb;AACF,QAAA,CAAC,CAAC;IACJ;IAEU,UAAU,GAAA;QAClB,OAAOA,UAAc,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,iBAAiB,CAAC;IACxD;IAEU,QAAQ,GAAA;AAChB,QAAA,IAAI,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC;YAAE;AACtB,QAAA,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC9B,IAAI,CAAC,IAAI,EAAE;IACb;IAEU,QAAQ,GAAA;QAChB,IAAI,IAAI,CAAC,IAAI,EAAE,IAAI,IAAI,CAAC,UAAU,EAAE;YAAE;AACtC,QAAA,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC9B,IAAI,CAAC,IAAI,EAAE;IACb;IAEQ,IAAI,GAAA;AACV,QAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;AACtB,QAAA,MAAM,OAAO,GAAgB;AAC3B,YAAA,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE;AACjB,YAAA,KAAK,EAAE,iBAAiB;SACzB;QACD,IAAI,IAAI,CAAC,YAAY,EAAE;AAAE,YAAA,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,YAAY,EAAgB;QAC3E,IAAI,IAAI,CAAC,UAAU,EAAE;AAAE,YAAA,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,UAAU,EAAE;QACvD,IAAI,IAAI,CAAC,YAAY,EAAE;AAAE,YAAA,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,YAAY,EAAgB;AAC3E,QAAA,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC,IAAI,EAAE;YAAE,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC,IAAI,EAAE;QAE3E,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC;YACnC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,KAAI;AAC/B,gBAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC;AACrB,gBAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC;AACrB,gBAAA,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;AACnB,gBAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;YACzB,CAAC;YACD,KAAK,EAAE,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;AACrC,SAAA,CAAC;IACJ;+GAvIW,kBAAkB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;AAAlB,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,kBAAkB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,gBAAA,EAAA,IAAA,EAAA,EAAA,cAAA,EAAA,sBAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EC5C/B,ulOA6KA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,ED7II,QAAQ,EAAA,IAAA,EAAA,MAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACR,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,SAAA,EAAA,MAAA,EAAA,UAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,MAAA,EAAA,SAAA,EAAA,OAAA,EAAA,UAAA,EAAA,OAAA,EAAA,MAAA,EAAA,MAAA,EAAA,YAAA,EAAA,KAAA,EAAA,QAAA,EAAA,UAAA,EAAA,WAAA,CAAA,EAAA,OAAA,EAAA,CAAA,QAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACjB,yBAAyB,EAAA,QAAA,EAAA,wBAAA,EAAA,MAAA,EAAA,CAAA,MAAA,CAAA,EAAA,OAAA,EAAA,CAAA,QAAA,EAAA,cAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACzB,qBAAqB,+iBACrB,mBAAmB,EAAA,QAAA,EAAA,aAAA,EAAA,MAAA,EAAA,CAAA,OAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA,CAAA;;4FAOV,kBAAkB,EAAA,UAAA,EAAA,CAAA;kBAf9B,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,gBAAgB,EAAA,OAAA,EACjB;wBACP,QAAQ;wBACR,UAAU;wBACV,iBAAiB;wBACjB,yBAAyB;wBACzB,qBAAqB;wBACrB,mBAAmB;AACpB,qBAAA,EAAA,eAAA,EAEgB,uBAAuB,CAAC,MAAM,EAAA,IAAA,EACzC,EAAE,KAAK,EAAE,sBAAsB,EAAE,EAAA,OAAA,EAC9B,CAAC,sBAAsB,CAAC,EAAA,QAAA,EAAA,ulOAAA,EAAA;;;;;"}