@edvak99/voice-receptionist-widget 1.1.3 → 1.1.4
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/fesm2022/edvak99-voice-receptionist-widget-activities-page.component-DT9UKvQO.mjs +307 -0
- package/fesm2022/edvak99-voice-receptionist-widget-activities-page.component-DT9UKvQO.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-Dn0GrZ6_.mjs → edvak99-voice-receptionist-widget-ai-receptionist-api.service-48cifVPF.mjs} +1275 -561
- package/fesm2022/edvak99-voice-receptionist-widget-ai-receptionist-api.service-48cifVPF.mjs.map +1 -0
- package/fesm2022/edvak99-voice-receptionist-widget-analytics-page.component-C5inEHJw.mjs +278 -0
- package/fesm2022/edvak99-voice-receptionist-widget-analytics-page.component-C5inEHJw.mjs.map +1 -0
- package/fesm2022/edvak99-voice-receptionist-widget-call-history-detail-page.component-sYhM20CE.mjs +418 -0
- package/fesm2022/edvak99-voice-receptionist-widget-call-history-detail-page.component-sYhM20CE.mjs.map +1 -0
- package/fesm2022/edvak99-voice-receptionist-widget-call-history-page.component-DpwajEOE.mjs +194 -0
- package/fesm2022/edvak99-voice-receptionist-widget-call-history-page.component-DpwajEOE.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-call-recording-player.component-B8_qp7Fe.mjs → edvak99-voice-receptionist-widget-call-recording-player.component-CgkRcFOl.mjs} +3 -2
- package/fesm2022/{edvak99-voice-receptionist-widget-call-recording-player.component-B8_qp7Fe.mjs.map → edvak99-voice-receptionist-widget-call-recording-player.component-CgkRcFOl.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-call-review.service-Cj2XTeK4.mjs → edvak99-voice-receptionist-widget-call-review.service-CIMcjGKX.mjs} +2 -2
- package/fesm2022/{edvak99-voice-receptionist-widget-call-review.service-Cj2XTeK4.mjs.map → edvak99-voice-receptionist-widget-call-review.service-CIMcjGKX.mjs.map} +1 -1
- package/fesm2022/edvak99-voice-receptionist-widget-call-review.util-Deh3jPgo.mjs +21 -0
- package/fesm2022/edvak99-voice-receptionist-widget-call-review.util-Deh3jPgo.mjs.map +1 -0
- package/fesm2022/edvak99-voice-receptionist-widget-dashboard-page.component-CxbO0eDS.mjs +440 -0
- package/fesm2022/edvak99-voice-receptionist-widget-dashboard-page.component-CxbO0eDS.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-eds-elapsed.pipe-BgLsnq6A.mjs → edvak99-voice-receptionist-widget-dashboard-socket.service-BX91r74O.mjs} +5 -21
- package/fesm2022/edvak99-voice-receptionist-widget-dashboard-socket.service-BX91r74O.mjs.map +1 -0
- package/fesm2022/edvak99-voice-receptionist-widget-eds-avatar.component-CWRiJGfv.mjs +38 -0
- package/fesm2022/edvak99-voice-receptionist-widget-eds-avatar.component-CWRiJGfv.mjs.map +1 -0
- package/fesm2022/edvak99-voice-receptionist-widget-eds-button.component-Bg5T5BN8.mjs +27 -0
- package/fesm2022/edvak99-voice-receptionist-widget-eds-button.component-Bg5T5BN8.mjs.map +1 -0
- package/fesm2022/edvak99-voice-receptionist-widget-eds-elapsed.pipe-BFCiJOT3.mjs +22 -0
- package/fesm2022/edvak99-voice-receptionist-widget-eds-elapsed.pipe-BFCiJOT3.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-live-calls-list.service-0kGWO6sh.mjs → edvak99-voice-receptionist-widget-eds-pulse-dot.component-BPY6xN7C.mjs} +15 -5
- package/fesm2022/edvak99-voice-receptionist-widget-eds-pulse-dot.component-BPY6xN7C.mjs.map +1 -0
- package/fesm2022/edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-BsBQIS_f.mjs +203 -0
- package/fesm2022/edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-BsBQIS_f.mjs.map +1 -0
- package/fesm2022/edvak99-voice-receptionist-widget-live-calls-page.component-CaSDMxpV.mjs +81 -0
- package/fesm2022/edvak99-voice-receptionist-widget-live-calls-page.component-CaSDMxpV.mjs.map +1 -0
- package/fesm2022/edvak99-voice-receptionist-widget-live-monitor-page.component-Cy3ND-c-.mjs +1070 -0
- package/fesm2022/edvak99-voice-receptionist-widget-live-monitor-page.component-Cy3ND-c-.mjs.map +1 -0
- package/fesm2022/edvak99-voice-receptionist-widget-modal.component-COfi7biN.mjs +48 -0
- package/fesm2022/edvak99-voice-receptionist-widget-modal.component-COfi7biN.mjs.map +1 -0
- package/fesm2022/edvak99-voice-receptionist-widget-outbound-purpose.util-Bdh4QfFe.mjs +127 -0
- package/fesm2022/edvak99-voice-receptionist-widget-outbound-purpose.util-Bdh4QfFe.mjs.map +1 -0
- package/fesm2022/edvak99-voice-receptionist-widget-outbound-purposes-page.component-fHVzpiVk.mjs +268 -0
- package/fesm2022/edvak99-voice-receptionist-widget-outbound-purposes-page.component-fHVzpiVk.mjs.map +1 -0
- package/fesm2022/edvak99-voice-receptionist-widget-settings-page.component-Bok64X2q.mjs +968 -0
- package/fesm2022/edvak99-voice-receptionist-widget-settings-page.component-Bok64X2q.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-tasks-page.component-DXxjMVUv.mjs → edvak99-voice-receptionist-widget-tasks-page.component-Bb9lPcYi.mjs} +56 -5
- package/fesm2022/edvak99-voice-receptionist-widget-tasks-page.component-Bb9lPcYi.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-wizard-page.component-C1Z6yC0q.mjs → edvak99-voice-receptionist-widget-wizard-page.component-BZVlWLWh.mjs} +4 -2
- package/fesm2022/{edvak99-voice-receptionist-widget-wizard-page.component-C1Z6yC0q.mjs.map → edvak99-voice-receptionist-widget-wizard-page.component-BZVlWLWh.mjs.map} +1 -1
- package/fesm2022/edvak99-voice-receptionist-widget.mjs +1 -1
- package/lib/components/call-conversation-panel/call-conversation-panel.component.d.ts +9 -6
- package/lib/components/call-tasks-panel/call-tasks-panel.component.d.ts +8 -8
- package/lib/components/knowledge-test-modal/knowledge-test-modal.component.d.ts +28 -0
- package/lib/components/live-transcript-panel/live-transcript-panel.component.d.ts +7 -4
- package/lib/components/outbound-dial-modal/outbound-dial-modal.component.d.ts +26 -0
- package/lib/layout/eds-module-nav.component.d.ts +0 -3
- package/lib/mocks/agent-activity.seed.d.ts +2 -0
- package/lib/models/agent-activity.types.d.ts +54 -0
- package/lib/models/ai-receptionist.types.d.ts +25 -0
- package/lib/models/api-dto.types.d.ts +18 -0
- package/lib/models/live-transcript.types.d.ts +2 -1
- package/lib/models/outbound-patient.types.d.ts +23 -0
- package/lib/models/outbound-purpose.types.d.ts +2 -0
- package/lib/models/staff-media.types.d.ts +36 -0
- package/lib/pages/activities-page/activities-page.component.d.ts +57 -0
- package/lib/pages/analytics-page/analytics-page.component.d.ts +38 -14
- package/lib/pages/call-history-detail-page/call-history-detail-page.component.d.ts +2 -3
- package/lib/pages/call-history-page/call-history-page.component.d.ts +9 -6
- package/lib/pages/dashboard-page/dashboard-page.component.d.ts +12 -8
- package/lib/pages/live-calls-page/live-calls-page.component.d.ts +14 -24
- package/lib/pages/live-monitor-page/live-monitor-page.component.d.ts +34 -1
- package/lib/pages/settings-page/settings-fields.config.d.ts +16 -0
- package/lib/pages/settings-page/settings-page.component.d.ts +48 -14
- package/lib/services/ai-receptionist-api.mock.d.ts +34 -0
- package/lib/services/ai-receptionist-api.service.d.ts +56 -1
- package/lib/services/live-transcript.service.d.ts +1 -0
- package/lib/services/staff-media.service.d.ts +52 -0
- package/lib/ui/eds-avatar.component.d.ts +5 -2
- package/lib/ui/eds-button.component.d.ts +1 -1
- package/lib/utils/call-history-display.util.d.ts +21 -0
- package/lib/utils/outbound-purpose.util.d.ts +19 -0
- package/lib/utils/transcript-timing.util.d.ts +1 -1
- package/lib/utils/welcome-message.util.d.ts +1 -1
- package/package.json +2 -1
- package/styles/eds.scss +95 -66
- package/fesm2022/edvak99-voice-receptionist-widget-analytics-page.component-Dsujn5az.mjs +0 -113
- package/fesm2022/edvak99-voice-receptionist-widget-analytics-page.component-Dsujn5az.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-audit-page.component-xoLlHj8K.mjs +0 -67
- package/fesm2022/edvak99-voice-receptionist-widget-audit-page.component-xoLlHj8K.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-call-history-detail-page.component-2K9W77As.mjs +0 -316
- package/fesm2022/edvak99-voice-receptionist-widget-call-history-detail-page.component-2K9W77As.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-call-history-page.component-B5AnEjoh.mjs +0 -174
- package/fesm2022/edvak99-voice-receptionist-widget-call-history-page.component-B5AnEjoh.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-call-review.util-BgsBCKgZ.mjs +0 -70
- package/fesm2022/edvak99-voice-receptionist-widget-call-review.util-BgsBCKgZ.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-dashboard-page.component-BNdnbAVM.mjs +0 -248
- package/fesm2022/edvak99-voice-receptionist-widget-dashboard-page.component-BNdnbAVM.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-eds-avatar.component-CbphhP6o.mjs +0 -27
- package/fesm2022/edvak99-voice-receptionist-widget-eds-avatar.component-CbphhP6o.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-eds-elapsed.pipe-BgLsnq6A.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-Dn0GrZ6_.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-knowledge-hub.page-BngGx_Lc.mjs +0 -609
- package/fesm2022/edvak99-voice-receptionist-widget-knowledge-hub.page-BngGx_Lc.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-live-calls-list.service-0kGWO6sh.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-live-calls-page.component-DfLmK89M.mjs +0 -115
- package/fesm2022/edvak99-voice-receptionist-widget-live-calls-page.component-DfLmK89M.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-live-monitor-page.component-DNpLFqBw.mjs +0 -574
- package/fesm2022/edvak99-voice-receptionist-widget-live-monitor-page.component-DNpLFqBw.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-outbound-purpose.util-BQECIuJu.mjs +0 -54
- package/fesm2022/edvak99-voice-receptionist-widget-outbound-purpose.util-BQECIuJu.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-outbound-purposes-page.component-CYSZ832p.mjs +0 -265
- package/fesm2022/edvak99-voice-receptionist-widget-outbound-purposes-page.component-CYSZ832p.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-settings-page.component-B9nv6wtB.mjs +0 -509
- package/fesm2022/edvak99-voice-receptionist-widget-settings-page.component-B9nv6wtB.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-task.util-DdtI0CR3.mjs +0 -52
- package/fesm2022/edvak99-voice-receptionist-widget-task.util-DdtI0CR3.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-tasks-page.component-DXxjMVUv.mjs.map +0 -1
- package/lib/knowledge/components/faq-empty-state/faq-empty-state.component.d.ts +0 -22
- package/lib/knowledge/components/faq-form/faq-form.component.d.ts +0 -27
- package/lib/knowledge/components/faq-search-tester/faq-search-tester.component.d.ts +0 -17
- package/lib/knowledge/mocks/practice-faq.seed.d.ts +0 -2
- package/lib/knowledge/models/practice-faq.model.d.ts +0 -50
- package/lib/knowledge/pages/knowledge-hub.page.d.ts +0 -54
- package/lib/knowledge/services/practice-faq-api.mock.d.ts +0 -16
- package/lib/knowledge/services/practice-faq-api.service.d.ts +0 -26
- package/lib/knowledge/utils/faq.util.d.ts +0 -3
- package/lib/layout/eds-topbar.component.d.ts +0 -29
- package/lib/pages/audit-page/audit-page.component.d.ts +0 -21
- package/lib/ui/eds-waveform.component.d.ts +0 -8
|
@@ -3,12 +3,31 @@ export declare const REQUIRED_FIELD_OPTIONS: {
|
|
|
3
3
|
value: OutboundRequiredField;
|
|
4
4
|
label: string;
|
|
5
5
|
}[];
|
|
6
|
+
/** Live dialer values used to fill opening-template tokens. */
|
|
7
|
+
export interface OpeningPreviewValues {
|
|
8
|
+
patientName?: string;
|
|
9
|
+
appointmentDate?: string;
|
|
10
|
+
appointmentTime?: string;
|
|
11
|
+
providerName?: string;
|
|
12
|
+
practiceName?: string;
|
|
13
|
+
locationName?: string;
|
|
14
|
+
visitType?: string;
|
|
15
|
+
customScript?: string;
|
|
16
|
+
}
|
|
6
17
|
export declare function requiredFieldLabel(field: OutboundRequiredField): string;
|
|
7
18
|
export declare function formatRequiredFields(fields: OutboundRequiredField[]): string;
|
|
8
19
|
/** Substitute placeholder tokens with sample values. */
|
|
9
20
|
export declare function substitutePlaceholders(text: string, placeholders: OutboundPurposePlaceholder[]): string;
|
|
10
21
|
/** Live preview: sampleOpening if set, else openingTemplate with substitutions. */
|
|
11
22
|
export declare function renderOpeningPreview(sampleOpening: string, openingTemplate: string, placeholders: OutboundPurposePlaceholder[]): string;
|
|
23
|
+
/**
|
|
24
|
+
* Dialer preview: prefer openingTemplate and fill with live patient/appointment values.
|
|
25
|
+
* Unfilled tokens show as [Label] so staff see what is still missing.
|
|
26
|
+
*/
|
|
27
|
+
export declare function renderLiveOpeningPreview(purpose: Pick<OutboundPurpose, 'openingTemplate' | 'sampleOpening' | 'placeholders'>, live: OpeningPreviewValues): string;
|
|
28
|
+
/** Human-friendly date/time for opening lines (from ISO or form fields). */
|
|
29
|
+
export declare function formatOpeningDate(isoOrYmd: string | null | undefined): string;
|
|
30
|
+
export declare function formatOpeningTime(isoOrHm: string | null | undefined, fallbackIso?: string | null): string;
|
|
12
31
|
export declare function purposeShowsCustomScript(purpose: OutboundPurpose): boolean;
|
|
13
32
|
export declare function isCustomScriptRequired(purpose: OutboundPurpose): boolean;
|
|
14
33
|
export declare function isPurposeFormValid(purpose: OutboundPurpose | null, values: Record<string, string>): boolean;
|
|
@@ -14,4 +14,4 @@ export declare function buildTimedTranscript(lines: TranscriptLine[], durationSe
|
|
|
14
14
|
export declare function activeTranscriptIndex(lines: TimedTranscriptLine[], currentSec: number): number;
|
|
15
15
|
export declare function formatPlaybackTime(seconds: number): string;
|
|
16
16
|
export declare function toolStateClass(state: ToolEvent['state']): string;
|
|
17
|
-
export declare function transcriptRoleLabel(who: TranscriptLine['who']): string;
|
|
17
|
+
export declare function transcriptRoleLabel(who: TranscriptLine['who'], callerName?: string | null, callerMatched?: boolean): string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AgentSettings } from '../models/ai-receptionist.types';
|
|
2
|
-
export declare const WELCOME_MESSAGE_MAX =
|
|
2
|
+
export declare const WELCOME_MESSAGE_MAX = 1000;
|
|
3
3
|
export declare function buildAutoWelcomeTemplate(practiceName: string, agentName: string): string;
|
|
4
4
|
export declare function resolveWelcomePreview(welcomeMessage: string | undefined, practiceName: string, agentName: string): string;
|
|
5
5
|
export declare function computeEffectiveWelcomeMessage(settings: Pick<AgentSettings, 'general'>): string;
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@edvak99/voice-receptionist-widget",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.4",
|
|
4
4
|
"description": "Edvak AI Receptionist — embeddable Angular routes and UI for EHR hosts",
|
|
5
5
|
"peerDependencies": {
|
|
6
6
|
"@angular/common": "^19.2.0",
|
|
7
7
|
"@angular/core": "^19.2.0",
|
|
8
8
|
"@angular/forms": "^19.2.0",
|
|
9
9
|
"@angular/router": "^19.2.0",
|
|
10
|
+
"livekit-client": "^2.15.0",
|
|
10
11
|
"rxjs": "^7.8.0",
|
|
11
12
|
"socket.io-client": "^4.8.0"
|
|
12
13
|
},
|
package/styles/eds.scss
CHANGED
|
@@ -8,11 +8,11 @@
|
|
|
8
8
|
eds-app-shell,
|
|
9
9
|
.voice-receptionist-host {
|
|
10
10
|
/* Brand */
|
|
11
|
-
--eds-brand-500: #
|
|
11
|
+
--eds-brand-500: #2162f0;
|
|
12
12
|
--eds-brand-600: #2162f0;
|
|
13
|
-
--eds-brand-400: #
|
|
14
|
-
--eds-brand-300: #
|
|
15
|
-
--eds-brand: var(--eds-brand-
|
|
13
|
+
--eds-brand-400: #4b82f3;
|
|
14
|
+
--eds-brand-300: #8aaff8;
|
|
15
|
+
--eds-brand: var(--eds-brand-600);
|
|
16
16
|
--eds-violet-500: #8e51ff;
|
|
17
17
|
--eds-violet-400: #a684ff;
|
|
18
18
|
--eds-green-500: #0abf52;
|
|
@@ -27,16 +27,16 @@ eds-app-shell,
|
|
|
27
27
|
--eds-purple-300: #c4b5fd;
|
|
28
28
|
|
|
29
29
|
/* Gray / slate */
|
|
30
|
-
--eds-gray-50: #
|
|
31
|
-
--eds-gray-100: #
|
|
32
|
-
--eds-gray-200: #
|
|
30
|
+
--eds-gray-50: #f7f9fa;
|
|
31
|
+
--eds-gray-100: #f7f9fa;
|
|
32
|
+
--eds-gray-200: #e5e5e5;
|
|
33
33
|
--eds-gray-300: #d4d4d8;
|
|
34
34
|
--eds-gray-400: #a1a1aa;
|
|
35
|
-
--eds-gray-500: #
|
|
36
|
-
--eds-gray-600: #
|
|
37
|
-
--eds-gray-700: #
|
|
38
|
-
--eds-gray-800: #
|
|
39
|
-
--eds-gray-900: #
|
|
35
|
+
--eds-gray-500: #767676;
|
|
36
|
+
--eds-gray-600: #53575c;
|
|
37
|
+
--eds-gray-700: #41464c;
|
|
38
|
+
--eds-gray-800: #2f3338;
|
|
39
|
+
--eds-gray-900: #1f2328;
|
|
40
40
|
--eds-slate-950: #030717;
|
|
41
41
|
--eds-slate-900: #121828;
|
|
42
42
|
--eds-slate-800: #212a39;
|
|
@@ -47,44 +47,45 @@ eds-app-shell,
|
|
|
47
47
|
--eds-slate-300: #cad5e2;
|
|
48
48
|
|
|
49
49
|
/* App color tokens (legacy names → eds-prefixed) */
|
|
50
|
-
--eds-color-primary: #
|
|
51
|
-
--eds-color-primary-hover: #
|
|
52
|
-
--eds-color-primary-light: #
|
|
50
|
+
--eds-color-primary: #2162f0;
|
|
51
|
+
--eds-color-primary-hover: #1a52d4;
|
|
52
|
+
--eds-color-primary-light: #eaf1fe;
|
|
53
53
|
--eds-color-primary-soft: var(--eds-color-primary-light);
|
|
54
|
-
--eds-color-accent: #
|
|
55
|
-
--eds-color-accent-light: #
|
|
56
|
-
--eds-color-bg: #
|
|
54
|
+
--eds-color-accent: #4b82f3;
|
|
55
|
+
--eds-color-accent-light: #dce8fd;
|
|
56
|
+
--eds-color-bg: #f7f9fa;
|
|
57
57
|
--eds-color-surface: #ffffff;
|
|
58
|
-
--eds-color-surface-alt: #
|
|
58
|
+
--eds-color-surface-alt: #f7f9fa;
|
|
59
59
|
--eds-color-sidebar-bg: #0f172a;
|
|
60
60
|
--eds-color-chat-ai: #f1f5f9;
|
|
61
|
-
--eds-color-text: #
|
|
62
|
-
--eds-color-text-muted: #
|
|
63
|
-
--eds-color-text-soft: #
|
|
64
|
-
--eds-color-border: #
|
|
65
|
-
--eds-color-border-strong: #
|
|
61
|
+
--eds-color-text: #41464c;
|
|
62
|
+
--eds-color-text-muted: #53575c;
|
|
63
|
+
--eds-color-text-soft: #767676;
|
|
64
|
+
--eds-color-border: #e5e5e5;
|
|
65
|
+
--eds-color-border-strong: #d4d4d8;
|
|
66
66
|
--eds-color-success: #22c55e;
|
|
67
67
|
--eds-color-success-soft: #ecfdf3;
|
|
68
68
|
--eds-color-warning: #f59e0b;
|
|
69
69
|
--eds-color-warning-soft: #fffbeb;
|
|
70
70
|
--eds-color-danger: #ef4444;
|
|
71
71
|
--eds-color-danger-soft: #fef2f2;
|
|
72
|
-
--eds-color-info: #
|
|
73
|
-
--eds-color-info-soft: #
|
|
72
|
+
--eds-color-info: #2162f0;
|
|
73
|
+
--eds-color-info-soft: #eaf1fe;
|
|
74
74
|
|
|
75
|
-
/* Surfaces / text / borders */
|
|
76
|
-
--eds-surface-l0: #ffffff;
|
|
77
|
-
--eds-surface-l1: #
|
|
78
|
-
--eds-surface-l2: #
|
|
75
|
+
/* Surfaces / text / borders — product palette */
|
|
76
|
+
--eds-surface-l0: #ffffff; /* Primary BG */
|
|
77
|
+
--eds-surface-l1: #f7f9fa; /* Secondary BG */
|
|
78
|
+
--eds-surface-l2: #f7f9fa;
|
|
79
79
|
--eds-surface-card: var(--eds-surface-l0);
|
|
80
80
|
--eds-surface-muted: var(--eds-surface-l1);
|
|
81
81
|
--eds-surface-hover: var(--eds-surface-l1);
|
|
82
|
-
--eds-text-primary:
|
|
83
|
-
--eds-text-secondary:
|
|
84
|
-
--eds-text-
|
|
85
|
-
--eds-
|
|
86
|
-
--eds-border-
|
|
87
|
-
--eds-
|
|
82
|
+
--eds-text-primary: #41464c;
|
|
83
|
+
--eds-text-secondary: #53575c;
|
|
84
|
+
--eds-text-tertiary: #767676;
|
|
85
|
+
--eds-text-brand: #2162f0;
|
|
86
|
+
--eds-border-default: #e5e5e5;
|
|
87
|
+
--eds-border-subtle: #e5e5e5;
|
|
88
|
+
--eds-bg-brand: #2162f0;
|
|
88
89
|
|
|
89
90
|
/* Radius / space / shadow */
|
|
90
91
|
--eds-radius-sm: 4px;
|
|
@@ -105,25 +106,39 @@ eds-app-shell,
|
|
|
105
106
|
/* Layout */
|
|
106
107
|
--eds-rail-width: 64px;
|
|
107
108
|
--eds-nav-width: 244px;
|
|
108
|
-
--eds-topbar-height:
|
|
109
|
+
--eds-topbar-height: 0px;
|
|
109
110
|
--eds-sidebar-width: 240px;
|
|
110
111
|
--eds-monitor-text: var(--eds-text-primary);
|
|
111
112
|
|
|
112
|
-
/* Fonts */
|
|
113
|
+
/* Fonts — Inter only (EHR dashboard parity; no DM Sans / Figtree) */
|
|
113
114
|
--eds-font-inter: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
114
|
-
--eds-font-dm:
|
|
115
|
-
--eds-font-figtree:
|
|
115
|
+
--eds-font-dm: var(--eds-font-inter);
|
|
116
|
+
--eds-font-figtree: var(--eds-font-inter);
|
|
116
117
|
--eds-font-mono: 'IBM Plex Mono', ui-monospace, monospace;
|
|
117
118
|
--eds-font-sans: var(--eds-font-inter);
|
|
118
|
-
--eds-font-body: var(--eds-font-
|
|
119
|
-
--eds-font-display: var(--eds-font-
|
|
119
|
+
--eds-font-body: var(--eds-font-inter);
|
|
120
|
+
--eds-font-display: var(--eds-font-inter);
|
|
121
|
+
|
|
122
|
+
/* Type scale — match EHR Tailwind utilities */
|
|
123
|
+
--eds-font-size-xs: 10px; /* fs-xs */
|
|
124
|
+
--eds-font-size-sm: 12px; /* fs-sm */
|
|
125
|
+
--eds-font-size-base: 13px; /* fs-base */
|
|
126
|
+
--eds-font-size-md: 15px; /* fs-md */
|
|
127
|
+
--eds-font-size-lg: 18px;
|
|
128
|
+
--eds-font-size-xl: 24px;
|
|
129
|
+
--eds-font-weight-regular: 400;
|
|
130
|
+
--eds-font-weight-medium: 500;
|
|
131
|
+
--eds-font-weight-semibold: 600;
|
|
132
|
+
--eds-font-weight-bold: 700;
|
|
133
|
+
/* EHR table-default header muted */
|
|
134
|
+
--eds-text-table-header: #4d5573;
|
|
120
135
|
}
|
|
121
136
|
|
|
122
|
-
/* Typography */
|
|
137
|
+
/* Typography — EHR weight scale: body 400, medium 500, semibold 600, bold 700 */
|
|
123
138
|
.eds-h1 {
|
|
124
139
|
font-family: var(--eds-font-inter);
|
|
125
|
-
font-size:
|
|
126
|
-
font-weight:
|
|
140
|
+
font-size: var(--eds-font-size-xl);
|
|
141
|
+
font-weight: var(--eds-font-weight-bold);
|
|
127
142
|
letter-spacing: -0.02em;
|
|
128
143
|
color: var(--eds-text-primary);
|
|
129
144
|
margin: 0;
|
|
@@ -131,8 +146,8 @@ eds-app-shell,
|
|
|
131
146
|
|
|
132
147
|
.eds-h2 {
|
|
133
148
|
font-family: var(--eds-font-inter);
|
|
134
|
-
font-size:
|
|
135
|
-
font-weight:
|
|
149
|
+
font-size: var(--eds-font-size-lg);
|
|
150
|
+
font-weight: var(--eds-font-weight-bold);
|
|
136
151
|
letter-spacing: -0.01em;
|
|
137
152
|
color: var(--eds-text-primary);
|
|
138
153
|
margin: 0;
|
|
@@ -140,64 +155,67 @@ eds-app-shell,
|
|
|
140
155
|
|
|
141
156
|
.eds-h3 {
|
|
142
157
|
font-family: var(--eds-font-inter);
|
|
143
|
-
font-size:
|
|
144
|
-
font-weight:
|
|
158
|
+
font-size: var(--eds-font-size-md);
|
|
159
|
+
font-weight: var(--eds-font-weight-semibold);
|
|
145
160
|
color: var(--eds-text-primary);
|
|
146
161
|
margin: 0;
|
|
147
162
|
}
|
|
148
163
|
|
|
149
164
|
.eds-h4 {
|
|
150
165
|
font-family: var(--eds-font-inter);
|
|
151
|
-
font-size:
|
|
152
|
-
font-weight:
|
|
166
|
+
font-size: var(--eds-font-size-base);
|
|
167
|
+
font-weight: var(--eds-font-weight-semibold);
|
|
153
168
|
color: var(--eds-text-primary);
|
|
154
169
|
margin: 0;
|
|
155
170
|
}
|
|
156
171
|
|
|
157
172
|
.eds-body {
|
|
158
|
-
font-family: var(--eds-font-
|
|
159
|
-
font-size:
|
|
173
|
+
font-family: var(--eds-font-inter);
|
|
174
|
+
font-size: var(--eds-font-size-base);
|
|
175
|
+
font-weight: var(--eds-font-weight-regular);
|
|
160
176
|
line-height: 1.5;
|
|
161
177
|
color: var(--eds-text-primary);
|
|
162
178
|
}
|
|
163
179
|
|
|
164
180
|
.eds-body-bold {
|
|
165
181
|
@extend .eds-body;
|
|
166
|
-
font-weight:
|
|
182
|
+
font-weight: var(--eds-font-weight-semibold);
|
|
167
183
|
}
|
|
168
184
|
|
|
169
185
|
.eds-body-sm {
|
|
170
|
-
font-family: var(--eds-font-
|
|
171
|
-
font-size:
|
|
186
|
+
font-family: var(--eds-font-inter);
|
|
187
|
+
font-size: var(--eds-font-size-sm);
|
|
188
|
+
font-weight: var(--eds-font-weight-regular);
|
|
172
189
|
line-height: 1.45;
|
|
173
190
|
color: var(--eds-text-secondary);
|
|
174
191
|
}
|
|
175
192
|
|
|
176
193
|
.eds-body-sm-bold {
|
|
177
194
|
@extend .eds-body-sm;
|
|
178
|
-
font-weight:
|
|
195
|
+
font-weight: var(--eds-font-weight-semibold);
|
|
179
196
|
color: var(--eds-text-primary);
|
|
180
197
|
}
|
|
181
198
|
|
|
182
199
|
.eds-mono {
|
|
183
200
|
font-family: var(--eds-font-mono);
|
|
184
|
-
font-size:
|
|
201
|
+
font-size: var(--eds-font-size-base);
|
|
185
202
|
color: var(--eds-text-secondary);
|
|
186
203
|
}
|
|
187
204
|
|
|
188
205
|
.eds-mono-sm {
|
|
189
206
|
font-family: var(--eds-font-mono);
|
|
190
|
-
font-size:
|
|
207
|
+
font-size: var(--eds-font-size-sm);
|
|
191
208
|
color: var(--eds-text-secondary);
|
|
192
209
|
}
|
|
193
210
|
|
|
211
|
+
/* Section / field labels — EHR table-default style (not 11px uppercase) */
|
|
194
212
|
.eds-label {
|
|
195
213
|
font-family: var(--eds-font-inter);
|
|
196
|
-
font-size:
|
|
197
|
-
font-weight:
|
|
198
|
-
letter-spacing:
|
|
199
|
-
text-transform:
|
|
200
|
-
color: var(--eds-
|
|
214
|
+
font-size: var(--eds-font-size-base);
|
|
215
|
+
font-weight: var(--eds-font-weight-semibold);
|
|
216
|
+
letter-spacing: normal;
|
|
217
|
+
text-transform: none;
|
|
218
|
+
color: var(--eds-text-table-header, #4d5573);
|
|
201
219
|
}
|
|
202
220
|
|
|
203
221
|
.eds-icon {
|
|
@@ -324,6 +342,10 @@ eds-app-shell,
|
|
|
324
342
|
min-height: calc(100vh - var(--eds-topbar-height));
|
|
325
343
|
background: var(--eds-surface-l1);
|
|
326
344
|
padding: 24px;
|
|
345
|
+
font-family: var(--eds-font-inter);
|
|
346
|
+
font-size: var(--eds-font-size-base, 13px);
|
|
347
|
+
font-weight: var(--eds-font-weight-regular, 400);
|
|
348
|
+
color: var(--eds-text-primary);
|
|
327
349
|
}
|
|
328
350
|
|
|
329
351
|
.eds-page--dark {
|
|
@@ -336,7 +358,12 @@ eds-app-shell,
|
|
|
336
358
|
border-collapse: collapse;
|
|
337
359
|
|
|
338
360
|
thead th {
|
|
339
|
-
|
|
361
|
+
font-family: var(--eds-font-inter);
|
|
362
|
+
font-size: var(--eds-font-size-base, 13px);
|
|
363
|
+
font-weight: var(--eds-font-weight-semibold, 600);
|
|
364
|
+
letter-spacing: normal;
|
|
365
|
+
text-transform: none;
|
|
366
|
+
color: var(--eds-text-table-header, #4d5573);
|
|
340
367
|
text-align: left;
|
|
341
368
|
padding: 10px 16px;
|
|
342
369
|
border-bottom: 1px solid var(--eds-border-default);
|
|
@@ -345,7 +372,9 @@ eds-app-shell,
|
|
|
345
372
|
|
|
346
373
|
tbody td {
|
|
347
374
|
padding: 12px 16px;
|
|
348
|
-
font-
|
|
375
|
+
font-family: var(--eds-font-inter);
|
|
376
|
+
font-size: var(--eds-font-size-base, 13px);
|
|
377
|
+
font-weight: var(--eds-font-weight-regular, 400);
|
|
349
378
|
color: var(--eds-text-primary);
|
|
350
379
|
border-bottom: 1px solid var(--eds-border-default);
|
|
351
380
|
}
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, signal, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
|
-
import { A as AiReceptionistApiService, b as EdsIconComponent } from './edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-Dn0GrZ6_.mjs';
|
|
4
|
-
|
|
5
|
-
class AnalyticsPageComponent {
|
|
6
|
-
constructor() {
|
|
7
|
-
this.api = inject(AiReceptionistApiService);
|
|
8
|
-
this.data = signal(null);
|
|
9
|
-
this.range = signal('30d');
|
|
10
|
-
this.loading = signal(true);
|
|
11
|
-
this.ranges = [
|
|
12
|
-
{ id: '7d', label: '7 days' },
|
|
13
|
-
{ id: '30d', label: '30 days' },
|
|
14
|
-
{ id: '90d', label: '90 days' },
|
|
15
|
-
];
|
|
16
|
-
}
|
|
17
|
-
ngOnInit() {
|
|
18
|
-
this.load();
|
|
19
|
-
}
|
|
20
|
-
setRange(id) {
|
|
21
|
-
this.range.set(id);
|
|
22
|
-
this.load();
|
|
23
|
-
}
|
|
24
|
-
maxCount(items) {
|
|
25
|
-
return Math.max(...items.map((i) => i.count), 1);
|
|
26
|
-
}
|
|
27
|
-
barHeightPercent(point, points) {
|
|
28
|
-
if (point.count <= 0)
|
|
29
|
-
return 0;
|
|
30
|
-
return (point.count / this.maxCount(points)) * 100;
|
|
31
|
-
}
|
|
32
|
-
/** Hide inline counts when bars are too narrow to stay readable. */
|
|
33
|
-
showBarValue(point, points) {
|
|
34
|
-
return point.count > 0 && points.length <= 21;
|
|
35
|
-
}
|
|
36
|
-
maxValue(items) {
|
|
37
|
-
return Math.max(...items.map((i) => i.value), 1);
|
|
38
|
-
}
|
|
39
|
-
volumeTooltip(point) {
|
|
40
|
-
const datePart = point.date ? this.formatChartDate(point.date) : point.label;
|
|
41
|
-
return `${datePart}: ${point.count} call${point.count === 1 ? '' : 's'}`;
|
|
42
|
-
}
|
|
43
|
-
peakTooltip(point) {
|
|
44
|
-
return `${point.label}: ${point.count} call${point.count === 1 ? '' : 's'}`;
|
|
45
|
-
}
|
|
46
|
-
/** ISO or YYYY-MM-DD → MM/DD (zero-padded). */
|
|
47
|
-
formatChartDate(date) {
|
|
48
|
-
const iso = /^(\d{4})-(\d{2})-(\d{2})/.exec(date.trim());
|
|
49
|
-
if (iso) {
|
|
50
|
-
return `${iso[2]}/${iso[3]}`;
|
|
51
|
-
}
|
|
52
|
-
return date;
|
|
53
|
-
}
|
|
54
|
-
/** Compact x-axis for volume — full labels on 7d, sparse dates on longer ranges. */
|
|
55
|
-
volumeAxisLabel(point, index, total) {
|
|
56
|
-
if (point.date) {
|
|
57
|
-
if (total <= 7)
|
|
58
|
-
return this.formatChartDate(point.date);
|
|
59
|
-
const step = total <= 14 ? 2 : total <= 31 ? 5 : 7;
|
|
60
|
-
if (index % step !== 0 && index !== total - 1)
|
|
61
|
-
return '';
|
|
62
|
-
return this.formatChartDate(point.date);
|
|
63
|
-
}
|
|
64
|
-
if (total <= 7)
|
|
65
|
-
return point.day;
|
|
66
|
-
const step = total <= 14 ? 2 : total <= 31 ? 5 : 7;
|
|
67
|
-
if (index % step !== 0 && index !== total - 1)
|
|
68
|
-
return '';
|
|
69
|
-
return point.day;
|
|
70
|
-
}
|
|
71
|
-
showPeakAxisLabel(index, total) {
|
|
72
|
-
if (total <= 12)
|
|
73
|
-
return true;
|
|
74
|
-
const step = total <= 24 ? 3 : 4;
|
|
75
|
-
return index % step === 0 || index === total - 1;
|
|
76
|
-
}
|
|
77
|
-
volumeRangeLabel() {
|
|
78
|
-
const vol = this.data()?.volume;
|
|
79
|
-
if (!vol?.startDate || !vol?.endDate)
|
|
80
|
-
return 'Calls per day';
|
|
81
|
-
const start = this.formatChartDate(vol.startDate);
|
|
82
|
-
const end = this.formatChartDate(vol.endDate);
|
|
83
|
-
return `${start} – ${end}${vol.timezone ? ` (${vol.timezone})` : ''}`;
|
|
84
|
-
}
|
|
85
|
-
kpiIcon(label) {
|
|
86
|
-
const key = label.toLowerCase();
|
|
87
|
-
if (key.includes('call') || key.includes('handled'))
|
|
88
|
-
return 'call';
|
|
89
|
-
if (key.includes('time') || key.includes('duration'))
|
|
90
|
-
return 'schedule';
|
|
91
|
-
if (key.includes('resolution') || key.includes('book'))
|
|
92
|
-
return 'event_available';
|
|
93
|
-
if (key.includes('transfer'))
|
|
94
|
-
return 'phone_forwarded';
|
|
95
|
-
return 'monitoring';
|
|
96
|
-
}
|
|
97
|
-
load() {
|
|
98
|
-
this.loading.set(true);
|
|
99
|
-
this.api.getAnalytics(this.range()).subscribe(({ data }) => {
|
|
100
|
-
this.data.set(data);
|
|
101
|
-
this.loading.set(false);
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: AnalyticsPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
105
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: AnalyticsPageComponent, isStandalone: true, selector: "eds-analytics-page", ngImport: i0, template: "<div class=\"eds-page analytics-page\">\n <header class=\"analytics-page__header\">\n <div>\n <h1 class=\"eds-h1\">Analytics</h1>\n <p class=\"eds-body-sm\">Call volume, outcomes, and performance KPIs</p>\n </div>\n <div class=\"analytics-page__range\">\n @for (r of ranges; track r.id) {\n <button\n type=\"button\"\n class=\"analytics-page__range-btn\"\n [class.analytics-page__range-btn--active]=\"range() === r.id\"\n (click)=\"setRange(r.id)\"\n >\n {{ r.label }}\n </button>\n }\n </div>\n </header>\n\n @if (loading()) {\n <p class=\"eds-body-sm\">Loading analytics\u2026</p>\n } @else if (data()) {\n <section class=\"analytics-page__kpis\">\n @for (kpi of data()!.kpiCards; track kpi.label) {\n <article class=\"eds-card analytics-page__kpi\">\n <eds-icon [name]=\"kpiIcon(kpi.label)\" [size]=\"22\" />\n <span class=\"eds-label\">{{ kpi.label }}</span>\n <span class=\"analytics-page__kpi-value\">{{ kpi.value }}</span>\n @if (kpi.delta) {\n <span class=\"analytics-page__kpi-delta\" [attr.data-tone]=\"kpi.tone\">{{ kpi.delta }}</span>\n }\n @if (kpi.sub) {\n <span class=\"analytics-page__kpi-sub\">{{ kpi.sub }}</span>\n }\n </article>\n }\n </section>\n\n <div class=\"analytics-page__charts\">\n <article class=\"eds-card analytics-page__chart\">\n <div class=\"analytics-page__chart-head\">\n <h2 class=\"eds-h2\">Call volume</h2>\n <span class=\"eds-label\">{{ volumeRangeLabel() }}</span>\n </div>\n <div class=\"analytics-page__volume-chart\">\n <div class=\"analytics-page__plot\">\n <div class=\"analytics-page__grid\" aria-hidden=\"true\"></div>\n <div class=\"analytics-page__bars\" role=\"list\" aria-label=\"Call volume by day\">\n @for (point of data()!.volume.points; track point.date || point.label; let i = $index) {\n <div\n class=\"analytics-page__bar-col\"\n role=\"listitem\"\n [attr.aria-label]=\"volumeTooltip(point)\"\n >\n <div class=\"analytics-page__bar-wrap\">\n @if (point.count > 0) {\n <div\n class=\"analytics-page__bar-stack\"\n [style.height.%]=\"barHeightPercent(point, data()!.volume.points)\"\n >\n @if (showBarValue(point, data()!.volume.points)) {\n <span class=\"analytics-page__bar-value eds-mono-sm\">{{ point.count }}</span>\n }\n <div class=\"analytics-page__bar\"></div>\n </div>\n }\n <span class=\"analytics-page__tooltip\">{{ volumeTooltip(point) }}</span>\n </div>\n <span class=\"eds-mono-sm analytics-page__bar-axis\">\n {{ volumeAxisLabel(point, i, data()!.volume.points.length) }}\n </span>\n </div>\n }\n </div>\n </div>\n </div>\n <!-- <p class=\"analytics-page__axis-note eds-label\">(MM/DD)/calls per day</p> -->\n </article>\n\n <article class=\"eds-card analytics-page__chart\">\n <h2 class=\"eds-h2\">Outcomes</h2>\n <div class=\"analytics-page__bars analytics-page__bars--horizontal\">\n @for (item of data()!.outcomes; track item.label) {\n <div class=\"analytics-page__hbar-row\">\n <span class=\"eds-body-sm\">{{ item.label }}</span>\n <div class=\"analytics-page__hbar-track\">\n <span\n class=\"analytics-page__hbar-fill\"\n [style.width.%]=\"(item.value / maxValue(data()!.outcomes)) * 100\"\n [style.background]=\"item.color\"\n ></span>\n </div>\n <span class=\"eds-mono-sm\">{{ item.value }}%</span>\n </div>\n }\n </div>\n </article>\n\n <article class=\"eds-card analytics-page__chart\">\n <h2 class=\"eds-h2\">Top reasons</h2>\n <div class=\"analytics-page__bars analytics-page__bars--horizontal\">\n @for (item of data()!.reasons; track item.label) {\n <div class=\"analytics-page__hbar-row\">\n <span class=\"eds-body-sm\">{{ item.label }}</span>\n <div class=\"analytics-page__hbar-track\">\n <span\n class=\"analytics-page__hbar-fill\"\n [style.width.%]=\"(item.value / maxValue(data()!.reasons)) * 100\"\n ></span>\n </div>\n <span class=\"eds-mono-sm\">{{ item.value }}%</span>\n </div>\n }\n </div>\n </article>\n\n <article class=\"eds-card analytics-page__chart\">\n <div class=\"analytics-page__chart-head\">\n <h2 class=\"eds-h2\">Peak hours</h2>\n <span class=\"eds-label\">\n @if (data()!.peakHours.timezone) {\n {{ data()!.peakHours.timezone }}\n } @else {\n Calls per hour\n }\n </span>\n </div>\n <div class=\"analytics-page__volume-chart analytics-page__volume-chart--peak\">\n <div class=\"analytics-page__plot\">\n <div class=\"analytics-page__grid\" aria-hidden=\"true\"></div>\n <div class=\"analytics-page__bars analytics-page__bars--peak\" role=\"list\" aria-label=\"Call volume by hour\">\n @for (point of data()!.peakHours.points; track point.hour) {\n <div\n class=\"analytics-page__bar-col analytics-page__bar-col--peak\"\n role=\"listitem\"\n [attr.aria-label]=\"peakTooltip(point)\"\n >\n <div class=\"analytics-page__bar-wrap\">\n @if (point.count > 0) {\n <div\n class=\"analytics-page__bar-stack\"\n [style.height.%]=\"barHeightPercent(point, data()!.peakHours.points)\"\n >\n <div class=\"analytics-page__bar\"></div>\n </div>\n }\n <span class=\"analytics-page__tooltip\">{{ peakTooltip(point) }}</span>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n <div class=\"analytics-page__peak-axis\">\n @for (point of data()!.peakHours.points; track point.hour; let i = $index) {\n <span class=\"analytics-page__peak-tick eds-mono-sm\">\n @if (showPeakAxisLabel(i, data()!.peakHours.points.length)) {\n {{ point.label }}\n }\n </span>\n }\n </div>\n </article>\n </div>\n }\n</div>\n", styles: [".analytics-page__header{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;margin-bottom:20px}.analytics-page__range{display:flex;gap:4px;background:var(--eds-surface-l0);border:1px solid var(--eds-border-default);border-radius:var(--eds-radius-md);padding:4px}.analytics-page__range-btn{padding:6px 12px;border:none;background:none;font-size:13px;border-radius:var(--eds-radius-sm);cursor:pointer;color:var(--eds-text-secondary)}.analytics-page__range-btn--active{background:var(--eds-brand-500);color:#fff}.analytics-page__kpis{display:grid;grid-template-columns:repeat(4,1fr);gap:12px;margin-bottom:20px}.analytics-page__kpi{display:flex;flex-direction:column;gap:6px;padding:16px}.analytics-page__kpi-value{font-size:24px;font-weight:600;color:var(--eds-text-primary)}.analytics-page__kpi-delta{font-size:12px;font-weight:600}.analytics-page__kpi-delta[data-tone=pos]{color:var(--eds-green-500, #16a34a)}.analytics-page__kpi-delta[data-tone=warn]{color:var(--eds-amber-500, #d97706)}.analytics-page__kpi-delta[data-tone=neutral]{color:var(--eds-text-secondary)}.analytics-page__kpi-sub{font-size:12px;color:var(--eds-text-secondary)}.analytics-page__charts{display:grid;grid-template-columns:1fr 1fr;gap:16px}.analytics-page__chart{padding:16px}.analytics-page__chart .eds-h2{margin-bottom:0}.analytics-page__chart-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px;margin-bottom:16px;flex-wrap:wrap}.analytics-page__volume-chart--peak .analytics-page__grid{inset:0}.analytics-page__plot{position:relative;width:100%;min-width:0}.analytics-page__grid{position:absolute;inset:0 0 24px;pointer-events:none;background-image:linear-gradient(to top,var(--eds-border-default) 1px,transparent 1px);background-size:100% 25%;opacity:.45}.analytics-page__bars{display:flex;align-items:flex-end;justify-content:space-between;gap:8px;height:160px;position:relative;z-index:1}.analytics-page__bars--horizontal{flex-direction:column;height:auto;align-items:stretch;gap:10px}.analytics-page__bars--peak{height:100px}.analytics-page__bars--peak .analytics-page__bar{max-width:100%}.analytics-page__bar-col{flex:1;display:flex;flex-direction:column;align-items:center;gap:6px;height:100%;min-width:0;cursor:default}.analytics-page__bar-col:hover .analytics-page__tooltip,.analytics-page__bar-col:focus-within .analytics-page__tooltip{opacity:1}.analytics-page__bar-col--peak{min-width:0}.analytics-page__bar-value{flex-shrink:0;color:var(--eds-text-primary);font-size:11px;font-weight:600;line-height:1}.analytics-page__bar-wrap{position:relative;width:100%;flex:1;display:flex;flex-direction:column;justify-content:flex-end;align-items:center;min-height:0}.analytics-page__bar-stack{width:100%;max-width:32px;display:flex;flex-direction:column;justify-content:flex-end;align-items:stretch;gap:4px;min-height:0}.analytics-page__bar-axis{flex-shrink:0;min-height:16px;color:var(--eds-text-secondary);font-size:10px;text-align:center;line-height:1.2}.analytics-page__tooltip{position:absolute;bottom:calc(100% + 6px);left:50%;transform:translate(-50%);padding:4px 8px;background:var(--eds-gray-900, #18181b);color:#fafafa;font-size:11px;font-weight:500;line-height:1.3;border-radius:4px;white-space:nowrap;opacity:0;pointer-events:none;transition:opacity .15s ease;z-index:2;box-shadow:0 2px 8px #00000026}.analytics-page__tooltip:after{content:\"\";position:absolute;top:100%;left:50%;transform:translate(-50%);border:4px solid transparent;border-top-color:var(--eds-gray-900, #18181b)}.analytics-page__peak-axis{display:flex;justify-content:space-between;gap:2px;margin-top:8px}.analytics-page__peak-tick{flex:1;text-align:center;min-height:16px;color:var(--eds-text-secondary);font-size:10px}.analytics-page__bar{width:100%;flex:1 1 auto;min-height:3px;background:linear-gradient(180deg,var(--eds-brand-500),var(--eds-violet-500));border-radius:4px 4px 0 0;animation:eds-bar-grow .5s ease forwards;transform-origin:bottom}.analytics-page__hbar-row{display:grid;grid-template-columns:120px 1fr 40px;align-items:center;gap:10px}.analytics-page__hbar-track{height:8px;background:var(--eds-surface-l2);border-radius:4px;overflow:hidden}.analytics-page__hbar-fill{display:block;height:100%;background:var(--eds-brand-500);border-radius:4px;animation:eds-bar-grow .5s ease forwards;transform-origin:left}@media(max-width:1000px){.analytics-page__kpis{grid-template-columns:repeat(2,1fr)}.analytics-page__charts{grid-template-columns:1fr}}\n"], dependencies: [{ kind: "component", type: EdsIconComponent, selector: "eds-icon", inputs: ["name", "size", "fill", "weight"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
106
|
-
}
|
|
107
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: AnalyticsPageComponent, decorators: [{
|
|
108
|
-
type: Component,
|
|
109
|
-
args: [{ selector: 'eds-analytics-page', imports: [EdsIconComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"eds-page analytics-page\">\n <header class=\"analytics-page__header\">\n <div>\n <h1 class=\"eds-h1\">Analytics</h1>\n <p class=\"eds-body-sm\">Call volume, outcomes, and performance KPIs</p>\n </div>\n <div class=\"analytics-page__range\">\n @for (r of ranges; track r.id) {\n <button\n type=\"button\"\n class=\"analytics-page__range-btn\"\n [class.analytics-page__range-btn--active]=\"range() === r.id\"\n (click)=\"setRange(r.id)\"\n >\n {{ r.label }}\n </button>\n }\n </div>\n </header>\n\n @if (loading()) {\n <p class=\"eds-body-sm\">Loading analytics\u2026</p>\n } @else if (data()) {\n <section class=\"analytics-page__kpis\">\n @for (kpi of data()!.kpiCards; track kpi.label) {\n <article class=\"eds-card analytics-page__kpi\">\n <eds-icon [name]=\"kpiIcon(kpi.label)\" [size]=\"22\" />\n <span class=\"eds-label\">{{ kpi.label }}</span>\n <span class=\"analytics-page__kpi-value\">{{ kpi.value }}</span>\n @if (kpi.delta) {\n <span class=\"analytics-page__kpi-delta\" [attr.data-tone]=\"kpi.tone\">{{ kpi.delta }}</span>\n }\n @if (kpi.sub) {\n <span class=\"analytics-page__kpi-sub\">{{ kpi.sub }}</span>\n }\n </article>\n }\n </section>\n\n <div class=\"analytics-page__charts\">\n <article class=\"eds-card analytics-page__chart\">\n <div class=\"analytics-page__chart-head\">\n <h2 class=\"eds-h2\">Call volume</h2>\n <span class=\"eds-label\">{{ volumeRangeLabel() }}</span>\n </div>\n <div class=\"analytics-page__volume-chart\">\n <div class=\"analytics-page__plot\">\n <div class=\"analytics-page__grid\" aria-hidden=\"true\"></div>\n <div class=\"analytics-page__bars\" role=\"list\" aria-label=\"Call volume by day\">\n @for (point of data()!.volume.points; track point.date || point.label; let i = $index) {\n <div\n class=\"analytics-page__bar-col\"\n role=\"listitem\"\n [attr.aria-label]=\"volumeTooltip(point)\"\n >\n <div class=\"analytics-page__bar-wrap\">\n @if (point.count > 0) {\n <div\n class=\"analytics-page__bar-stack\"\n [style.height.%]=\"barHeightPercent(point, data()!.volume.points)\"\n >\n @if (showBarValue(point, data()!.volume.points)) {\n <span class=\"analytics-page__bar-value eds-mono-sm\">{{ point.count }}</span>\n }\n <div class=\"analytics-page__bar\"></div>\n </div>\n }\n <span class=\"analytics-page__tooltip\">{{ volumeTooltip(point) }}</span>\n </div>\n <span class=\"eds-mono-sm analytics-page__bar-axis\">\n {{ volumeAxisLabel(point, i, data()!.volume.points.length) }}\n </span>\n </div>\n }\n </div>\n </div>\n </div>\n <!-- <p class=\"analytics-page__axis-note eds-label\">(MM/DD)/calls per day</p> -->\n </article>\n\n <article class=\"eds-card analytics-page__chart\">\n <h2 class=\"eds-h2\">Outcomes</h2>\n <div class=\"analytics-page__bars analytics-page__bars--horizontal\">\n @for (item of data()!.outcomes; track item.label) {\n <div class=\"analytics-page__hbar-row\">\n <span class=\"eds-body-sm\">{{ item.label }}</span>\n <div class=\"analytics-page__hbar-track\">\n <span\n class=\"analytics-page__hbar-fill\"\n [style.width.%]=\"(item.value / maxValue(data()!.outcomes)) * 100\"\n [style.background]=\"item.color\"\n ></span>\n </div>\n <span class=\"eds-mono-sm\">{{ item.value }}%</span>\n </div>\n }\n </div>\n </article>\n\n <article class=\"eds-card analytics-page__chart\">\n <h2 class=\"eds-h2\">Top reasons</h2>\n <div class=\"analytics-page__bars analytics-page__bars--horizontal\">\n @for (item of data()!.reasons; track item.label) {\n <div class=\"analytics-page__hbar-row\">\n <span class=\"eds-body-sm\">{{ item.label }}</span>\n <div class=\"analytics-page__hbar-track\">\n <span\n class=\"analytics-page__hbar-fill\"\n [style.width.%]=\"(item.value / maxValue(data()!.reasons)) * 100\"\n ></span>\n </div>\n <span class=\"eds-mono-sm\">{{ item.value }}%</span>\n </div>\n }\n </div>\n </article>\n\n <article class=\"eds-card analytics-page__chart\">\n <div class=\"analytics-page__chart-head\">\n <h2 class=\"eds-h2\">Peak hours</h2>\n <span class=\"eds-label\">\n @if (data()!.peakHours.timezone) {\n {{ data()!.peakHours.timezone }}\n } @else {\n Calls per hour\n }\n </span>\n </div>\n <div class=\"analytics-page__volume-chart analytics-page__volume-chart--peak\">\n <div class=\"analytics-page__plot\">\n <div class=\"analytics-page__grid\" aria-hidden=\"true\"></div>\n <div class=\"analytics-page__bars analytics-page__bars--peak\" role=\"list\" aria-label=\"Call volume by hour\">\n @for (point of data()!.peakHours.points; track point.hour) {\n <div\n class=\"analytics-page__bar-col analytics-page__bar-col--peak\"\n role=\"listitem\"\n [attr.aria-label]=\"peakTooltip(point)\"\n >\n <div class=\"analytics-page__bar-wrap\">\n @if (point.count > 0) {\n <div\n class=\"analytics-page__bar-stack\"\n [style.height.%]=\"barHeightPercent(point, data()!.peakHours.points)\"\n >\n <div class=\"analytics-page__bar\"></div>\n </div>\n }\n <span class=\"analytics-page__tooltip\">{{ peakTooltip(point) }}</span>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n <div class=\"analytics-page__peak-axis\">\n @for (point of data()!.peakHours.points; track point.hour; let i = $index) {\n <span class=\"analytics-page__peak-tick eds-mono-sm\">\n @if (showPeakAxisLabel(i, data()!.peakHours.points.length)) {\n {{ point.label }}\n }\n </span>\n }\n </div>\n </article>\n </div>\n }\n</div>\n", styles: [".analytics-page__header{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;margin-bottom:20px}.analytics-page__range{display:flex;gap:4px;background:var(--eds-surface-l0);border:1px solid var(--eds-border-default);border-radius:var(--eds-radius-md);padding:4px}.analytics-page__range-btn{padding:6px 12px;border:none;background:none;font-size:13px;border-radius:var(--eds-radius-sm);cursor:pointer;color:var(--eds-text-secondary)}.analytics-page__range-btn--active{background:var(--eds-brand-500);color:#fff}.analytics-page__kpis{display:grid;grid-template-columns:repeat(4,1fr);gap:12px;margin-bottom:20px}.analytics-page__kpi{display:flex;flex-direction:column;gap:6px;padding:16px}.analytics-page__kpi-value{font-size:24px;font-weight:600;color:var(--eds-text-primary)}.analytics-page__kpi-delta{font-size:12px;font-weight:600}.analytics-page__kpi-delta[data-tone=pos]{color:var(--eds-green-500, #16a34a)}.analytics-page__kpi-delta[data-tone=warn]{color:var(--eds-amber-500, #d97706)}.analytics-page__kpi-delta[data-tone=neutral]{color:var(--eds-text-secondary)}.analytics-page__kpi-sub{font-size:12px;color:var(--eds-text-secondary)}.analytics-page__charts{display:grid;grid-template-columns:1fr 1fr;gap:16px}.analytics-page__chart{padding:16px}.analytics-page__chart .eds-h2{margin-bottom:0}.analytics-page__chart-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px;margin-bottom:16px;flex-wrap:wrap}.analytics-page__volume-chart--peak .analytics-page__grid{inset:0}.analytics-page__plot{position:relative;width:100%;min-width:0}.analytics-page__grid{position:absolute;inset:0 0 24px;pointer-events:none;background-image:linear-gradient(to top,var(--eds-border-default) 1px,transparent 1px);background-size:100% 25%;opacity:.45}.analytics-page__bars{display:flex;align-items:flex-end;justify-content:space-between;gap:8px;height:160px;position:relative;z-index:1}.analytics-page__bars--horizontal{flex-direction:column;height:auto;align-items:stretch;gap:10px}.analytics-page__bars--peak{height:100px}.analytics-page__bars--peak .analytics-page__bar{max-width:100%}.analytics-page__bar-col{flex:1;display:flex;flex-direction:column;align-items:center;gap:6px;height:100%;min-width:0;cursor:default}.analytics-page__bar-col:hover .analytics-page__tooltip,.analytics-page__bar-col:focus-within .analytics-page__tooltip{opacity:1}.analytics-page__bar-col--peak{min-width:0}.analytics-page__bar-value{flex-shrink:0;color:var(--eds-text-primary);font-size:11px;font-weight:600;line-height:1}.analytics-page__bar-wrap{position:relative;width:100%;flex:1;display:flex;flex-direction:column;justify-content:flex-end;align-items:center;min-height:0}.analytics-page__bar-stack{width:100%;max-width:32px;display:flex;flex-direction:column;justify-content:flex-end;align-items:stretch;gap:4px;min-height:0}.analytics-page__bar-axis{flex-shrink:0;min-height:16px;color:var(--eds-text-secondary);font-size:10px;text-align:center;line-height:1.2}.analytics-page__tooltip{position:absolute;bottom:calc(100% + 6px);left:50%;transform:translate(-50%);padding:4px 8px;background:var(--eds-gray-900, #18181b);color:#fafafa;font-size:11px;font-weight:500;line-height:1.3;border-radius:4px;white-space:nowrap;opacity:0;pointer-events:none;transition:opacity .15s ease;z-index:2;box-shadow:0 2px 8px #00000026}.analytics-page__tooltip:after{content:\"\";position:absolute;top:100%;left:50%;transform:translate(-50%);border:4px solid transparent;border-top-color:var(--eds-gray-900, #18181b)}.analytics-page__peak-axis{display:flex;justify-content:space-between;gap:2px;margin-top:8px}.analytics-page__peak-tick{flex:1;text-align:center;min-height:16px;color:var(--eds-text-secondary);font-size:10px}.analytics-page__bar{width:100%;flex:1 1 auto;min-height:3px;background:linear-gradient(180deg,var(--eds-brand-500),var(--eds-violet-500));border-radius:4px 4px 0 0;animation:eds-bar-grow .5s ease forwards;transform-origin:bottom}.analytics-page__hbar-row{display:grid;grid-template-columns:120px 1fr 40px;align-items:center;gap:10px}.analytics-page__hbar-track{height:8px;background:var(--eds-surface-l2);border-radius:4px;overflow:hidden}.analytics-page__hbar-fill{display:block;height:100%;background:var(--eds-brand-500);border-radius:4px;animation:eds-bar-grow .5s ease forwards;transform-origin:left}@media(max-width:1000px){.analytics-page__kpis{grid-template-columns:repeat(2,1fr)}.analytics-page__charts{grid-template-columns:1fr}}\n"] }]
|
|
110
|
-
}] });
|
|
111
|
-
|
|
112
|
-
export { AnalyticsPageComponent };
|
|
113
|
-
//# sourceMappingURL=edvak99-voice-receptionist-widget-analytics-page.component-Dsujn5az.mjs.map
|
package/fesm2022/edvak99-voice-receptionist-widget-analytics-page.component-Dsujn5az.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"edvak99-voice-receptionist-widget-analytics-page.component-Dsujn5az.mjs","sources":["../../../projects/voice-receptionist-widget/src/lib/pages/analytics-page/analytics-page.component.ts","../../../projects/voice-receptionist-widget/src/lib/pages/analytics-page/analytics-page.component.html"],"sourcesContent":["import { ChangeDetectionStrategy, Component, inject, OnInit, signal } from '@angular/core';\n\nimport {\n AnalyticsData,\n AnalyticsPeakPoint,\n AnalyticsVolumePoint,\n} from '../../models/ai-receptionist.types';\nimport { AiReceptionistApiService } from '../../services/ai-receptionist-api.service';\nimport { EdsIconComponent } from '../../ui/eds-icon.component';\n\n@Component({\n selector: 'eds-analytics-page',\n imports: [EdsIconComponent],\n templateUrl: './analytics-page.component.html',\n styleUrl: './analytics-page.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class AnalyticsPageComponent implements OnInit {\n private readonly api = inject(AiReceptionistApiService);\n\n protected readonly data = signal<AnalyticsData | null>(null);\n protected readonly range = signal('30d');\n protected readonly loading = signal(true);\n\n protected readonly ranges = [\n { id: '7d', label: '7 days' },\n { id: '30d', label: '30 days' },\n { id: '90d', label: '90 days' },\n ];\n\n ngOnInit(): void {\n this.load();\n }\n\n protected setRange(id: string): void {\n this.range.set(id);\n this.load();\n }\n\n protected maxCount(items: { count: number }[]): number {\n return Math.max(...items.map((i) => i.count), 1);\n }\n\n protected barHeightPercent(point: { count: number }, points: { count: number }[]): number {\n if (point.count <= 0) return 0;\n return (point.count / this.maxCount(points)) * 100;\n }\n\n /** Hide inline counts when bars are too narrow to stay readable. */\n protected showBarValue(point: { count: number }, points: { count: number }[]): boolean {\n return point.count > 0 && points.length <= 21;\n }\n\n protected maxValue(items: { value: number }[]): number {\n return Math.max(...items.map((i) => i.value), 1);\n }\n\n protected volumeTooltip(point: AnalyticsVolumePoint): string {\n const datePart = point.date ? this.formatChartDate(point.date) : point.label;\n return `${datePart}: ${point.count} call${point.count === 1 ? '' : 's'}`;\n }\n\n protected peakTooltip(point: AnalyticsPeakPoint): string {\n return `${point.label}: ${point.count} call${point.count === 1 ? '' : 's'}`;\n }\n\n /** ISO or YYYY-MM-DD → MM/DD (zero-padded). */\n protected formatChartDate(date: string): string {\n const iso = /^(\\d{4})-(\\d{2})-(\\d{2})/.exec(date.trim());\n if (iso) {\n return `${iso[2]}/${iso[3]}`;\n }\n return date;\n }\n\n /** Compact x-axis for volume — full labels on 7d, sparse dates on longer ranges. */\n protected volumeAxisLabel(point: AnalyticsVolumePoint, index: number, total: number): string {\n if (point.date) {\n if (total <= 7) return this.formatChartDate(point.date);\n const step = total <= 14 ? 2 : total <= 31 ? 5 : 7;\n if (index % step !== 0 && index !== total - 1) return '';\n return this.formatChartDate(point.date);\n }\n if (total <= 7) return point.day;\n const step = total <= 14 ? 2 : total <= 31 ? 5 : 7;\n if (index % step !== 0 && index !== total - 1) return '';\n return point.day;\n }\n\n protected showPeakAxisLabel(index: number, total: number): boolean {\n if (total <= 12) return true;\n const step = total <= 24 ? 3 : 4;\n return index % step === 0 || index === total - 1;\n }\n\n protected volumeRangeLabel(): string {\n const vol = this.data()?.volume;\n if (!vol?.startDate || !vol?.endDate) return 'Calls per day';\n const start = this.formatChartDate(vol.startDate);\n const end = this.formatChartDate(vol.endDate);\n return `${start} – ${end}${vol.timezone ? ` (${vol.timezone})` : ''}`;\n }\n\n protected kpiIcon(label: string): string {\n const key = label.toLowerCase();\n if (key.includes('call') || key.includes('handled')) return 'call';\n if (key.includes('time') || key.includes('duration')) return 'schedule';\n if (key.includes('resolution') || key.includes('book')) return 'event_available';\n if (key.includes('transfer')) return 'phone_forwarded';\n return 'monitoring';\n }\n\n private load(): void {\n this.loading.set(true);\n this.api.getAnalytics(this.range()).subscribe(({ data }) => {\n this.data.set(data);\n this.loading.set(false);\n });\n }\n}\n","<div class=\"eds-page analytics-page\">\n <header class=\"analytics-page__header\">\n <div>\n <h1 class=\"eds-h1\">Analytics</h1>\n <p class=\"eds-body-sm\">Call volume, outcomes, and performance KPIs</p>\n </div>\n <div class=\"analytics-page__range\">\n @for (r of ranges; track r.id) {\n <button\n type=\"button\"\n class=\"analytics-page__range-btn\"\n [class.analytics-page__range-btn--active]=\"range() === r.id\"\n (click)=\"setRange(r.id)\"\n >\n {{ r.label }}\n </button>\n }\n </div>\n </header>\n\n @if (loading()) {\n <p class=\"eds-body-sm\">Loading analytics…</p>\n } @else if (data()) {\n <section class=\"analytics-page__kpis\">\n @for (kpi of data()!.kpiCards; track kpi.label) {\n <article class=\"eds-card analytics-page__kpi\">\n <eds-icon [name]=\"kpiIcon(kpi.label)\" [size]=\"22\" />\n <span class=\"eds-label\">{{ kpi.label }}</span>\n <span class=\"analytics-page__kpi-value\">{{ kpi.value }}</span>\n @if (kpi.delta) {\n <span class=\"analytics-page__kpi-delta\" [attr.data-tone]=\"kpi.tone\">{{ kpi.delta }}</span>\n }\n @if (kpi.sub) {\n <span class=\"analytics-page__kpi-sub\">{{ kpi.sub }}</span>\n }\n </article>\n }\n </section>\n\n <div class=\"analytics-page__charts\">\n <article class=\"eds-card analytics-page__chart\">\n <div class=\"analytics-page__chart-head\">\n <h2 class=\"eds-h2\">Call volume</h2>\n <span class=\"eds-label\">{{ volumeRangeLabel() }}</span>\n </div>\n <div class=\"analytics-page__volume-chart\">\n <div class=\"analytics-page__plot\">\n <div class=\"analytics-page__grid\" aria-hidden=\"true\"></div>\n <div class=\"analytics-page__bars\" role=\"list\" aria-label=\"Call volume by day\">\n @for (point of data()!.volume.points; track point.date || point.label; let i = $index) {\n <div\n class=\"analytics-page__bar-col\"\n role=\"listitem\"\n [attr.aria-label]=\"volumeTooltip(point)\"\n >\n <div class=\"analytics-page__bar-wrap\">\n @if (point.count > 0) {\n <div\n class=\"analytics-page__bar-stack\"\n [style.height.%]=\"barHeightPercent(point, data()!.volume.points)\"\n >\n @if (showBarValue(point, data()!.volume.points)) {\n <span class=\"analytics-page__bar-value eds-mono-sm\">{{ point.count }}</span>\n }\n <div class=\"analytics-page__bar\"></div>\n </div>\n }\n <span class=\"analytics-page__tooltip\">{{ volumeTooltip(point) }}</span>\n </div>\n <span class=\"eds-mono-sm analytics-page__bar-axis\">\n {{ volumeAxisLabel(point, i, data()!.volume.points.length) }}\n </span>\n </div>\n }\n </div>\n </div>\n </div>\n <!-- <p class=\"analytics-page__axis-note eds-label\">(MM/DD)/calls per day</p> -->\n </article>\n\n <article class=\"eds-card analytics-page__chart\">\n <h2 class=\"eds-h2\">Outcomes</h2>\n <div class=\"analytics-page__bars analytics-page__bars--horizontal\">\n @for (item of data()!.outcomes; track item.label) {\n <div class=\"analytics-page__hbar-row\">\n <span class=\"eds-body-sm\">{{ item.label }}</span>\n <div class=\"analytics-page__hbar-track\">\n <span\n class=\"analytics-page__hbar-fill\"\n [style.width.%]=\"(item.value / maxValue(data()!.outcomes)) * 100\"\n [style.background]=\"item.color\"\n ></span>\n </div>\n <span class=\"eds-mono-sm\">{{ item.value }}%</span>\n </div>\n }\n </div>\n </article>\n\n <article class=\"eds-card analytics-page__chart\">\n <h2 class=\"eds-h2\">Top reasons</h2>\n <div class=\"analytics-page__bars analytics-page__bars--horizontal\">\n @for (item of data()!.reasons; track item.label) {\n <div class=\"analytics-page__hbar-row\">\n <span class=\"eds-body-sm\">{{ item.label }}</span>\n <div class=\"analytics-page__hbar-track\">\n <span\n class=\"analytics-page__hbar-fill\"\n [style.width.%]=\"(item.value / maxValue(data()!.reasons)) * 100\"\n ></span>\n </div>\n <span class=\"eds-mono-sm\">{{ item.value }}%</span>\n </div>\n }\n </div>\n </article>\n\n <article class=\"eds-card analytics-page__chart\">\n <div class=\"analytics-page__chart-head\">\n <h2 class=\"eds-h2\">Peak hours</h2>\n <span class=\"eds-label\">\n @if (data()!.peakHours.timezone) {\n {{ data()!.peakHours.timezone }}\n } @else {\n Calls per hour\n }\n </span>\n </div>\n <div class=\"analytics-page__volume-chart analytics-page__volume-chart--peak\">\n <div class=\"analytics-page__plot\">\n <div class=\"analytics-page__grid\" aria-hidden=\"true\"></div>\n <div class=\"analytics-page__bars analytics-page__bars--peak\" role=\"list\" aria-label=\"Call volume by hour\">\n @for (point of data()!.peakHours.points; track point.hour) {\n <div\n class=\"analytics-page__bar-col analytics-page__bar-col--peak\"\n role=\"listitem\"\n [attr.aria-label]=\"peakTooltip(point)\"\n >\n <div class=\"analytics-page__bar-wrap\">\n @if (point.count > 0) {\n <div\n class=\"analytics-page__bar-stack\"\n [style.height.%]=\"barHeightPercent(point, data()!.peakHours.points)\"\n >\n <div class=\"analytics-page__bar\"></div>\n </div>\n }\n <span class=\"analytics-page__tooltip\">{{ peakTooltip(point) }}</span>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n <div class=\"analytics-page__peak-axis\">\n @for (point of data()!.peakHours.points; track point.hour; let i = $index) {\n <span class=\"analytics-page__peak-tick eds-mono-sm\">\n @if (showPeakAxisLabel(i, data()!.peakHours.points.length)) {\n {{ point.label }}\n }\n </span>\n }\n </div>\n </article>\n </div>\n }\n</div>\n"],"names":[],"mappings":"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"}
|