@memberjunction/ng-explorer-core 5.44.0 → 5.45.1
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/dist/generated/lazy-feature-config.d.ts +1 -1
- package/dist/generated/lazy-feature-config.d.ts.map +1 -1
- package/dist/generated/lazy-feature-config.js +5 -1
- package/dist/generated/lazy-feature-config.js.map +1 -1
- package/dist/lib/resource-wrappers/chat-conversations-resource.component.d.ts +4 -3
- package/dist/lib/resource-wrappers/chat-conversations-resource.component.d.ts.map +1 -1
- package/dist/lib/resource-wrappers/chat-conversations-resource.component.js +21 -11
- package/dist/lib/resource-wrappers/chat-conversations-resource.component.js.map +1 -1
- package/dist/lib/shell/components/header/app-switcher.component.d.ts +6 -1
- package/dist/lib/shell/components/header/app-switcher.component.d.ts.map +1 -1
- package/dist/lib/shell/components/header/app-switcher.component.js +6 -3
- package/dist/lib/shell/components/header/app-switcher.component.js.map +1 -1
- package/dist/lib/user-notifications/user-notifications.component.d.ts +65 -9
- package/dist/lib/user-notifications/user-notifications.component.d.ts.map +1 -1
- package/dist/lib/user-notifications/user-notifications.component.js +453 -258
- package/dist/lib/user-notifications/user-notifications.component.js.map +1 -1
- package/dist/module.d.ts +33 -32
- package/dist/module.d.ts.map +1 -1
- package/dist/module.js +6 -2
- package/dist/module.js.map +1 -1
- package/package.json +49 -47
|
@@ -1,88 +1,102 @@
|
|
|
1
|
-
import { Component,
|
|
1
|
+
import { Component, ChangeDetectorRef, inject } from '@angular/core';
|
|
2
2
|
import { SharedService } from '@memberjunction/ng-shared';
|
|
3
3
|
import { MJUserNotificationEntity, UserInfoEngine } from '@memberjunction/core-entities';
|
|
4
|
-
import {
|
|
4
|
+
import { CompositeKey } from '@memberjunction/core';
|
|
5
5
|
import { SafeJSONParse, UUIDsEqual } from '@memberjunction/global';
|
|
6
6
|
import { MJNotificationService } from '@memberjunction/ng-notifications';
|
|
7
7
|
import { BaseAngularComponent } from '@memberjunction/ng-base-types';
|
|
8
8
|
import * as i0 from "@angular/core";
|
|
9
9
|
import * as i1 from "@memberjunction/ng-shared";
|
|
10
10
|
import * as i2 from "@memberjunction/ng-base-application";
|
|
11
|
-
import * as i3 from "@
|
|
12
|
-
import * as i4 from "@
|
|
13
|
-
import * as i5 from "@
|
|
14
|
-
|
|
15
|
-
const _c1 = ["unreadRadio"];
|
|
16
|
-
const _c2 = ["readRadio"];
|
|
11
|
+
import * as i3 from "@memberjunction/ng-markdown";
|
|
12
|
+
import * as i4 from "@angular/forms";
|
|
13
|
+
import * as i5 from "@memberjunction/ng-ui-components";
|
|
14
|
+
import * as i6 from "@angular/common";
|
|
17
15
|
const _forTrack0 = ($index, $item) => $item.ID;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
i0.ɵɵ
|
|
22
|
-
i0.ɵɵ
|
|
23
|
-
i0.ɵɵ
|
|
16
|
+
const _forTrack1 = ($index, $item) => $item.Key;
|
|
17
|
+
const _forTrack2 = ($index, $item) => $item.N.ID;
|
|
18
|
+
function UserNotificationsComponent_Conditional_9_Template(rf, ctx) { if (rf & 1) {
|
|
19
|
+
i0.ɵɵelementStart(0, "span", 7);
|
|
20
|
+
i0.ɵɵtext(1);
|
|
21
|
+
i0.ɵɵelementEnd();
|
|
22
|
+
} if (rf & 2) {
|
|
23
|
+
const ctx_r0 = i0.ɵɵnextContext();
|
|
24
|
+
i0.ɵɵadvance();
|
|
25
|
+
i0.ɵɵtextInterpolate1("", ctx_r0.UnreadNotifications.length, " unread");
|
|
26
|
+
} }
|
|
27
|
+
function UserNotificationsComponent_Conditional_10_Template(rf, ctx) { if (rf & 1) {
|
|
28
|
+
i0.ɵɵelementStart(0, "span", 7);
|
|
29
|
+
i0.ɵɵtext(1, "All caught up");
|
|
30
|
+
i0.ɵɵelementEnd();
|
|
31
|
+
} }
|
|
32
|
+
function UserNotificationsComponent_Conditional_11_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
33
|
+
const _r2 = i0.ɵɵgetCurrentView();
|
|
34
|
+
i0.ɵɵelementStart(0, "button", 16);
|
|
35
|
+
i0.ɵɵlistener("click", function UserNotificationsComponent_Conditional_11_Conditional_1_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.markAllAsRead()); });
|
|
36
|
+
i0.ɵɵelement(1, "i", 17);
|
|
37
|
+
i0.ɵɵelementStart(2, "span", 18);
|
|
24
38
|
i0.ɵɵtext(3, "Mark All Read");
|
|
25
39
|
i0.ɵɵelementEnd()();
|
|
26
40
|
} }
|
|
27
|
-
function
|
|
41
|
+
function UserNotificationsComponent_Conditional_11_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
28
42
|
const _r3 = i0.ɵɵgetCurrentView();
|
|
29
|
-
i0.ɵɵelementStart(0, "button",
|
|
30
|
-
i0.ɵɵlistener("click", function
|
|
31
|
-
i0.ɵɵelement(1, "i",
|
|
32
|
-
i0.ɵɵelementStart(2, "span",
|
|
43
|
+
i0.ɵɵelementStart(0, "button", 19);
|
|
44
|
+
i0.ɵɵlistener("click", function UserNotificationsComponent_Conditional_11_Conditional_2_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.markAllAsUnread()); });
|
|
45
|
+
i0.ɵɵelement(1, "i", 20);
|
|
46
|
+
i0.ɵɵelementStart(2, "span", 18);
|
|
33
47
|
i0.ɵɵtext(3, "Mark All Unread");
|
|
34
48
|
i0.ɵɵelementEnd()();
|
|
35
49
|
} }
|
|
36
|
-
function
|
|
37
|
-
i0.ɵɵelementStart(0, "div",
|
|
38
|
-
i0.ɵɵconditionalCreate(1,
|
|
39
|
-
i0.ɵɵconditionalCreate(2,
|
|
50
|
+
function UserNotificationsComponent_Conditional_11_Template(rf, ctx) { if (rf & 1) {
|
|
51
|
+
i0.ɵɵelementStart(0, "div", 8);
|
|
52
|
+
i0.ɵɵconditionalCreate(1, UserNotificationsComponent_Conditional_11_Conditional_1_Template, 4, 0, "button", 14);
|
|
53
|
+
i0.ɵɵconditionalCreate(2, UserNotificationsComponent_Conditional_11_Conditional_2_Template, 4, 0, "button", 15);
|
|
40
54
|
i0.ɵɵelementEnd();
|
|
41
55
|
} if (rf & 2) {
|
|
42
|
-
const
|
|
56
|
+
const ctx_r0 = i0.ɵɵnextContext();
|
|
43
57
|
i0.ɵɵadvance();
|
|
44
|
-
i0.ɵɵconditional(
|
|
58
|
+
i0.ɵɵconditional(ctx_r0.UnreadNotifications.length > 0 ? 1 : -1);
|
|
45
59
|
i0.ɵɵadvance();
|
|
46
|
-
i0.ɵɵconditional(
|
|
60
|
+
i0.ɵɵconditional(ctx_r0.ReadNotifications.length > 0 ? 2 : -1);
|
|
47
61
|
} }
|
|
48
|
-
function
|
|
62
|
+
function UserNotificationsComponent_Conditional_12_Conditional_9_Template(rf, ctx) { if (rf & 1) {
|
|
49
63
|
const _r5 = i0.ɵɵgetCurrentView();
|
|
50
|
-
i0.ɵɵelementStart(0, "button",
|
|
51
|
-
i0.ɵɵlistener("click", function
|
|
52
|
-
i0.ɵɵelementStart(1, "span",
|
|
64
|
+
i0.ɵɵelementStart(0, "button", 35);
|
|
65
|
+
i0.ɵɵlistener("click", function UserNotificationsComponent_Conditional_12_Conditional_9_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r5); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.selectReadOption("Unread")); });
|
|
66
|
+
i0.ɵɵelementStart(1, "span", 25);
|
|
53
67
|
i0.ɵɵtext(2, "Unread");
|
|
54
68
|
i0.ɵɵelementEnd();
|
|
55
|
-
i0.ɵɵelementStart(3, "span",
|
|
69
|
+
i0.ɵɵelementStart(3, "span", 26);
|
|
56
70
|
i0.ɵɵtext(4);
|
|
57
71
|
i0.ɵɵelementEnd()();
|
|
58
72
|
} if (rf & 2) {
|
|
59
|
-
const
|
|
60
|
-
i0.ɵɵclassProp("active",
|
|
61
|
-
i0.ɵɵattribute("aria-pressed",
|
|
73
|
+
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
74
|
+
i0.ɵɵclassProp("active", ctx_r0.radioSelected === "Unread")("has-unread", ctx_r0.UnreadNotifications.length > 0);
|
|
75
|
+
i0.ɵɵattribute("aria-pressed", ctx_r0.radioSelected === "Unread");
|
|
62
76
|
i0.ɵɵadvance(3);
|
|
63
|
-
i0.ɵɵclassProp("unread-count",
|
|
77
|
+
i0.ɵɵclassProp("unread-count", ctx_r0.UnreadNotifications.length > 0);
|
|
64
78
|
i0.ɵɵadvance();
|
|
65
|
-
i0.ɵɵtextInterpolate1(" ",
|
|
79
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r0.UnreadNotifications.length, " ");
|
|
66
80
|
} }
|
|
67
|
-
function
|
|
81
|
+
function UserNotificationsComponent_Conditional_12_Conditional_10_Template(rf, ctx) { if (rf & 1) {
|
|
68
82
|
const _r6 = i0.ɵɵgetCurrentView();
|
|
69
|
-
i0.ɵɵelementStart(0, "button",
|
|
70
|
-
i0.ɵɵlistener("click", function
|
|
71
|
-
i0.ɵɵelementStart(1, "span",
|
|
83
|
+
i0.ɵɵelementStart(0, "button", 36);
|
|
84
|
+
i0.ɵɵlistener("click", function UserNotificationsComponent_Conditional_12_Conditional_10_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r6); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.selectReadOption("Read")); });
|
|
85
|
+
i0.ɵɵelementStart(1, "span", 25);
|
|
72
86
|
i0.ɵɵtext(2, "Read");
|
|
73
87
|
i0.ɵɵelementEnd();
|
|
74
|
-
i0.ɵɵelementStart(3, "span",
|
|
88
|
+
i0.ɵɵelementStart(3, "span", 26);
|
|
75
89
|
i0.ɵɵtext(4);
|
|
76
90
|
i0.ɵɵelementEnd()();
|
|
77
91
|
} if (rf & 2) {
|
|
78
|
-
const
|
|
79
|
-
i0.ɵɵclassProp("active",
|
|
80
|
-
i0.ɵɵattribute("aria-pressed",
|
|
92
|
+
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
93
|
+
i0.ɵɵclassProp("active", ctx_r0.radioSelected === "Read");
|
|
94
|
+
i0.ɵɵattribute("aria-pressed", ctx_r0.radioSelected === "Read");
|
|
81
95
|
i0.ɵɵadvance(4);
|
|
82
|
-
i0.ɵɵtextInterpolate(
|
|
96
|
+
i0.ɵɵtextInterpolate(ctx_r0.ReadNotifications.length);
|
|
83
97
|
} }
|
|
84
|
-
function
|
|
85
|
-
i0.ɵɵelementStart(0, "option",
|
|
98
|
+
function UserNotificationsComponent_Conditional_12_Conditional_11_For_5_Template(rf, ctx) { if (rf & 1) {
|
|
99
|
+
i0.ɵɵelementStart(0, "option", 38);
|
|
86
100
|
i0.ɵɵtext(1);
|
|
87
101
|
i0.ɵɵelementEnd();
|
|
88
102
|
} if (rf & 2) {
|
|
@@ -91,189 +105,281 @@ function UserNotificationsComponent_Conditional_9_Conditional_17_For_5_Template(
|
|
|
91
105
|
i0.ɵɵadvance();
|
|
92
106
|
i0.ɵɵtextInterpolate(type_r8.Name);
|
|
93
107
|
} }
|
|
94
|
-
function
|
|
108
|
+
function UserNotificationsComponent_Conditional_12_Conditional_11_Template(rf, ctx) { if (rf & 1) {
|
|
95
109
|
const _r7 = i0.ɵɵgetCurrentView();
|
|
96
|
-
i0.ɵɵelementStart(0, "div",
|
|
97
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
98
|
-
i0.ɵɵlistener("change", function
|
|
99
|
-
i0.ɵɵelementStart(2, "option",
|
|
110
|
+
i0.ɵɵelementStart(0, "div", 29)(1, "select", 37);
|
|
111
|
+
i0.ɵɵtwoWayListener("ngModelChange", function UserNotificationsComponent_Conditional_12_Conditional_11_Template_select_ngModelChange_1_listener($event) { i0.ɵɵrestoreView(_r7); const ctx_r0 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r0.selectedTypeFilter, $event) || (ctx_r0.selectedTypeFilter = $event); return i0.ɵɵresetView($event); });
|
|
112
|
+
i0.ɵɵlistener("change", function UserNotificationsComponent_Conditional_12_Conditional_11_Template_select_change_1_listener() { i0.ɵɵrestoreView(_r7); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.onTypeFilterChange(ctx_r0.selectedTypeFilter)); });
|
|
113
|
+
i0.ɵɵelementStart(2, "option", 38);
|
|
100
114
|
i0.ɵɵtext(3, "All Types");
|
|
101
115
|
i0.ɵɵelementEnd();
|
|
102
|
-
i0.ɵɵrepeaterCreate(4,
|
|
116
|
+
i0.ɵɵrepeaterCreate(4, UserNotificationsComponent_Conditional_12_Conditional_11_For_5_Template, 2, 2, "option", 38, _forTrack0);
|
|
103
117
|
i0.ɵɵelementEnd()();
|
|
104
118
|
} if (rf & 2) {
|
|
105
|
-
const
|
|
119
|
+
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
106
120
|
i0.ɵɵadvance();
|
|
107
|
-
i0.ɵɵtwoWayProperty("ngModel",
|
|
121
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r0.selectedTypeFilter);
|
|
108
122
|
i0.ɵɵadvance();
|
|
109
123
|
i0.ɵɵproperty("value", null);
|
|
110
124
|
i0.ɵɵadvance(2);
|
|
111
|
-
i0.ɵɵrepeater(
|
|
125
|
+
i0.ɵɵrepeater(ctx_r0.notificationTypes);
|
|
112
126
|
} }
|
|
113
|
-
function
|
|
114
|
-
i0.ɵɵelementStart(0, "div",
|
|
115
|
-
i0.ɵɵelement(2, "i",
|
|
127
|
+
function UserNotificationsComponent_Conditional_12_Conditional_16_Template(rf, ctx) { if (rf & 1) {
|
|
128
|
+
i0.ɵɵelementStart(0, "div", 34)(1, "span", 39);
|
|
129
|
+
i0.ɵɵelement(2, "i", 40);
|
|
116
130
|
i0.ɵɵtext(3);
|
|
117
131
|
i0.ɵɵelementEnd()();
|
|
118
132
|
} if (rf & 2) {
|
|
119
|
-
const
|
|
133
|
+
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
120
134
|
i0.ɵɵadvance(3);
|
|
121
|
-
i0.ɵɵtextInterpolate2(" Showing ",
|
|
135
|
+
i0.ɵɵtextInterpolate2(" Showing ", ctx_r0.NotificationsToShow.length, " of ", ctx_r0.AllNotifications.length, " ");
|
|
122
136
|
} }
|
|
123
|
-
function
|
|
137
|
+
function UserNotificationsComponent_Conditional_12_Template(rf, ctx) { if (rf & 1) {
|
|
124
138
|
const _r4 = i0.ɵɵgetCurrentView();
|
|
125
|
-
i0.ɵɵelementStart(0, "div",
|
|
126
|
-
i0.ɵɵlistener("
|
|
127
|
-
i0.ɵɵ
|
|
128
|
-
i0.ɵɵ
|
|
129
|
-
i0.ɵɵlistener("click", function UserNotificationsComponent_Conditional_9_Template_button_click_6_listener() { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.selectReadOption("All")); });
|
|
130
|
-
i0.ɵɵelementStart(7, "span", 27);
|
|
131
|
-
i0.ɵɵtext(8, "All");
|
|
139
|
+
i0.ɵɵelementStart(0, "div", 9)(1, "div", 21)(2, "div", 22)(3, "div", 23)(4, "button", 24);
|
|
140
|
+
i0.ɵɵlistener("click", function UserNotificationsComponent_Conditional_12_Template_button_click_4_listener() { i0.ɵɵrestoreView(_r4); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.selectReadOption("All")); });
|
|
141
|
+
i0.ɵɵelementStart(5, "span", 25);
|
|
142
|
+
i0.ɵɵtext(6, "All");
|
|
132
143
|
i0.ɵɵelementEnd();
|
|
133
|
-
i0.ɵɵelementStart(
|
|
134
|
-
i0.ɵɵtext(
|
|
144
|
+
i0.ɵɵelementStart(7, "span", 26);
|
|
145
|
+
i0.ɵɵtext(8);
|
|
135
146
|
i0.ɵɵelementEnd()();
|
|
136
|
-
i0.ɵɵ
|
|
137
|
-
i0.ɵɵ
|
|
147
|
+
i0.ɵɵconditionalCreate(9, UserNotificationsComponent_Conditional_12_Conditional_9_Template, 5, 8, "button", 27);
|
|
148
|
+
i0.ɵɵconditionalCreate(10, UserNotificationsComponent_Conditional_12_Conditional_10_Template, 5, 4, "button", 28);
|
|
138
149
|
i0.ɵɵelementEnd();
|
|
139
|
-
i0.ɵɵconditionalCreate(
|
|
140
|
-
i0.ɵɵelementStart(14, "input", 31, 2);
|
|
141
|
-
i0.ɵɵlistener("change", function UserNotificationsComponent_Conditional_9_Template_input_change_14_listener($event) { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onReadRadioChanged($event)); });
|
|
142
|
-
i0.ɵɵelementEnd();
|
|
143
|
-
i0.ɵɵconditionalCreate(16, UserNotificationsComponent_Conditional_9_Conditional_16_Template, 5, 4, "button", 32);
|
|
144
|
-
i0.ɵɵelementEnd();
|
|
145
|
-
i0.ɵɵconditionalCreate(17, UserNotificationsComponent_Conditional_9_Conditional_17_Template, 6, 2, "div", 33);
|
|
150
|
+
i0.ɵɵconditionalCreate(11, UserNotificationsComponent_Conditional_12_Conditional_11_Template, 6, 2, "div", 29);
|
|
146
151
|
i0.ɵɵelementEnd()();
|
|
147
|
-
i0.ɵɵelementStart(
|
|
148
|
-
i0.ɵɵelement(
|
|
149
|
-
i0.ɵɵelementStart(
|
|
150
|
-
i0.ɵɵlistener("input", function
|
|
152
|
+
i0.ɵɵelementStart(12, "div", 30)(13, "div", 31);
|
|
153
|
+
i0.ɵɵelement(14, "i", 32);
|
|
154
|
+
i0.ɵɵelementStart(15, "input", 33);
|
|
155
|
+
i0.ɵɵlistener("input", function UserNotificationsComponent_Conditional_12_Template_input_input_15_listener($event) { i0.ɵɵrestoreView(_r4); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onFilterChanged($event.target.value)); });
|
|
151
156
|
i0.ɵɵelementEnd()()();
|
|
152
|
-
i0.ɵɵconditionalCreate(
|
|
157
|
+
i0.ɵɵconditionalCreate(16, UserNotificationsComponent_Conditional_12_Conditional_16_Template, 4, 2, "div", 34);
|
|
153
158
|
i0.ɵɵelementEnd();
|
|
154
159
|
} if (rf & 2) {
|
|
155
|
-
const
|
|
156
|
-
i0.ɵɵadvance(6);
|
|
157
|
-
i0.ɵɵclassProp("active", ctx_r1.radioSelected === "All");
|
|
158
|
-
i0.ɵɵattribute("aria-pressed", ctx_r1.radioSelected === "All");
|
|
160
|
+
const ctx_r0 = i0.ɵɵnextContext();
|
|
159
161
|
i0.ɵɵadvance(4);
|
|
160
|
-
i0.ɵɵ
|
|
161
|
-
i0.ɵɵ
|
|
162
|
-
i0.ɵɵ
|
|
163
|
-
i0.ɵɵ
|
|
164
|
-
i0.ɵɵ
|
|
162
|
+
i0.ɵɵclassProp("active", ctx_r0.radioSelected === "All");
|
|
163
|
+
i0.ɵɵattribute("aria-pressed", ctx_r0.radioSelected === "All");
|
|
164
|
+
i0.ɵɵadvance(4);
|
|
165
|
+
i0.ɵɵtextInterpolate(ctx_r0.AllNotifications.length);
|
|
166
|
+
i0.ɵɵadvance();
|
|
167
|
+
i0.ɵɵconditional(ctx_r0.UnreadNotifications.length > 0 || ctx_r0.ReadNotifications.length === 0 ? 9 : -1);
|
|
165
168
|
i0.ɵɵadvance();
|
|
166
|
-
i0.ɵɵconditional(
|
|
169
|
+
i0.ɵɵconditional(ctx_r0.ReadNotifications.length > 0 || ctx_r0.UnreadNotifications.length === 0 ? 10 : -1);
|
|
170
|
+
i0.ɵɵadvance();
|
|
171
|
+
i0.ɵɵconditional(ctx_r0.notificationTypes.length > 0 ? 11 : -1);
|
|
167
172
|
i0.ɵɵadvance(4);
|
|
168
|
-
i0.ɵɵproperty("value",
|
|
173
|
+
i0.ɵɵproperty("value", ctx_r0.currentFilter);
|
|
169
174
|
i0.ɵɵadvance();
|
|
170
|
-
i0.ɵɵconditional(
|
|
175
|
+
i0.ɵɵconditional(ctx_r0.NotificationsToShow.length !== ctx_r0.AllNotifications.length ? 16 : -1);
|
|
171
176
|
} }
|
|
172
|
-
function
|
|
177
|
+
function UserNotificationsComponent_Conditional_14_Template(rf, ctx) { if (rf & 1) {
|
|
178
|
+
i0.ɵɵelement(0, "mj-empty-state", 11);
|
|
179
|
+
} }
|
|
180
|
+
function UserNotificationsComponent_Conditional_15_Template(rf, ctx) { if (rf & 1) {
|
|
173
181
|
i0.ɵɵelement(0, "mj-empty-state", 12);
|
|
174
182
|
} }
|
|
175
|
-
function
|
|
176
|
-
i0.ɵɵ
|
|
183
|
+
function UserNotificationsComponent_Conditional_16_For_2_For_3_Conditional_10_Template(rf, ctx) { if (rf & 1) {
|
|
184
|
+
i0.ɵɵtext(0);
|
|
185
|
+
} if (rf & 2) {
|
|
186
|
+
const vm_r10 = i0.ɵɵnextContext().$implicit;
|
|
187
|
+
i0.ɵɵtextInterpolate1(" ", vm_r10.Relative, " ");
|
|
188
|
+
} }
|
|
189
|
+
function UserNotificationsComponent_Conditional_16_For_2_For_3_Conditional_11_Template(rf, ctx) { if (rf & 1) {
|
|
190
|
+
i0.ɵɵelementStart(0, "time");
|
|
191
|
+
i0.ɵɵtext(1);
|
|
192
|
+
i0.ɵɵpipe(2, "date");
|
|
193
|
+
i0.ɵɵelementEnd();
|
|
194
|
+
} if (rf & 2) {
|
|
195
|
+
const vm_r10 = i0.ɵɵnextContext().$implicit;
|
|
196
|
+
i0.ɵɵattribute("datetime", vm_r10.N.__mj_CreatedAt);
|
|
197
|
+
i0.ɵɵadvance();
|
|
198
|
+
i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(2, 2, vm_r10.N.__mj_CreatedAt, "MMM d, h:mm a"));
|
|
177
199
|
} }
|
|
178
|
-
function
|
|
200
|
+
function UserNotificationsComponent_Conditional_16_For_2_For_3_Conditional_15_Template(rf, ctx) { if (rf & 1) {
|
|
201
|
+
i0.ɵɵelementStart(0, "span", 52);
|
|
202
|
+
i0.ɵɵelement(1, "i", 59);
|
|
203
|
+
i0.ɵɵtext(2, " Open ");
|
|
204
|
+
i0.ɵɵelementEnd();
|
|
205
|
+
} }
|
|
206
|
+
function UserNotificationsComponent_Conditional_16_For_2_For_3_Conditional_16_Template(rf, ctx) { if (rf & 1) {
|
|
207
|
+
i0.ɵɵelementStart(0, "p", 53);
|
|
208
|
+
i0.ɵɵtext(1);
|
|
209
|
+
i0.ɵɵelementEnd();
|
|
210
|
+
} if (rf & 2) {
|
|
211
|
+
const vm_r10 = i0.ɵɵnextContext().$implicit;
|
|
212
|
+
i0.ɵɵadvance();
|
|
213
|
+
i0.ɵɵtextInterpolate(vm_r10.Preview);
|
|
214
|
+
} }
|
|
215
|
+
function UserNotificationsComponent_Conditional_16_For_2_For_3_Conditional_17_Case_1_Template(rf, ctx) { if (rf & 1) {
|
|
216
|
+
i0.ɵɵelement(0, "div", 61);
|
|
217
|
+
} if (rf & 2) {
|
|
218
|
+
const vm_r10 = i0.ɵɵnextContext(2).$implicit;
|
|
219
|
+
i0.ɵɵproperty("innerHTML", vm_r10.Body, i0.ɵɵsanitizeHtml);
|
|
220
|
+
} }
|
|
221
|
+
function UserNotificationsComponent_Conditional_16_For_2_For_3_Conditional_17_Case_2_Template(rf, ctx) { if (rf & 1) {
|
|
222
|
+
i0.ɵɵelement(0, "mj-markdown", 62);
|
|
223
|
+
} if (rf & 2) {
|
|
224
|
+
const vm_r10 = i0.ɵɵnextContext(2).$implicit;
|
|
225
|
+
i0.ɵɵproperty("data", vm_r10.Body)("enableMermaid", false);
|
|
226
|
+
} }
|
|
227
|
+
function UserNotificationsComponent_Conditional_16_For_2_For_3_Conditional_17_Case_3_Template(rf, ctx) { if (rf & 1) {
|
|
228
|
+
i0.ɵɵelementStart(0, "p", 63);
|
|
229
|
+
i0.ɵɵtext(1);
|
|
230
|
+
i0.ɵɵelementEnd();
|
|
231
|
+
} if (rf & 2) {
|
|
232
|
+
const vm_r10 = i0.ɵɵnextContext(2).$implicit;
|
|
233
|
+
i0.ɵɵadvance();
|
|
234
|
+
i0.ɵɵtextInterpolate(vm_r10.N.Message);
|
|
235
|
+
} }
|
|
236
|
+
function UserNotificationsComponent_Conditional_16_For_2_For_3_Conditional_17_Template(rf, ctx) { if (rf & 1) {
|
|
179
237
|
const _r11 = i0.ɵɵgetCurrentView();
|
|
180
|
-
i0.ɵɵelementStart(0, "
|
|
181
|
-
i0.ɵɵlistener("click", function
|
|
182
|
-
i0.ɵɵ
|
|
183
|
-
i0.ɵɵ
|
|
238
|
+
i0.ɵɵelementStart(0, "div", 60);
|
|
239
|
+
i0.ɵɵlistener("click", function UserNotificationsComponent_Conditional_16_For_2_For_3_Conditional_17_Template_div_click_0_listener($event) { i0.ɵɵrestoreView(_r11); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
240
|
+
i0.ɵɵconditionalCreate(1, UserNotificationsComponent_Conditional_16_For_2_For_3_Conditional_17_Case_1_Template, 1, 1, "div", 61)(2, UserNotificationsComponent_Conditional_16_For_2_For_3_Conditional_17_Case_2_Template, 1, 2, "mj-markdown", 62)(3, UserNotificationsComponent_Conditional_16_For_2_For_3_Conditional_17_Case_3_Template, 2, 1, "p", 63);
|
|
241
|
+
i0.ɵɵelementEnd();
|
|
242
|
+
} if (rf & 2) {
|
|
243
|
+
let tmp_22_0;
|
|
244
|
+
const vm_r10 = i0.ɵɵnextContext().$implicit;
|
|
245
|
+
i0.ɵɵadvance();
|
|
246
|
+
i0.ɵɵconditional((tmp_22_0 = vm_r10.Kind) === "html" ? 1 : tmp_22_0 === "markdown" ? 2 : 3);
|
|
247
|
+
} }
|
|
248
|
+
function UserNotificationsComponent_Conditional_16_For_2_For_3_Conditional_18_Template(rf, ctx) { if (rf & 1) {
|
|
249
|
+
const _r12 = i0.ɵɵgetCurrentView();
|
|
250
|
+
i0.ɵɵelementStart(0, "button", 64);
|
|
251
|
+
i0.ɵɵlistener("click", function UserNotificationsComponent_Conditional_16_For_2_For_3_Conditional_18_Template_button_click_0_listener($event) { i0.ɵɵrestoreView(_r12); const vm_r10 = i0.ɵɵnextContext().$implicit; const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.ToggleExpanded(vm_r10, $event)); });
|
|
252
|
+
i0.ɵɵelement(1, "i", 65);
|
|
253
|
+
i0.ɵɵtext(2);
|
|
254
|
+
i0.ɵɵelementEnd();
|
|
255
|
+
} if (rf & 2) {
|
|
256
|
+
const vm_r10 = i0.ɵɵnextContext().$implicit;
|
|
257
|
+
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
258
|
+
i0.ɵɵattribute("aria-expanded", ctx_r0.IsExpanded(vm_r10));
|
|
259
|
+
i0.ɵɵadvance();
|
|
260
|
+
i0.ɵɵclassProp("fa-chevron-down", !ctx_r0.IsExpanded(vm_r10))("fa-chevron-up", ctx_r0.IsExpanded(vm_r10));
|
|
261
|
+
i0.ɵɵadvance();
|
|
262
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r0.IsExpanded(vm_r10) ? "Show less" : "Show more", " ");
|
|
263
|
+
} }
|
|
264
|
+
function UserNotificationsComponent_Conditional_16_For_2_For_3_Conditional_20_Template(rf, ctx) { if (rf & 1) {
|
|
265
|
+
const _r13 = i0.ɵɵgetCurrentView();
|
|
266
|
+
i0.ɵɵelementStart(0, "button", 66);
|
|
267
|
+
i0.ɵɵlistener("click", function UserNotificationsComponent_Conditional_16_For_2_For_3_Conditional_20_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r13); const vm_r10 = i0.ɵɵnextContext().$implicit; const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.markAsRead(vm_r10.N, true, null)); });
|
|
268
|
+
i0.ɵɵelement(1, "i", 67);
|
|
269
|
+
i0.ɵɵelementStart(2, "span", 68);
|
|
184
270
|
i0.ɵɵtext(3, "Read");
|
|
185
271
|
i0.ɵɵelementEnd()();
|
|
186
272
|
} if (rf & 2) {
|
|
187
|
-
const
|
|
188
|
-
i0.ɵɵattribute("aria-label", "Mark " +
|
|
273
|
+
const vm_r10 = i0.ɵɵnextContext().$implicit;
|
|
274
|
+
i0.ɵɵattribute("aria-label", "Mark " + vm_r10.N.Title + " as read");
|
|
189
275
|
} }
|
|
190
|
-
function
|
|
191
|
-
const
|
|
192
|
-
i0.ɵɵelementStart(0, "button",
|
|
193
|
-
i0.ɵɵlistener("click", function
|
|
194
|
-
i0.ɵɵelement(1, "i",
|
|
195
|
-
i0.ɵɵelementStart(2, "span",
|
|
276
|
+
function UserNotificationsComponent_Conditional_16_For_2_For_3_Conditional_21_Template(rf, ctx) { if (rf & 1) {
|
|
277
|
+
const _r14 = i0.ɵɵgetCurrentView();
|
|
278
|
+
i0.ɵɵelementStart(0, "button", 69);
|
|
279
|
+
i0.ɵɵlistener("click", function UserNotificationsComponent_Conditional_16_For_2_For_3_Conditional_21_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r14); const vm_r10 = i0.ɵɵnextContext().$implicit; const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.markAsRead(vm_r10.N, false, null)); });
|
|
280
|
+
i0.ɵɵelement(1, "i", 20);
|
|
281
|
+
i0.ɵɵelementStart(2, "span", 68);
|
|
196
282
|
i0.ɵɵtext(3, "Unread");
|
|
197
283
|
i0.ɵɵelementEnd()();
|
|
198
284
|
} if (rf & 2) {
|
|
199
|
-
const
|
|
200
|
-
i0.ɵɵattribute("aria-label", "Mark " +
|
|
285
|
+
const vm_r10 = i0.ɵɵnextContext().$implicit;
|
|
286
|
+
i0.ɵɵattribute("aria-label", "Mark " + vm_r10.N.Title + " as unread");
|
|
201
287
|
} }
|
|
202
|
-
function
|
|
288
|
+
function UserNotificationsComponent_Conditional_16_For_2_For_3_Template(rf, ctx) { if (rf & 1) {
|
|
203
289
|
const _r9 = i0.ɵɵgetCurrentView();
|
|
204
|
-
i0.ɵɵelementStart(0, "article",
|
|
205
|
-
i0.ɵɵelement(1, "div",
|
|
206
|
-
i0.ɵɵelementStart(2, "div",
|
|
290
|
+
i0.ɵɵelementStart(0, "article", 43);
|
|
291
|
+
i0.ɵɵelement(1, "div", 44);
|
|
292
|
+
i0.ɵɵelementStart(2, "div", 45);
|
|
207
293
|
i0.ɵɵelement(3, "i");
|
|
208
294
|
i0.ɵɵelementEnd();
|
|
209
|
-
i0.ɵɵelementStart(4, "div",
|
|
210
|
-
i0.ɵɵlistener("click", function
|
|
211
|
-
i0.ɵɵelementStart(5, "div",
|
|
295
|
+
i0.ɵɵelementStart(4, "div", 46);
|
|
296
|
+
i0.ɵɵlistener("click", function UserNotificationsComponent_Conditional_16_For_2_For_3_Template_div_click_4_listener() { const vm_r10 = i0.ɵɵrestoreView(_r9).$implicit; const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.notificationClicked(vm_r10.N)); });
|
|
297
|
+
i0.ɵɵelementStart(5, "div", 47)(6, "h3", 48);
|
|
212
298
|
i0.ɵɵtext(7);
|
|
213
299
|
i0.ɵɵelementEnd();
|
|
214
|
-
i0.ɵɵelementStart(8, "span",
|
|
215
|
-
i0.ɵɵ
|
|
216
|
-
i0.ɵɵ
|
|
217
|
-
i0.ɵɵtext(11);
|
|
218
|
-
i0.ɵɵpipe(12, "date");
|
|
219
|
-
i0.ɵɵelementEnd()()();
|
|
220
|
-
i0.ɵɵelementStart(13, "div", 54)(14, "span", 55);
|
|
221
|
-
i0.ɵɵtext(15);
|
|
300
|
+
i0.ɵɵelementStart(8, "span", 49);
|
|
301
|
+
i0.ɵɵpipe(9, "date");
|
|
302
|
+
i0.ɵɵconditionalCreate(10, UserNotificationsComponent_Conditional_16_For_2_For_3_Conditional_10_Template, 1, 1)(11, UserNotificationsComponent_Conditional_16_For_2_For_3_Conditional_11_Template, 3, 5, "time");
|
|
222
303
|
i0.ɵɵelementEnd()();
|
|
223
|
-
i0.ɵɵelementStart(
|
|
224
|
-
i0.ɵɵtext(
|
|
225
|
-
i0.ɵɵelementEnd()
|
|
226
|
-
i0.ɵɵ
|
|
227
|
-
i0.ɵɵ
|
|
304
|
+
i0.ɵɵelementStart(12, "div", 50)(13, "span", 51);
|
|
305
|
+
i0.ɵɵtext(14);
|
|
306
|
+
i0.ɵɵelementEnd();
|
|
307
|
+
i0.ɵɵconditionalCreate(15, UserNotificationsComponent_Conditional_16_For_2_For_3_Conditional_15_Template, 3, 0, "span", 52);
|
|
308
|
+
i0.ɵɵelementEnd();
|
|
309
|
+
i0.ɵɵconditionalCreate(16, UserNotificationsComponent_Conditional_16_For_2_For_3_Conditional_16_Template, 2, 1, "p", 53)(17, UserNotificationsComponent_Conditional_16_For_2_For_3_Conditional_17_Template, 4, 1, "div", 54);
|
|
310
|
+
i0.ɵɵconditionalCreate(18, UserNotificationsComponent_Conditional_16_For_2_For_3_Conditional_18_Template, 3, 6, "button", 55);
|
|
311
|
+
i0.ɵɵelementEnd();
|
|
312
|
+
i0.ɵɵelementStart(19, "div", 56);
|
|
313
|
+
i0.ɵɵconditionalCreate(20, UserNotificationsComponent_Conditional_16_For_2_For_3_Conditional_20_Template, 4, 1, "button", 57)(21, UserNotificationsComponent_Conditional_16_For_2_For_3_Conditional_21_Template, 4, 1, "button", 58);
|
|
228
314
|
i0.ɵɵelementEnd()();
|
|
229
315
|
} if (rf & 2) {
|
|
230
|
-
const
|
|
231
|
-
const
|
|
232
|
-
i0.ɵɵclassProp("unread",
|
|
233
|
-
i0.ɵɵattribute("aria-label",
|
|
234
|
-
i0.ɵɵadvance(2);
|
|
235
|
-
i0.ɵɵstyleProp("background-color", ctx_r1.getTypeColor(notification_r10) + "15");
|
|
236
|
-
i0.ɵɵadvance();
|
|
237
|
-
i0.ɵɵclassMap("fa-solid " + ctx_r1.getTypeIcon(notification_r10));
|
|
238
|
-
i0.ɵɵstyleProp("color", ctx_r1.getTypeColor(notification_r10));
|
|
316
|
+
const vm_r10 = ctx.$implicit;
|
|
317
|
+
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
318
|
+
i0.ɵɵclassProp("unread", vm_r10.N.Unread)("expanded", ctx_r0.IsExpanded(vm_r10))("clickable", vm_r10.Clickable);
|
|
319
|
+
i0.ɵɵattribute("aria-label", vm_r10.N.Title);
|
|
239
320
|
i0.ɵɵadvance(3);
|
|
240
|
-
i0.ɵɵ
|
|
241
|
-
i0.ɵɵ
|
|
242
|
-
i0.ɵɵtextInterpolate1(" ", notification_r10.Title, " ");
|
|
321
|
+
i0.ɵɵclassMap("fa-solid " + ctx_r0.getTypeIcon(vm_r10.N));
|
|
322
|
+
i0.ɵɵstyleProp("color", ctx_r0.getTypeColor(vm_r10.N));
|
|
243
323
|
i0.ɵɵadvance(3);
|
|
244
|
-
i0.ɵɵ
|
|
324
|
+
i0.ɵɵclassProp("card-title-unread", vm_r10.N.Unread);
|
|
245
325
|
i0.ɵɵadvance();
|
|
246
|
-
i0.ɵɵtextInterpolate1(" ",
|
|
247
|
-
i0.ɵɵadvance(
|
|
248
|
-
i0.ɵɵ
|
|
326
|
+
i0.ɵɵtextInterpolate1(" ", vm_r10.N.Title, " ");
|
|
327
|
+
i0.ɵɵadvance();
|
|
328
|
+
i0.ɵɵproperty("title", i0.ɵɵpipeBind2(9, 21, vm_r10.N.__mj_CreatedAt, "medium") ?? "");
|
|
329
|
+
i0.ɵɵadvance(2);
|
|
330
|
+
i0.ɵɵconditional(vm_r10.Relative ? 10 : 11);
|
|
331
|
+
i0.ɵɵadvance(4);
|
|
332
|
+
i0.ɵɵtextInterpolate(ctx_r0.getTypeName(vm_r10.N));
|
|
249
333
|
i0.ɵɵadvance();
|
|
250
|
-
i0.ɵɵ
|
|
334
|
+
i0.ɵɵconditional(vm_r10.Clickable ? 15 : -1);
|
|
335
|
+
i0.ɵɵadvance();
|
|
336
|
+
i0.ɵɵconditional(!ctx_r0.IsExpanded(vm_r10) ? 16 : 17);
|
|
251
337
|
i0.ɵɵadvance(2);
|
|
252
|
-
i0.ɵɵ
|
|
338
|
+
i0.ɵɵconditional(vm_r10.Expandable ? 18 : -1);
|
|
253
339
|
i0.ɵɵadvance(2);
|
|
254
|
-
i0.ɵɵconditional(
|
|
340
|
+
i0.ɵɵconditional(vm_r10.N.Unread ? 20 : 21);
|
|
341
|
+
} }
|
|
342
|
+
function UserNotificationsComponent_Conditional_16_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
343
|
+
i0.ɵɵelementStart(0, "div", 41);
|
|
344
|
+
i0.ɵɵtext(1);
|
|
345
|
+
i0.ɵɵelementEnd();
|
|
346
|
+
i0.ɵɵrepeaterCreate(2, UserNotificationsComponent_Conditional_16_For_2_For_3_Template, 22, 24, "article", 42, _forTrack2);
|
|
347
|
+
} if (rf & 2) {
|
|
348
|
+
const group_r15 = ctx.$implicit;
|
|
349
|
+
i0.ɵɵadvance();
|
|
350
|
+
i0.ɵɵtextInterpolate(group_r15.Label);
|
|
351
|
+
i0.ɵɵadvance();
|
|
352
|
+
i0.ɵɵrepeater(group_r15.Items);
|
|
255
353
|
} }
|
|
256
|
-
function
|
|
257
|
-
i0.ɵɵelementStart(0, "div",
|
|
258
|
-
i0.ɵɵrepeaterCreate(1,
|
|
354
|
+
function UserNotificationsComponent_Conditional_16_Template(rf, ctx) { if (rf & 1) {
|
|
355
|
+
i0.ɵɵelementStart(0, "div", 13);
|
|
356
|
+
i0.ɵɵrepeaterCreate(1, UserNotificationsComponent_Conditional_16_For_2_Template, 4, 1, null, null, _forTrack1);
|
|
259
357
|
i0.ɵɵelementEnd();
|
|
260
358
|
} if (rf & 2) {
|
|
261
|
-
const
|
|
359
|
+
const ctx_r0 = i0.ɵɵnextContext();
|
|
262
360
|
i0.ɵɵadvance();
|
|
263
|
-
i0.ɵɵrepeater(
|
|
361
|
+
i0.ɵɵrepeater(ctx_r0.Groups);
|
|
264
362
|
} }
|
|
363
|
+
/** Collapsed-preview cap (characters of plain text). */
|
|
364
|
+
const PREVIEW_MAX_CHARS = 240;
|
|
365
|
+
/** How often the snapshot relative-time labels refresh. */
|
|
366
|
+
const RELATIVE_REFRESH_MS = 60_000;
|
|
265
367
|
export class UserNotificationsComponent extends BaseAngularComponent {
|
|
266
368
|
sharedService;
|
|
267
369
|
navigationService;
|
|
268
370
|
appManager;
|
|
269
|
-
|
|
270
|
-
unreadRadio;
|
|
271
|
-
readRadio;
|
|
371
|
+
cdr = inject(ChangeDetectorRef);
|
|
272
372
|
radioSelected = 'All';
|
|
273
373
|
currentFilter = '';
|
|
274
374
|
notificationTypes = [];
|
|
275
375
|
selectedTypeFilter = null;
|
|
276
376
|
loadingTypes = true;
|
|
377
|
+
/** IDs of cards currently expanded to their full rendered content. */
|
|
378
|
+
Expanded = new Set();
|
|
379
|
+
groups = [];
|
|
380
|
+
groupsKey = '';
|
|
381
|
+
vmCache = new Map();
|
|
382
|
+
relativeTimer = null;
|
|
277
383
|
constructor(sharedService, navigationService, appManager) {
|
|
278
384
|
super();
|
|
279
385
|
this.sharedService = sharedService;
|
|
@@ -282,10 +388,23 @@ export class UserNotificationsComponent extends BaseAngularComponent {
|
|
|
282
388
|
}
|
|
283
389
|
async ngOnInit() {
|
|
284
390
|
this.loadNotificationTypes();
|
|
391
|
+
// Refresh the snapshot relative-time labels between change-detection passes.
|
|
392
|
+
this.relativeTimer = setInterval(() => {
|
|
393
|
+
for (const vm of this.vmCache.values()) {
|
|
394
|
+
vm.Relative = this.relativeTime(vm.N.__mj_CreatedAt);
|
|
395
|
+
}
|
|
396
|
+
this.groupsKey = ''; // day buckets can shift at midnight
|
|
397
|
+
this.cdr.markForCheck();
|
|
398
|
+
}, RELATIVE_REFRESH_MS);
|
|
285
399
|
}
|
|
286
400
|
ngAfterViewInit() {
|
|
287
401
|
this.sharedService.InvokeManualResize(); // make sure the notifications component is sized correctly
|
|
288
402
|
}
|
|
403
|
+
ngOnDestroy() {
|
|
404
|
+
if (this.relativeTimer != null) {
|
|
405
|
+
clearInterval(this.relativeTimer);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
289
408
|
loadNotificationTypes() {
|
|
290
409
|
// Get notification types from UserInfoEngine cache, sorted client-side
|
|
291
410
|
// UserInfoEngine is auto-configured via @RegisterForStartup()
|
|
@@ -299,6 +418,9 @@ export class UserNotificationsComponent extends BaseAngularComponent {
|
|
|
299
418
|
});
|
|
300
419
|
this.loadingTypes = false;
|
|
301
420
|
}
|
|
421
|
+
// ========================================================================
|
|
422
|
+
// Data shaping (filter → view models → day groups)
|
|
423
|
+
// ========================================================================
|
|
302
424
|
get NotificationsToShow() {
|
|
303
425
|
let temp = [];
|
|
304
426
|
switch (this.radioSelected) {
|
|
@@ -324,6 +446,153 @@ export class UserNotificationsComponent extends BaseAngularComponent {
|
|
|
324
446
|
}
|
|
325
447
|
return temp;
|
|
326
448
|
}
|
|
449
|
+
/**
|
|
450
|
+
* The filtered notifications as render-ready day groups. Memoized on a composite
|
|
451
|
+
* key of the inputs so the getter stays cheap across change-detection passes and
|
|
452
|
+
* the (time-sensitive) VM snapshots never rebuild mid-pass.
|
|
453
|
+
*/
|
|
454
|
+
get Groups() {
|
|
455
|
+
const list = this.NotificationsToShow;
|
|
456
|
+
const unread = list.filter(n => n.Unread).length;
|
|
457
|
+
const key = `${list.length}|${unread}|${this.radioSelected}|${this.selectedTypeFilter}|${this.currentFilter}|${list[0]?.ID ?? ''}|${list[list.length - 1]?.ID ?? ''}`;
|
|
458
|
+
if (key !== this.groupsKey) {
|
|
459
|
+
this.groups = this.buildGroups(list);
|
|
460
|
+
this.groupsKey = key;
|
|
461
|
+
}
|
|
462
|
+
return this.groups;
|
|
463
|
+
}
|
|
464
|
+
buildGroups(list) {
|
|
465
|
+
const groups = [];
|
|
466
|
+
let current = null;
|
|
467
|
+
for (const n of list) {
|
|
468
|
+
const label = this.dayLabel(n.__mj_CreatedAt);
|
|
469
|
+
if (!current || current.Label !== label) {
|
|
470
|
+
current = { Key: `${label}-${n.ID}`, Label: label, Items: [] };
|
|
471
|
+
groups.push(current);
|
|
472
|
+
}
|
|
473
|
+
current.Items.push(this.vmFor(n));
|
|
474
|
+
}
|
|
475
|
+
return groups;
|
|
476
|
+
}
|
|
477
|
+
vmFor(n) {
|
|
478
|
+
const cached = this.vmCache.get(n.ID);
|
|
479
|
+
if (cached) {
|
|
480
|
+
cached.N = n;
|
|
481
|
+
cached.Clickable = this.isNotificationClickable(n);
|
|
482
|
+
return cached;
|
|
483
|
+
}
|
|
484
|
+
const { kind, body, preview, expandable } = this.classifyMessage(n.Message ?? '');
|
|
485
|
+
const vm = {
|
|
486
|
+
N: n,
|
|
487
|
+
Kind: kind,
|
|
488
|
+
Body: body,
|
|
489
|
+
Preview: preview,
|
|
490
|
+
Expandable: expandable,
|
|
491
|
+
Relative: this.relativeTime(n.__mj_CreatedAt),
|
|
492
|
+
Clickable: this.isNotificationClickable(n),
|
|
493
|
+
};
|
|
494
|
+
this.vmCache.set(n.ID, vm);
|
|
495
|
+
return vm;
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
498
|
+
* Classifies a notification Message for rendering:
|
|
499
|
+
* - Full HTML documents (e.g. templated email bodies) and HTML fragments →
|
|
500
|
+
* parsed with DOMParser, chrome elements (style/script/link/meta/title) removed,
|
|
501
|
+
* and the body markup kept for a SANITIZED [innerHTML] binding (Angular's
|
|
502
|
+
* default sanitizer strips scripts/event handlers on bind).
|
|
503
|
+
* - Markdown-looking text → rendered through mj-markdown when expanded.
|
|
504
|
+
* - Everything else → plain text.
|
|
505
|
+
*/
|
|
506
|
+
classifyMessage(message) {
|
|
507
|
+
const trimmed = (message ?? '').trim();
|
|
508
|
+
const looksHtml = /^<!doctype\s|^<html[\s>]/i.test(trimmed) || /<\/?[a-z][^>]*>/i.test(trimmed);
|
|
509
|
+
if (looksHtml) {
|
|
510
|
+
const doc = new DOMParser().parseFromString(trimmed, 'text/html');
|
|
511
|
+
for (const el of Array.from(doc.querySelectorAll('style, script, link, meta, title'))) {
|
|
512
|
+
el.remove();
|
|
513
|
+
}
|
|
514
|
+
const body = doc.body?.innerHTML?.trim() ?? '';
|
|
515
|
+
const text = this.collapseWhitespace(doc.body?.textContent ?? '');
|
|
516
|
+
return { kind: 'html', body, preview: this.excerpt(text), expandable: true };
|
|
517
|
+
}
|
|
518
|
+
const looksMarkdown = /(^|\n)#{1,6}\s|\*\*[^*]+\*\*|(^|\n)\s*[-*]\s+|\[[^\]]+\]\([^)]+\)|```/m.test(trimmed);
|
|
519
|
+
const text = this.collapseWhitespace(trimmed);
|
|
520
|
+
if (looksMarkdown) {
|
|
521
|
+
return { kind: 'markdown', body: trimmed, preview: this.excerpt(this.stripMarkdown(text)), expandable: true };
|
|
522
|
+
}
|
|
523
|
+
return { kind: 'text', body: '', preview: text, expandable: text.length > PREVIEW_MAX_CHARS };
|
|
524
|
+
}
|
|
525
|
+
collapseWhitespace(value) {
|
|
526
|
+
return value.replace(/\s+/g, ' ').trim();
|
|
527
|
+
}
|
|
528
|
+
excerpt(text) {
|
|
529
|
+
return text.length > PREVIEW_MAX_CHARS ? `${text.substring(0, PREVIEW_MAX_CHARS - 1)}…` : text;
|
|
530
|
+
}
|
|
531
|
+
/** Light de-noising of markdown syntax for the plain-text preview. */
|
|
532
|
+
stripMarkdown(text) {
|
|
533
|
+
return text
|
|
534
|
+
.replace(/```[\s\S]*?```/g, ' ')
|
|
535
|
+
.replace(/[#*_`>]+/g, '')
|
|
536
|
+
.replace(/\[([^\]]+)\]\([^)]*\)/g, '$1')
|
|
537
|
+
.replace(/\s+/g, ' ')
|
|
538
|
+
.trim();
|
|
539
|
+
}
|
|
540
|
+
/** Compact "just now / 5m ago / 3h ago / 2d ago" label. NEVER call from templates (NG0100) — snapshot only. */
|
|
541
|
+
relativeTime(value) {
|
|
542
|
+
if (!value) {
|
|
543
|
+
return '';
|
|
544
|
+
}
|
|
545
|
+
const ms = Date.now() - new Date(value).getTime();
|
|
546
|
+
const minutes = Math.floor(ms / 60_000);
|
|
547
|
+
if (minutes < 1)
|
|
548
|
+
return 'just now';
|
|
549
|
+
if (minutes < 60)
|
|
550
|
+
return `${minutes}m ago`;
|
|
551
|
+
const hours = Math.floor(minutes / 60);
|
|
552
|
+
if (hours < 24)
|
|
553
|
+
return `${hours}h ago`;
|
|
554
|
+
const days = Math.floor(hours / 24);
|
|
555
|
+
return days < 7 ? `${days}d ago` : '';
|
|
556
|
+
}
|
|
557
|
+
dayLabel(value) {
|
|
558
|
+
if (!value) {
|
|
559
|
+
return 'Earlier';
|
|
560
|
+
}
|
|
561
|
+
const d = new Date(value);
|
|
562
|
+
const now = new Date();
|
|
563
|
+
const startOfDay = (x) => new Date(x.getFullYear(), x.getMonth(), x.getDate()).getTime();
|
|
564
|
+
const diffDays = Math.round((startOfDay(now) - startOfDay(d)) / 86_400_000);
|
|
565
|
+
if (diffDays <= 0)
|
|
566
|
+
return 'Today';
|
|
567
|
+
if (diffDays === 1)
|
|
568
|
+
return 'Yesterday';
|
|
569
|
+
if (diffDays < 7)
|
|
570
|
+
return 'This Week';
|
|
571
|
+
return 'Earlier';
|
|
572
|
+
}
|
|
573
|
+
// ========================================================================
|
|
574
|
+
// Expand / collapse
|
|
575
|
+
// ========================================================================
|
|
576
|
+
IsExpanded(vm) {
|
|
577
|
+
return this.Expanded.has(vm.N.ID);
|
|
578
|
+
}
|
|
579
|
+
ToggleExpanded(vm, event) {
|
|
580
|
+
event.stopPropagation();
|
|
581
|
+
if (this.Expanded.has(vm.N.ID)) {
|
|
582
|
+
this.Expanded.delete(vm.N.ID);
|
|
583
|
+
}
|
|
584
|
+
else {
|
|
585
|
+
this.Expanded.add(vm.N.ID);
|
|
586
|
+
// Reading the full content is reading — mark it as such.
|
|
587
|
+
if (vm.N.Unread) {
|
|
588
|
+
void this.markAsRead(vm.N, true, null);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
this.cdr.markForCheck();
|
|
592
|
+
}
|
|
593
|
+
// ========================================================================
|
|
594
|
+
// Clickability + navigation (unchanged behavior)
|
|
595
|
+
// ========================================================================
|
|
327
596
|
isNotificationClickable(notification) {
|
|
328
597
|
// Check for special types navigated via NavigationService (not a URL)
|
|
329
598
|
if (notification.ResourceConfiguration && notification.ResourceConfiguration.trim().length > 0) {
|
|
@@ -401,41 +670,10 @@ export class UserNotificationsComponent extends BaseAngularComponent {
|
|
|
401
670
|
}
|
|
402
671
|
selectReadOption(option) {
|
|
403
672
|
this.radioSelected = option;
|
|
404
|
-
// now update the radio button group in the UI
|
|
405
|
-
switch (option) {
|
|
406
|
-
case 'All':
|
|
407
|
-
this.allRadio.nativeElement.checked = true;
|
|
408
|
-
break;
|
|
409
|
-
case 'Unread':
|
|
410
|
-
this.unreadRadio.nativeElement.checked = true;
|
|
411
|
-
break;
|
|
412
|
-
case 'Read':
|
|
413
|
-
this.readRadio.nativeElement.checked = true;
|
|
414
|
-
break;
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
onReadRadioChanged(event) {
|
|
418
|
-
if (event.target instanceof HTMLInputElement) {
|
|
419
|
-
this.radioSelected = event.target.value;
|
|
420
|
-
}
|
|
421
673
|
}
|
|
422
674
|
onFilterChanged(value) {
|
|
423
675
|
this.currentFilter = value;
|
|
424
676
|
}
|
|
425
|
-
getItemTitleClass(notification) {
|
|
426
|
-
if (notification.Unread) {
|
|
427
|
-
return 'notification-title notification-title-unread';
|
|
428
|
-
}
|
|
429
|
-
return 'notification-title';
|
|
430
|
-
}
|
|
431
|
-
getItemWrapperClass(notification) {
|
|
432
|
-
let classInfo = 'notification-wrap';
|
|
433
|
-
if (this.isNotificationClickable(notification))
|
|
434
|
-
classInfo += ' notification-wrap-clickable';
|
|
435
|
-
if (notification.Unread)
|
|
436
|
-
classInfo += ' notification-wrap-unread';
|
|
437
|
-
return classInfo;
|
|
438
|
-
}
|
|
439
677
|
async markAsRead(notification, bRead, transGroup) {
|
|
440
678
|
if (notification) {
|
|
441
679
|
const notificationId = notification.ID;
|
|
@@ -472,37 +710,6 @@ export class UserNotificationsComponent extends BaseAngularComponent {
|
|
|
472
710
|
}
|
|
473
711
|
async markAllAsRead() {
|
|
474
712
|
await this.markAll(true);
|
|
475
|
-
// test harness for creating Conversations and Conversation Details record in a single transaction using variables
|
|
476
|
-
await this.TestTransactionGroupVariables();
|
|
477
|
-
}
|
|
478
|
-
async TestTransactionGroupVariables() {
|
|
479
|
-
const md = this.ProviderToUse;
|
|
480
|
-
const transGroup = await md.CreateTransactionGroup();
|
|
481
|
-
const conversation = await md.GetEntityObject('MJ: Conversations');
|
|
482
|
-
conversation.UserID = md.CurrentUser.ID;
|
|
483
|
-
conversation.Description = 'Test Conversation';
|
|
484
|
-
conversation.TransactionGroup = transGroup;
|
|
485
|
-
if (!await conversation.Save()) {
|
|
486
|
-
this.sharedService.CreateSimpleNotification('Unable to create conversation', 'error', 5000);
|
|
487
|
-
}
|
|
488
|
-
const tvDefine = new TransactionVariable('NewConvoID', conversation, 'ID', 'Define');
|
|
489
|
-
transGroup.AddVariable(tvDefine);
|
|
490
|
-
const conversationDetail = await md.GetEntityObject('MJ: Conversation Details');
|
|
491
|
-
conversationDetail.Message = 'Test Message';
|
|
492
|
-
conversationDetail.Role = 'User';
|
|
493
|
-
conversationDetail.ConversationID = 'x'; // fake UUID must be non-null to pass validation, this will be replaced by the variable, since we're part of a TG, not a real save, so doesn't validate it as a true fkey
|
|
494
|
-
conversationDetail.TransactionGroup = transGroup;
|
|
495
|
-
if (!await conversationDetail.Save()) {
|
|
496
|
-
this.sharedService.CreateSimpleNotification('Unable to create conversation detail', 'error', 500);
|
|
497
|
-
}
|
|
498
|
-
const tvUse = new TransactionVariable('NewConvoID', conversationDetail, 'ConversationID', 'Use');
|
|
499
|
-
transGroup.AddVariable(tvUse);
|
|
500
|
-
if (await transGroup.Submit()) {
|
|
501
|
-
this.sharedService.CreateSimpleNotification('Transaction Group with Variables worked', 'success', 5000);
|
|
502
|
-
}
|
|
503
|
-
else {
|
|
504
|
-
this.sharedService.CreateSimpleNotification('Transaction Group with Variables failed', 'error', 5000);
|
|
505
|
-
}
|
|
506
713
|
}
|
|
507
714
|
async markAllAsUnread() {
|
|
508
715
|
await this.markAll(false);
|
|
@@ -669,7 +876,7 @@ export class UserNotificationsComponent extends BaseAngularComponent {
|
|
|
669
876
|
}
|
|
670
877
|
getTypeColor(notification) {
|
|
671
878
|
const type = this.getNotificationType(notification.NotificationTypeID);
|
|
672
|
-
return type?.Color || '
|
|
879
|
+
return type?.Color || 'var(--mj-text-muted)';
|
|
673
880
|
}
|
|
674
881
|
getTypeName(notification) {
|
|
675
882
|
const type = this.getNotificationType(notification.NotificationTypeID);
|
|
@@ -679,48 +886,36 @@ export class UserNotificationsComponent extends BaseAngularComponent {
|
|
|
679
886
|
this.selectedTypeFilter = typeId;
|
|
680
887
|
}
|
|
681
888
|
static ɵfac = function UserNotificationsComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || UserNotificationsComponent)(i0.ɵɵdirectiveInject(i1.SharedService), i0.ɵɵdirectiveInject(i1.NavigationService), i0.ɵɵdirectiveInject(i2.ApplicationManager)); };
|
|
682
|
-
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: UserNotificationsComponent, selectors: [["app-user-notifications"]],
|
|
683
|
-
i0.ɵɵ
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
i0.ɵɵ
|
|
687
|
-
i0.ɵɵ
|
|
688
|
-
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.readRadio = _t.first);
|
|
689
|
-
} }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 14, vars: 3, consts: [["allRadio", ""], ["unreadRadio", ""], ["readRadio", ""], [1, "notifications-container"], [1, "notifications-header"], [1, "header-top"], [1, "header-title"], [1, "title-icon"], [1, "fa-solid", "fa-bell"], [1, "header-actions"], [1, "filters-section"], [1, "notifications-content"], ["Variant", "success", "Icon", "fa-solid fa-bell-slash", "Title", "No Notifications", "Message", "You're all caught up! New notifications will appear here."], ["Variant", "no-results", "Icon", "fa-solid fa-filter-circle-xmark", "Title", "No Matching Notifications", "Message", "Try adjusting your filters to see more notifications."], [1, "notifications-list"], ["type", "button", "aria-label", "Mark all notifications as read", 1, "action-btn", "action-btn-ghost"], ["type", "button", "aria-label", "Mark all notifications as unread", 1, "action-btn", "action-btn-secondary"], ["type", "button", "aria-label", "Mark all notifications as read", 1, "action-btn", "action-btn-ghost", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-check-double"], [1, "btn-text"], ["type", "button", "aria-label", "Mark all notifications as unread", 1, "action-btn", "action-btn-secondary", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-envelope"], [1, "filters-slider"], [1, "slider-content"], ["role", "group", "aria-label", "Filter notifications by read status", 1, "header-stats"], ["type", "radio", "name", "UnreadStatus", "value", "All", "checked", "", "id", "filter-all", 1, "hidden-radio", 3, "change"], ["type", "button", "aria-label", "Show all notifications", 1, "stat-pill", 3, "click"], [1, "stat-label"], [1, "stat-count"], ["type", "radio", "name", "UnreadStatus", "value", "Unread", "id", "filter-unread", 1, "hidden-radio", 3, "change"], ["type", "button", "aria-label", "Show unread notifications", 1, "stat-pill", 3, "active", "has-unread"], ["type", "radio", "name", "UnreadStatus", "value", "Read", "id", "filter-read", 1, "hidden-radio", 3, "change"], ["type", "button", "aria-label", "Show read notifications", 1, "stat-pill", 3, "active"], [1, "filter-item", "type-filter-slider"], [1, "search-section"], [1, "search-container"], ["aria-hidden", "true", 1, "fa-solid", "fa-magnifying-glass", "search-icon"], ["type", "text", "placeholder", "Search notifications...", "aria-label", "Search notifications", 1, "search-input", 3, "input", "value"], [1, "filter-info"], ["type", "button", "aria-label", "Show unread notifications", 1, "stat-pill", 3, "click"], ["type", "button", "aria-label", "Show read notifications", 1, "stat-pill", 3, "click"], ["aria-label", "Filter by notification type", 1, "type-select", 3, "ngModelChange", "change", "ngModel"], [3, "value"], [1, "filter-badge"], ["aria-hidden", "true", 1, "fa-solid", "fa-filter"], ["role", "article", 1, "notification-card", 3, "unread", "clickable"], ["role", "article", 1, "notification-card"], ["aria-hidden", "true", 1, "card-indicator"], ["aria-hidden", "true", 1, "card-icon"], [1, "card-content", 3, "click"], [1, "card-header"], [1, "card-title"], [1, "card-time"], ["aria-hidden", "true", 1, "fa-regular", "fa-clock"], [1, "card-meta"], [1, "card-type"], [1, "card-message"], [1, "card-actions"], ["type", "button", "title", "Mark as Read", 1, "card-action-btn"], ["type", "button", "title", "Mark as Unread", 1, "card-action-btn"], ["type", "button", "title", "Mark as Read", 1, "card-action-btn", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-check"], [1, "action-text"], ["type", "button", "title", "Mark as Unread", 1, "card-action-btn", 3, "click"]], template: function UserNotificationsComponent_Template(rf, ctx) { if (rf & 1) {
|
|
690
|
-
i0.ɵɵelementStart(0, "div", 3)(1, "div", 4)(2, "div", 5)(3, "div", 6)(4, "div", 7);
|
|
691
|
-
i0.ɵɵelement(5, "i", 8);
|
|
889
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: UserNotificationsComponent, selectors: [["app-user-notifications"]], standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 17, vars: 4, consts: [[1, "notifications-container"], [1, "notifications-header"], [1, "header-top"], [1, "header-title"], [1, "title-icon"], [1, "fa-solid", "fa-bell"], [1, "title-text"], [1, "title-subtitle"], [1, "header-actions"], [1, "filters-section"], [1, "notifications-content"], ["Variant", "success", "Icon", "fa-solid fa-bell-slash", "Title", "No Notifications", "Message", "You're all caught up! New notifications will appear here."], ["Variant", "no-results", "Icon", "fa-solid fa-filter-circle-xmark", "Title", "No Matching Notifications", "Message", "Try adjusting your filters to see more notifications."], [1, "notifications-list"], ["type", "button", "aria-label", "Mark all notifications as read", 1, "action-btn", "action-btn-ghost"], ["type", "button", "aria-label", "Mark all notifications as unread", 1, "action-btn", "action-btn-secondary"], ["type", "button", "aria-label", "Mark all notifications as read", 1, "action-btn", "action-btn-ghost", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-check-double"], [1, "btn-text"], ["type", "button", "aria-label", "Mark all notifications as unread", 1, "action-btn", "action-btn-secondary", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-envelope"], [1, "filters-slider"], [1, "slider-content"], ["role", "group", "aria-label", "Filter notifications by read status", 1, "header-stats"], ["type", "button", "aria-label", "Show all notifications", 1, "stat-pill", 3, "click"], [1, "stat-label"], [1, "stat-count"], ["type", "button", "aria-label", "Show unread notifications", 1, "stat-pill", 3, "active", "has-unread"], ["type", "button", "aria-label", "Show read notifications", 1, "stat-pill", 3, "active"], [1, "filter-item", "type-filter-slider"], [1, "search-section"], [1, "search-container"], ["aria-hidden", "true", 1, "fa-solid", "fa-magnifying-glass", "search-icon"], ["type", "text", "placeholder", "Search notifications...", "aria-label", "Search notifications", 1, "search-input", 3, "input", "value"], [1, "filter-info"], ["type", "button", "aria-label", "Show unread notifications", 1, "stat-pill", 3, "click"], ["type", "button", "aria-label", "Show read notifications", 1, "stat-pill", 3, "click"], ["aria-label", "Filter by notification type", 1, "type-select", 3, "ngModelChange", "change", "ngModel"], [3, "value"], [1, "filter-badge"], ["aria-hidden", "true", 1, "fa-solid", "fa-filter"], [1, "group-label"], ["role", "article", 1, "notification-card", 3, "unread", "expanded", "clickable"], ["role", "article", 1, "notification-card"], ["aria-hidden", "true", 1, "card-indicator"], ["aria-hidden", "true", 1, "card-icon"], [1, "card-content", 3, "click"], [1, "card-header"], [1, "card-title"], [1, "card-time", 3, "title"], [1, "card-meta"], [1, "card-type"], [1, "card-open-hint"], [1, "card-message"], [1, "card-rich"], ["type", "button", 1, "card-expand-btn"], [1, "card-actions"], ["type", "button", "title", "Mark as Read", 1, "card-action-btn"], ["type", "button", "title", "Mark as Unread", 1, "card-action-btn"], ["aria-hidden", "true", 1, "fa-solid", "fa-arrow-up-right-from-square"], [1, "card-rich", 3, "click"], [1, "card-rich-html", 3, "innerHTML"], [1, "card-rich-md", 3, "data", "enableMermaid"], [1, "card-message", "card-message-full"], ["type", "button", 1, "card-expand-btn", 3, "click"], ["aria-hidden", "true", 1, "fa-solid"], ["type", "button", "title", "Mark as Read", 1, "card-action-btn", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-check"], [1, "action-text"], ["type", "button", "title", "Mark as Unread", 1, "card-action-btn", 3, "click"]], template: function UserNotificationsComponent_Template(rf, ctx) { if (rf & 1) {
|
|
890
|
+
i0.ɵɵelementStart(0, "div", 0)(1, "div", 1)(2, "div", 2)(3, "div", 3)(4, "div", 4);
|
|
891
|
+
i0.ɵɵelement(5, "i", 5);
|
|
892
|
+
i0.ɵɵelementEnd();
|
|
893
|
+
i0.ɵɵelementStart(6, "div", 6)(7, "h1");
|
|
894
|
+
i0.ɵɵtext(8, "Notifications");
|
|
692
895
|
i0.ɵɵelementEnd();
|
|
693
|
-
i0.ɵɵ
|
|
694
|
-
i0.ɵɵtext(7, "Notifications");
|
|
896
|
+
i0.ɵɵconditionalCreate(9, UserNotificationsComponent_Conditional_9_Template, 2, 1, "span", 7)(10, UserNotificationsComponent_Conditional_10_Template, 2, 0, "span", 7);
|
|
695
897
|
i0.ɵɵelementEnd()();
|
|
696
|
-
i0.ɵɵconditionalCreate(
|
|
898
|
+
i0.ɵɵconditionalCreate(11, UserNotificationsComponent_Conditional_11_Template, 3, 2, "div", 8);
|
|
697
899
|
i0.ɵɵelementEnd();
|
|
698
|
-
i0.ɵɵconditionalCreate(
|
|
900
|
+
i0.ɵɵconditionalCreate(12, UserNotificationsComponent_Conditional_12_Template, 17, 9, "div", 9);
|
|
699
901
|
i0.ɵɵelementEnd();
|
|
700
|
-
i0.ɵɵelementStart(
|
|
701
|
-
i0.ɵɵconditionalCreate(
|
|
902
|
+
i0.ɵɵelementStart(13, "div", 10);
|
|
903
|
+
i0.ɵɵconditionalCreate(14, UserNotificationsComponent_Conditional_14_Template, 1, 0, "mj-empty-state", 11)(15, UserNotificationsComponent_Conditional_15_Template, 1, 0, "mj-empty-state", 12)(16, UserNotificationsComponent_Conditional_16_Template, 3, 0, "div", 13);
|
|
702
904
|
i0.ɵɵelementEnd()();
|
|
703
905
|
} if (rf & 2) {
|
|
704
|
-
i0.ɵɵadvance(
|
|
705
|
-
i0.ɵɵconditional(ctx.AllNotifications.length > 0 ?
|
|
906
|
+
i0.ɵɵadvance(9);
|
|
907
|
+
i0.ɵɵconditional(ctx.UnreadNotifications.length > 0 ? 9 : ctx.AllNotifications.length > 0 ? 10 : -1);
|
|
908
|
+
i0.ɵɵadvance(2);
|
|
909
|
+
i0.ɵɵconditional(ctx.AllNotifications.length > 0 ? 11 : -1);
|
|
706
910
|
i0.ɵɵadvance();
|
|
707
|
-
i0.ɵɵconditional(ctx.AllNotifications.length > 0 ?
|
|
911
|
+
i0.ɵɵconditional(ctx.AllNotifications.length > 0 ? 12 : -1);
|
|
708
912
|
i0.ɵɵadvance(2);
|
|
709
|
-
i0.ɵɵconditional(ctx.NotificationsToShow.length === 0 && ctx.AllNotifications.length === 0 ?
|
|
710
|
-
} }, dependencies: [i3.NgSelectOption, i3.ɵNgSelectMultipleOption, i3.SelectControlValueAccessor, i3.NgControlStatus, i3.NgModel, i4.MJEmptyStateComponent, i5.DatePipe], styles: ["\n\n\n\n\n\n[_nghost-%COMP%] {\n display: block;\n width: 100%;\n height: 100%;\n}\n\n\n\n\n\n\n.notifications-container[_ngcontent-%COMP%] {\n height: 100%;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface-card);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-sm);\n overflow: hidden;\n}\n\n\n\n\n\n\n.notifications-header[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n padding: 0;\n flex-shrink: 0;\n}\n\n\n\n.header-top[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 24px 24px 16px;\n gap: 16px;\n}\n\n.header-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.title-icon[_ngcontent-%COMP%] {\n width: 48px;\n height: 48px;\n background: var(--mj-brand-primary);\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: 0 4px 12px color-mix(in srgb, var(--mj-brand-primary) 30%, transparent);\n transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.title-icon[_ngcontent-%COMP%]:hover {\n transform: scale(1.05);\n}\n\n.title-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 22px;\n color: white;\n}\n\n.header-title[_ngcontent-%COMP%] h1[_ngcontent-%COMP%] {\n font-size: 1.75rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin: 0;\n letter-spacing: -0.02em;\n}\n\n\n\n\n\n\n.header-actions[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.action-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 20px;\n border-radius: 9999px; \n\n font-size: 14px;\n font-weight: 600;\n border: 2px solid var(--mj-brand-primary);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 44px;\n font-family: inherit;\n}\n\n.action-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 16px;\n transition: transform 0.2s ease;\n}\n\n.action-btn[_ngcontent-%COMP%]:hover i[_ngcontent-%COMP%] {\n transform: scale(1.1);\n}\n\n\n\n.action-btn-ghost[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.action-btn-ghost[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary);\n color: white;\n border-color: var(--mj-brand-primary);\n box-shadow: var(--mj-shadow-md);\n}\n\n.action-btn-ghost[_ngcontent-%COMP%]:active {\n background: var(--mj-brand-primary);\n transform: scale(0.98);\n}\n\n\n\n.action-btn-secondary[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.action-btn-secondary[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary);\n color: white;\n border-color: var(--mj-brand-primary);\n}\n\n.action-btn-secondary[_ngcontent-%COMP%]:active {\n transform: scale(0.98);\n}\n\n\n\n\n\n\n.filters-section[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 12px;\n background: var(--mj-bg-surface-card);\n border-top: 1px solid var(--mj-border-default);\n}\n\n.filters-slider[_ngcontent-%COMP%] {\n overflow-x: auto;\n overflow-y: hidden;\n -webkit-overflow-scrolling: touch;\n scrollbar-width: none;\n -ms-overflow-style: none;\n}\n\n.filters-slider[_ngcontent-%COMP%]::-webkit-scrollbar {\n display: none;\n}\n\n.slider-content[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 16px 24px;\n min-width: min-content;\n}\n\n\n\n\n\n\n.header-stats[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n flex-shrink: 0;\n}\n\n.hidden-radio[_ngcontent-%COMP%] {\n position: absolute;\n opacity: 0;\n pointer-events: none;\n}\n\n.stat-pill[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 20px;\n border-radius: 9999px; \n\n border: 2px solid var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n font-family: inherit;\n min-height: 44px;\n}\n\n.stat-pill[_ngcontent-%COMP%]:hover:not(.active) {\n background: var(--mj-bg-surface-card);\n border-color: var(--mj-brand-primary);\n transform: translateY(-1px);\n}\n\n\n\n.stat-pill.active[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n color: white;\n box-shadow: 0 4px 12px color-mix(in srgb, var(--mj-brand-primary) 35%, transparent);\n transform: translateY(-1px);\n}\n\n.stat-label[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 600;\n}\n\n.stat-count[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 700;\n padding: 4px 10px;\n border-radius: 9999px;\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n min-width: 28px;\n text-align: center;\n transition: all 0.2s ease;\n}\n\n.stat-pill.active[_ngcontent-%COMP%] .stat-count[_ngcontent-%COMP%] {\n background: rgba(255, 255, 255, 0.25);\n color: white;\n}\n\n.stat-count.unread-count[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-weight: 700;\n}\n\n.stat-pill.has-unread[_ngcontent-%COMP%]:not(.active) {\n border-color: var(--mj-brand-primary);\n}\n\n\n\n\n\n\n.type-filter-slider[_ngcontent-%COMP%] {\n flex-shrink: 0;\n min-width: 180px;\n}\n\n\n\n\n\n\n.search-section[_ngcontent-%COMP%] {\n padding: 0 24px 16px;\n}\n\n\n\n\n\n\n.filter-info[_ngcontent-%COMP%] {\n padding: 0 24px 16px;\n display: flex;\n justify-content: center;\n}\n\n\n\n.type-select[_ngcontent-%COMP%] {\n width: 100%;\n padding: 10px 16px;\n border: 2px solid var(--mj-brand-primary);\n border-radius: 9999px; \n\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n font-family: inherit;\n appearance: none;\n background-image: url(\"data:image/svg+xml,%3Csvg width='12' height='8' viewBox='0 0 12 8' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1 1.5L6 6.5L11 1.5' stroke='%230076B6' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\");\n background-repeat: no-repeat;\n background-position: right 16px center;\n padding-right: 42px;\n}\n\n.type-select[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n background-color: var(--mj-bg-surface-card);\n}\n\n.type-select[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.search-container[_ngcontent-%COMP%] {\n position: relative;\n width: 100%;\n max-width: 100%;\n}\n\n.search-icon[_ngcontent-%COMP%] {\n position: absolute;\n left: 16px;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-secondary);\n font-size: 14px;\n pointer-events: none;\n transition: color 0.2s ease;\n}\n\n.search-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 10px 16px 10px 44px;\n border: 2px solid var(--mj-brand-primary);\n border-radius: 9999px; \n\n font-size: 14px;\n font-weight: 500;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n font-family: inherit;\n}\n\n.search-input[_ngcontent-%COMP%]::placeholder {\n color: var(--mj-text-secondary);\n}\n\n.search-input[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface-card);\n}\n\n.search-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n background: var(--mj-bg-surface);\n}\n\n.search-container[_ngcontent-%COMP%]:focus-within .search-icon[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.filter-badge[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 14px;\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n border-radius: 9999px; \n\n font-size: 13px;\n font-weight: 600;\n border: 1px solid var(--mj-brand-primary);\n}\n\n.filter-badge[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n\n\n\n\n\n.notifications-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n -webkit-overflow-scrolling: touch; \n\n}\n\n\n\n.notifications-content[_ngcontent-%COMP%]::-webkit-scrollbar {\n width: 8px;\n}\n\n.notifications-content[_ngcontent-%COMP%]::-webkit-scrollbar-track {\n background: var(--mj-bg-surface-card);\n}\n\n.notifications-content[_ngcontent-%COMP%]::-webkit-scrollbar-thumb {\n background: var(--mj-border-default);\n border-radius: 4px;\n}\n\n.notifications-content[_ngcontent-%COMP%]::-webkit-scrollbar-thumb:hover {\n background: var(--mj-text-muted);\n}\n\n\n\n\n\n\n.notifications-list[_ngcontent-%COMP%] {\n background: transparent;\n}\n\n\n\n\n\n\n.notification-card[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 4px 56px 1fr auto;\n gap: 14px;\n align-items: start;\n padding: 16px 20px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n position: relative;\n}\n\n.notification-card[_ngcontent-%COMP%]:last-child {\n border-bottom: none;\n}\n\n.notification-card[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.notification-card.clickable[_ngcontent-%COMP%] {\n cursor: pointer;\n}\n\n.notification-card.clickable[_ngcontent-%COMP%]:active {\n background: var(--mj-bg-surface-sunken);\n transform: scale(0.995);\n}\n\n\n\n.notification-card.unread[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.notification-card.unread[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface-card));\n}\n\n\n\n.card-indicator[_ngcontent-%COMP%] {\n width: 4px;\n height: 100%;\n min-height: 64px;\n border-radius: 2px;\n background: transparent;\n transition: all 0.2s ease;\n align-self: stretch;\n}\n\n.notification-card.unread[_ngcontent-%COMP%] .card-indicator[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n box-shadow: 0 0 8px color-mix(in srgb, var(--mj-brand-primary) 50%, transparent);\n}\n\n\n\n.card-icon[_ngcontent-%COMP%] {\n width: 56px;\n height: 56px;\n border-radius: 14px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n transition: transform 0.2s ease;\n}\n\n.notification-card[_ngcontent-%COMP%]:hover .card-icon[_ngcontent-%COMP%] {\n transform: scale(1.05);\n}\n\n.card-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 24px;\n}\n\n\n\n.card-content[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.card-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: 12px;\n margin-bottom: 6px;\n}\n\n.card-title[_ngcontent-%COMP%] {\n font-size: 16px;\n font-weight: 500;\n color: var(--mj-text-primary);\n margin: 0;\n line-height: 1.4;\n word-wrap: break-word;\n}\n\n.card-title-unread[_ngcontent-%COMP%] {\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.notification-card.clickable[_ngcontent-%COMP%] .card-title[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.notification-card.clickable[_ngcontent-%COMP%]:hover .card-title[_ngcontent-%COMP%] {\n text-decoration: underline;\n}\n\n.card-time[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 5px;\n font-size: 13px;\n color: var(--mj-text-secondary);\n white-space: nowrap;\n flex-shrink: 0;\n}\n\n.card-time[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n\n\n.card-meta[_ngcontent-%COMP%] {\n margin-bottom: 8px;\n}\n\n.card-type[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n padding: 4px 12px;\n border-radius: 9999px; \n\n font-size: 12px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.03em;\n}\n\n\n\n.card-message[_ngcontent-%COMP%] {\n font-size: 15px;\n color: var(--mj-text-secondary);\n line-height: 1.5;\n margin: 0;\n display: -webkit-box;\n -webkit-line-clamp: 3;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n\n\n.card-actions[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n gap: 8px;\n padding-top: 6px;\n}\n\n.card-action-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 16px;\n border-radius: 9999px; \n\n font-size: 13px;\n font-weight: 600;\n border: 2px solid var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n white-space: nowrap;\n font-family: inherit;\n}\n\n.card-action-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n color: white;\n transform: translateY(-1px);\n box-shadow: var(--mj-shadow-md);\n}\n\n.card-action-btn[_ngcontent-%COMP%]:active {\n transform: translateY(0) scale(0.98);\n}\n\n.card-action-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 13px;\n}\n\n\n\n\n\n\n@keyframes _ngcontent-%COMP%_slideInUp {\n from {\n opacity: 0;\n transform: translateY(12px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n.notification-card[_ngcontent-%COMP%] {\n animation: _ngcontent-%COMP%_slideInUp 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n\n\n\n\n\nbutton[_ngcontent-%COMP%]:focus-visible, \ninput[_ngcontent-%COMP%]:focus-visible, \nselect[_ngcontent-%COMP%]:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n\n\n@media (prefers-reduced-motion: reduce) {\n *[_ngcontent-%COMP%], \n *[_ngcontent-%COMP%]::before, \n *[_ngcontent-%COMP%]::after {\n animation-duration: 0.01ms !important;\n animation-iteration-count: 1 !important;\n transition-duration: 0.01ms !important;\n }\n}\n\n\n\n\n\n\n\n\n@media (max-width: 768px) {\n .notifications-container[_ngcontent-%COMP%] {\n border-radius: 0;\n box-shadow: none;\n }\n\n .header-top[_ngcontent-%COMP%] {\n padding: 20px 20px 14px;\n }\n\n .title-icon[_ngcontent-%COMP%] {\n width: 44px;\n height: 44px;\n }\n\n .title-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 20px;\n }\n\n .header-title[_ngcontent-%COMP%] h1[_ngcontent-%COMP%] {\n font-size: 1.5rem;\n }\n\n \n\n .slider-content[_ngcontent-%COMP%] {\n padding: 14px 20px;\n gap: 10px;\n }\n\n .stat-pill[_ngcontent-%COMP%] {\n padding: 8px 16px;\n flex-shrink: 0;\n }\n\n .type-filter-slider[_ngcontent-%COMP%] {\n min-width: 160px;\n }\n\n .search-section[_ngcontent-%COMP%] {\n padding: 0 20px 14px;\n }\n\n .filter-info[_ngcontent-%COMP%] {\n padding: 0 20px 14px;\n }\n\n .notification-card[_ngcontent-%COMP%] {\n grid-template-columns: 4px 52px 1fr;\n gap: 12px;\n padding: 14px 16px;\n }\n\n .card-actions[_ngcontent-%COMP%] {\n grid-column: 2 / -1;\n padding-top: 10px;\n }\n\n .card-icon[_ngcontent-%COMP%] {\n width: 52px;\n height: 52px;\n }\n\n .card-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 22px;\n }\n}\n\n\n\n@media (max-width: 480px) {\n .header-top[_ngcontent-%COMP%] {\n flex-direction: column;\n align-items: stretch;\n gap: 12px;\n padding: 16px 16px 12px;\n }\n\n .header-title[_ngcontent-%COMP%] {\n justify-content: flex-start;\n }\n\n .title-icon[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n }\n\n .title-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 18px;\n }\n\n .header-title[_ngcontent-%COMP%] h1[_ngcontent-%COMP%] {\n font-size: 1.375rem;\n }\n\n .header-actions[_ngcontent-%COMP%] {\n width: 100%;\n justify-content: stretch;\n gap: 8px;\n }\n\n .action-btn[_ngcontent-%COMP%] {\n flex: 1;\n justify-content: center;\n padding: 10px 16px;\n font-size: 13px;\n }\n\n .btn-text[_ngcontent-%COMP%] {\n display: none;\n }\n\n \n\n .slider-content[_ngcontent-%COMP%] {\n padding: 12px 16px;\n gap: 8px;\n }\n\n .header-stats[_ngcontent-%COMP%] {\n gap: 8px;\n }\n\n .stat-pill[_ngcontent-%COMP%] {\n padding: 8px 14px;\n min-height: 40px;\n flex-shrink: 0;\n }\n\n .stat-label[_ngcontent-%COMP%] {\n font-size: 13px;\n }\n\n .stat-count[_ngcontent-%COMP%] {\n font-size: 12px;\n padding: 3px 8px;\n min-width: 24px;\n }\n\n .type-filter-slider[_ngcontent-%COMP%] {\n min-width: 140px;\n }\n\n .type-select[_ngcontent-%COMP%], \n .search-input[_ngcontent-%COMP%] {\n font-size: 16px; \n\n }\n\n .search-section[_ngcontent-%COMP%] {\n padding: 0 16px 12px;\n }\n\n .filter-info[_ngcontent-%COMP%] {\n padding: 0 16px 12px;\n }\n\n .notification-card[_ngcontent-%COMP%] {\n grid-template-columns: 3px 48px 1fr;\n gap: 10px;\n padding: 12px 12px;\n }\n\n .card-indicator[_ngcontent-%COMP%] {\n width: 3px;\n min-height: 56px;\n }\n\n .card-icon[_ngcontent-%COMP%] {\n width: 48px;\n height: 48px;\n border-radius: 12px;\n }\n\n .card-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 20px;\n }\n\n .card-title[_ngcontent-%COMP%] {\n font-size: 15px;\n }\n\n .card-time[_ngcontent-%COMP%] {\n font-size: 12px;\n }\n\n .card-message[_ngcontent-%COMP%] {\n font-size: 14px;\n -webkit-line-clamp: 2;\n }\n\n .card-type[_ngcontent-%COMP%] {\n font-size: 11px;\n padding: 3px 10px;\n }\n\n .card-actions[_ngcontent-%COMP%] {\n padding-top: 8px;\n gap: 6px;\n }\n\n .action-text[_ngcontent-%COMP%] {\n display: none;\n }\n\n .card-action-btn[_ngcontent-%COMP%] {\n padding: 8px 12px;\n min-width: 40px;\n justify-content: center;\n }\n\n}\n\n\n\n@media (min-width: 390px) and (max-width: 480px) {\n .btn-text[_ngcontent-%COMP%] {\n display: inline;\n }\n\n .action-btn[_ngcontent-%COMP%] {\n font-size: 14px;\n }\n}\n\n\n\n@media (prefers-color-scheme: dark) {\n \n\n}"] });
|
|
913
|
+
i0.ɵɵconditional(ctx.NotificationsToShow.length === 0 && ctx.AllNotifications.length === 0 ? 14 : ctx.NotificationsToShow.length === 0 ? 15 : 16);
|
|
914
|
+
} }, dependencies: [i3.MarkdownComponent, i4.NgSelectOption, i4.ɵNgSelectMultipleOption, i4.SelectControlValueAccessor, i4.NgControlStatus, i4.NgModel, i5.MJEmptyStateComponent, i6.DatePipe], styles: ["\n\n\n\n\n\n[_nghost-%COMP%] {\n display: block;\n height: 100%;\n}\n\n.notifications-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--mj-bg-page);\n}\n\n\n\n\n.notifications-header[_ngcontent-%COMP%] {\n flex-shrink: 0;\n padding: 20px 24px 12px 24px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.header-top[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 16px;\n margin-bottom: 14px;\n}\n\n.header-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n min-width: 0;\n}\n\n.title-icon[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 40px;\n height: 40px;\n border-radius: var(--mj-radius-lg, 12px);\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: 16px;\n}\n\n.title-text[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n\n.title-text[_ngcontent-%COMP%] h1[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 20px;\n font-weight: 700;\n color: var(--mj-text-primary);\n line-height: 1.2;\n}\n\n.title-subtitle[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n.header-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n flex-shrink: 0;\n}\n\n.action-btn[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 7px 12px;\n border-radius: var(--mj-radius-md, 8px);\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n font-size: 12px;\n font-weight: 600;\n cursor: pointer;\n transition: background-color 0.15s, color 0.15s, border-color 0.15s;\n}\n\n.action-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n.action-btn-ghost[_ngcontent-%COMP%] {\n border-color: color-mix(in srgb, var(--mj-brand-primary) 35%, transparent);\n color: var(--mj-brand-primary);\n}\n\n.action-btn-ghost[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n\n\n\n.filters-section[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 10px;\n}\n\n.filters-slider[_ngcontent-%COMP%] {\n min-width: 0;\n}\n\n.slider-content[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n flex-wrap: wrap;\n}\n\n.header-stats[_ngcontent-%COMP%] {\n display: inline-flex;\n gap: 4px;\n padding: 3px;\n border-radius: var(--mj-radius-full, 999px);\n background: var(--mj-bg-surface-sunken);\n}\n\n.stat-pill[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 5px 12px;\n border: none;\n border-radius: var(--mj-radius-full, 999px);\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 12px;\n font-weight: 600;\n cursor: pointer;\n transition: background-color 0.15s, color 0.15s;\n}\n\n.stat-pill[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-primary);\n}\n\n.stat-pill.active[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n box-shadow: var(--mj-shadow-sm);\n}\n\n.stat-count[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 18px;\n height: 18px;\n padding: 0 5px;\n border-radius: var(--mj-radius-full, 999px);\n background: color-mix(in srgb, var(--mj-text-muted) 14%, transparent);\n color: var(--mj-text-secondary);\n font-size: 10px;\n font-weight: 700;\n}\n\n.stat-count.unread-count[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n color: var(--mj-brand-primary);\n}\n\n.type-select[_ngcontent-%COMP%] {\n padding: 7px 10px;\n border-radius: var(--mj-radius-md, 8px);\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n font-size: 12px;\n cursor: pointer;\n}\n\n.search-section[_ngcontent-%COMP%] {\n flex: 1 1 220px;\n min-width: 180px;\n}\n\n.search-container[_ngcontent-%COMP%] {\n position: relative;\n display: flex;\n align-items: center;\n}\n\n.search-icon[_ngcontent-%COMP%] {\n position: absolute;\n left: 12px;\n color: var(--mj-text-muted);\n font-size: 12px;\n pointer-events: none;\n}\n\n.search-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 8px 12px 8px 32px;\n border-radius: var(--mj-radius-md, 8px);\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n font-size: 13px;\n}\n\n.search-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--mj-border-focus);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n}\n\n.filter-info[_ngcontent-%COMP%] {\n flex-basis: 100%;\n}\n\n.filter-badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n border-radius: var(--mj-radius-full, 999px);\n background: color-mix(in srgb, var(--mj-status-info) 10%, var(--mj-bg-surface));\n color: var(--mj-status-info);\n font-size: 11px;\n font-weight: 600;\n}\n\n\n\n\n.notifications-content[_ngcontent-%COMP%] {\n flex: 1 1 auto;\n min-height: 0;\n overflow-y: auto;\n padding: 16px 24px 32px 24px;\n}\n\n.notifications-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 10px;\n max-width: 960px;\n margin: 0 auto;\n}\n\n.group-label[_ngcontent-%COMP%] {\n position: sticky;\n top: -16px;\n z-index: 1;\n padding: 10px 2px 4px 2px;\n background: var(--mj-bg-page);\n font-size: 11px;\n font-weight: 700;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n color: var(--mj-text-muted);\n}\n\n.group-label[_ngcontent-%COMP%]:not(:first-child) {\n margin-top: 8px;\n}\n\n\n\n\n.notification-card[_ngcontent-%COMP%] {\n position: relative;\n display: flex;\n gap: 12px;\n padding: 14px 16px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg, 12px);\n background: var(--mj-bg-surface);\n transition: border-color 0.15s, box-shadow 0.15s, background-color 0.15s;\n overflow: hidden;\n}\n\n.notification-card[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-border-strong);\n box-shadow: var(--mj-shadow-sm);\n}\n\n.notification-card.unread[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 3%, var(--mj-bg-surface));\n}\n\n.card-indicator[_ngcontent-%COMP%] {\n display: none;\n position: absolute;\n left: 0;\n top: 0;\n bottom: 0;\n width: 3px;\n background: var(--mj-brand-primary);\n border-radius: 0 2px 2px 0;\n}\n\n.notification-card.unread[_ngcontent-%COMP%] .card-indicator[_ngcontent-%COMP%] {\n display: block;\n}\n\n.card-icon[_ngcontent-%COMP%] {\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 36px;\n height: 36px;\n border-radius: var(--mj-radius-md, 10px);\n background: var(--mj-bg-surface-sunken);\n font-size: 14px;\n}\n\n.card-content[_ngcontent-%COMP%] {\n flex: 1 1 auto;\n min-width: 0;\n}\n\n.notification-card.clickable[_ngcontent-%COMP%] .card-content[_ngcontent-%COMP%] {\n cursor: pointer;\n}\n\n.card-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: baseline;\n justify-content: space-between;\n gap: 12px;\n}\n\n.card-title[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-primary);\n overflow-wrap: anywhere;\n}\n\n.card-title-unread[_ngcontent-%COMP%] {\n font-weight: 700;\n}\n\n.card-time[_ngcontent-%COMP%] {\n flex-shrink: 0;\n font-size: 11px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n}\n\n.card-meta[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 3px 0 6px 0;\n}\n\n.card-type[_ngcontent-%COMP%] {\n display: inline-flex;\n padding: 2px 8px;\n border-radius: var(--mj-radius-full, 999px);\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n font-size: 10px;\n font-weight: 700;\n letter-spacing: 0.04em;\n text-transform: uppercase;\n}\n\n.card-open-hint[_ngcontent-%COMP%] {\n display: none;\n align-items: center;\n gap: 4px;\n font-size: 10px;\n font-weight: 600;\n color: var(--mj-brand-primary);\n}\n\n.notification-card.clickable[_ngcontent-%COMP%]:hover .card-open-hint[_ngcontent-%COMP%] {\n display: inline-flex;\n}\n\n.card-message[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 13px;\n line-height: 1.5;\n color: var(--mj-text-secondary);\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n overflow-wrap: anywhere;\n}\n\n.card-message-full[_ngcontent-%COMP%] {\n display: block;\n -webkit-line-clamp: unset;\n white-space: pre-wrap;\n}\n\n\n\n\n.card-rich[_ngcontent-%COMP%] {\n margin-top: 4px;\n padding: 12px 14px;\n border: 1px solid var(--mj-border-subtle);\n border-radius: var(--mj-radius-md, 8px);\n background: var(--mj-bg-surface-card);\n cursor: default;\n}\n\n\n\n.card-rich-html[_ngcontent-%COMP%] {\n font-size: 13px;\n line-height: 1.55;\n color: var(--mj-text-primary);\n overflow-x: auto;\n}\n\n.card-rich-html[_ngcontent-%COMP%] img[_ngcontent-%COMP%] {\n max-width: 100%;\n height: auto;\n}\n\n.card-rich-html[_ngcontent-%COMP%] table[_ngcontent-%COMP%] {\n max-width: 100%;\n border-collapse: collapse;\n}\n\n.card-rich-html[_ngcontent-%COMP%] td[_ngcontent-%COMP%], \n.card-rich-html[_ngcontent-%COMP%] th[_ngcontent-%COMP%] {\n padding: 4px 8px;\n border: 1px solid var(--mj-border-subtle);\n}\n\n.card-rich-html[_ngcontent-%COMP%] a[_ngcontent-%COMP%] {\n color: var(--mj-text-link);\n}\n\n.card-rich-html[_ngcontent-%COMP%] h1[_ngcontent-%COMP%], \n.card-rich-html[_ngcontent-%COMP%] h2[_ngcontent-%COMP%], \n.card-rich-html[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0.4em 0 0.3em 0;\n font-size: 1.05em;\n}\n\n.card-rich-md[_ngcontent-%COMP%] {\n display: block;\n font-size: 13px;\n}\n\n.card-expand-btn[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n margin-top: 8px;\n padding: 4px 10px;\n border: none;\n border-radius: var(--mj-radius-full, 999px);\n background: transparent;\n color: var(--mj-brand-primary);\n font-size: 11px;\n font-weight: 700;\n cursor: pointer;\n}\n\n.card-expand-btn[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n\n\n\n\n.card-actions[_ngcontent-%COMP%] {\n flex-shrink: 0;\n display: flex;\n align-items: flex-start;\n}\n\n.card-action-btn[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 10px;\n border: 1px solid transparent;\n border-radius: var(--mj-radius-md, 8px);\n background: transparent;\n color: var(--mj-text-muted);\n font-size: 11px;\n font-weight: 600;\n cursor: pointer;\n transition: background-color 0.15s, color 0.15s;\n}\n\n.card-action-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n border-color: var(--mj-border-default);\n}\n\n\n\n\n@media (max-width: 720px) {\n .notifications-header[_ngcontent-%COMP%] {\n padding: 14px 14px 10px 14px;\n }\n\n .notifications-content[_ngcontent-%COMP%] {\n padding: 12px 12px 24px 12px;\n }\n\n .btn-text[_ngcontent-%COMP%], \n .action-text[_ngcontent-%COMP%] {\n display: none;\n }\n\n .card-header[_ngcontent-%COMP%] {\n flex-direction: column;\n gap: 2px;\n }\n\n .card-time[_ngcontent-%COMP%] {\n order: -1;\n }\n}"] });
|
|
711
915
|
}
|
|
712
916
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(UserNotificationsComponent, [{
|
|
713
917
|
type: Component,
|
|
714
|
-
args: [{ standalone: false, selector: 'app-user-notifications', template: "<div class=\"notifications-container\">\n <!-- Header Section -->\n <div class=\"notifications-header\">\n <div class=\"header-top\">\n <div class=\"header-title\">\n <div class=\"title-icon\">\n <i class=\"fa-solid fa-bell\"></i>\n </div>\n <h1>Notifications</h1>\n </div>\n\n @if (AllNotifications.length > 0) {\n <div class=\"header-actions\">\n @if (UnreadNotifications.length > 0) {\n <button class=\"action-btn action-btn-ghost\"\n type=\"button\"\n (click)=\"markAllAsRead()\"\n aria-label=\"Mark all notifications as read\">\n <i class=\"fa-solid fa-check-double\" aria-hidden=\"true\"></i>\n <span class=\"btn-text\">Mark All Read</span>\n </button>\n }\n @if (ReadNotifications.length > 0) {\n <button class=\"action-btn action-btn-secondary\"\n type=\"button\"\n (click)=\"markAllAsUnread()\"\n aria-label=\"Mark all notifications as unread\">\n <i class=\"fa-solid fa-envelope\" aria-hidden=\"true\"></i>\n <span class=\"btn-text\">Mark All Unread</span>\n </button>\n }\n </div>\n }\n </div>\n\n <!-- Filters Section -->\n @if (AllNotifications.length > 0) {\n <div class=\"filters-section\">\n <!-- Horizontal Slider for Filters (Mobile) -->\n <div class=\"filters-slider\">\n <div class=\"slider-content\">\n <!-- Stats Pills (Filter Tabs) -->\n <div class=\"header-stats\" role=\"group\" aria-label=\"Filter notifications by read status\">\n <input #allRadio type=\"radio\" name=\"UnreadStatus\" value=\"All\"\n (change)=\"onReadRadioChanged($event)\" checked class=\"hidden-radio\"\n id=\"filter-all\" />\n <button class=\"stat-pill\"\n type=\"button\"\n [class.active]=\"radioSelected === 'All'\"\n (click)=\"selectReadOption('All')\"\n [attr.aria-pressed]=\"radioSelected === 'All'\"\n aria-label=\"Show all notifications\">\n <span class=\"stat-label\">All</span>\n <span class=\"stat-count\">{{AllNotifications.length}}</span>\n </button>\n\n <input #unreadRadio type=\"radio\" name=\"UnreadStatus\" value=\"Unread\"\n (change)=\"onReadRadioChanged($event)\" class=\"hidden-radio\"\n id=\"filter-unread\" />\n @if (UnreadNotifications.length > 0 || ReadNotifications.length === 0) {\n <button class=\"stat-pill\"\n type=\"button\"\n [class.active]=\"radioSelected === 'Unread'\"\n [class.has-unread]=\"UnreadNotifications.length > 0\"\n (click)=\"selectReadOption('Unread')\"\n [attr.aria-pressed]=\"radioSelected === 'Unread'\"\n aria-label=\"Show unread notifications\">\n <span class=\"stat-label\">Unread</span>\n <span class=\"stat-count\" [class.unread-count]=\"UnreadNotifications.length > 0\">\n {{UnreadNotifications.length}}\n </span>\n </button>\n }\n\n <input #readRadio type=\"radio\" name=\"UnreadStatus\" value=\"Read\"\n (change)=\"onReadRadioChanged($event)\" class=\"hidden-radio\"\n id=\"filter-read\" />\n @if (ReadNotifications.length > 0 || UnreadNotifications.length === 0) {\n <button class=\"stat-pill\"\n type=\"button\"\n [class.active]=\"radioSelected === 'Read'\"\n (click)=\"selectReadOption('Read')\"\n [attr.aria-pressed]=\"radioSelected === 'Read'\"\n aria-label=\"Show read notifications\">\n <span class=\"stat-label\">Read</span>\n <span class=\"stat-count\">{{ReadNotifications.length}}</span>\n </button>\n }\n </div>\n\n <!-- Native Type Filter Dropdown (in slider on mobile) -->\n @if (notificationTypes.length > 0) {\n <div class=\"filter-item type-filter-slider\">\n <select class=\"type-select\"\n [(ngModel)]=\"selectedTypeFilter\"\n (change)=\"onTypeFilterChange(selectedTypeFilter)\"\n aria-label=\"Filter by notification type\">\n <option [value]=\"null\">All Types</option>\n @for (type of notificationTypes; track type.ID) {\n <option [value]=\"type.ID\">{{type.Name}}</option>\n }\n </select>\n </div>\n }\n </div>\n </div>\n\n <!-- Search Filter (separate, full-width on mobile) -->\n <div class=\"search-section\">\n <div class=\"search-container\">\n <i class=\"fa-solid fa-magnifying-glass search-icon\" aria-hidden=\"true\"></i>\n <input type=\"text\"\n class=\"search-input\"\n placeholder=\"Search notifications...\"\n [value]=\"currentFilter\"\n (input)=\"onFilterChanged($any($event.target).value)\"\n aria-label=\"Search notifications\" />\n </div>\n </div>\n\n <!-- Filter Info Badge -->\n @if (NotificationsToShow.length !== AllNotifications.length) {\n <div class=\"filter-info\">\n <span class=\"filter-badge\">\n <i class=\"fa-solid fa-filter\" aria-hidden=\"true\"></i>\n Showing {{NotificationsToShow.length}} of {{AllNotifications.length}}\n </span>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Notifications Content -->\n <div class=\"notifications-content\">\n @if (NotificationsToShow.length === 0 && AllNotifications.length === 0) {\n <mj-empty-state\n Variant=\"success\"\n Icon=\"fa-solid fa-bell-slash\"\n Title=\"No Notifications\"\n Message=\"You're all caught up! New notifications will appear here.\" />\n } @else if (NotificationsToShow.length === 0) {\n <mj-empty-state\n Variant=\"no-results\"\n Icon=\"fa-solid fa-filter-circle-xmark\"\n Title=\"No Matching Notifications\"\n Message=\"Try adjusting your filters to see more notifications.\" />\n } @else {\n <!-- Notifications List -->\n <div class=\"notifications-list\">\n @for (notification of NotificationsToShow; track notification.ID) {\n <article class=\"notification-card\"\n [class.unread]=\"notification.Unread\"\n [class.clickable]=\"isNotificationClickable(notification)\"\n role=\"article\"\n [attr.aria-label]=\"notification.Title\">\n\n <!-- Unread Indicator Bar -->\n <div class=\"card-indicator\" aria-hidden=\"true\"></div>\n\n <!-- Type Icon -->\n <div class=\"card-icon\"\n [style.background-color]=\"getTypeColor(notification) + '15'\"\n aria-hidden=\"true\">\n <i [class]=\"'fa-solid ' + getTypeIcon(notification)\"\n [style.color]=\"getTypeColor(notification)\"></i>\n </div>\n\n <!-- Content -->\n <div class=\"card-content\" (click)=\"notificationClicked(notification)\">\n <div class=\"card-header\">\n <h3 class=\"card-title\" [class.card-title-unread]=\"notification.Unread\">\n {{notification.Title}}\n </h3>\n <span class=\"card-time\">\n <i class=\"fa-regular fa-clock\" aria-hidden=\"true\"></i>\n <time [attr.datetime]=\"notification.__mj_CreatedAt\">\n {{notification.__mj_CreatedAt | date:'MMM d, h:mm a'}}\n </time>\n </span>\n </div>\n\n <div class=\"card-meta\">\n <span class=\"card-type\"\n [style.background-color]=\"getTypeColor(notification) + '15'\"\n [style.color]=\"getTypeColor(notification)\">\n {{getTypeName(notification)}}\n </span>\n </div>\n\n <p class=\"card-message\">{{notification.Message}}</p>\n </div>\n\n <!-- Actions -->\n <div class=\"card-actions\">\n @if (notification.Unread) {\n <button class=\"card-action-btn\"\n type=\"button\"\n (click)=\"markAsRead(notification, true, null)\"\n [attr.aria-label]=\"'Mark ' + notification.Title + ' as read'\"\n title=\"Mark as Read\">\n <i class=\"fa-solid fa-check\" aria-hidden=\"true\"></i>\n <span class=\"action-text\">Read</span>\n </button>\n } @else {\n <button class=\"card-action-btn\"\n type=\"button\"\n (click)=\"markAsRead(notification, false, null)\"\n [attr.aria-label]=\"'Mark ' + notification.Title + ' as unread'\"\n title=\"Mark as Unread\">\n <i class=\"fa-solid fa-envelope\" aria-hidden=\"true\"></i>\n <span class=\"action-text\">Unread</span>\n </button>\n }\n </div>\n </article>\n }\n </div>\n }\n </div>\n</div>\n", styles: ["/* ===================================\n USER NOTIFICATIONS - MD3 DESIGN\n iPhone-inspired UX with Circular Buttons\n =================================== */\n\n:host {\n display: block;\n width: 100%;\n height: 100%;\n}\n\n/* ===================================\n CONTAINER\n =================================== */\n\n.notifications-container {\n height: 100%;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface-card);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-sm);\n overflow: hidden;\n}\n\n/* ===================================\n HEADER SECTION\n =================================== */\n\n.notifications-header {\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n padding: 0;\n flex-shrink: 0;\n}\n\n/* Header Top Row */\n.header-top {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 24px 24px 16px;\n gap: 16px;\n}\n\n.header-title {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.title-icon {\n width: 48px;\n height: 48px;\n background: var(--mj-brand-primary);\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: 0 4px 12px color-mix(in srgb, var(--mj-brand-primary) 30%, transparent);\n transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.title-icon:hover {\n transform: scale(1.05);\n}\n\n.title-icon i {\n font-size: 22px;\n color: white;\n}\n\n.header-title h1 {\n font-size: 1.75rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin: 0;\n letter-spacing: -0.02em;\n}\n\n/* ===================================\n HEADER ACTIONS - Circular Buttons\n =================================== */\n\n.header-actions {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.action-btn {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 20px;\n border-radius: 9999px; /* Circular design */\n font-size: 14px;\n font-weight: 600;\n border: 2px solid var(--mj-brand-primary);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 44px;\n font-family: inherit;\n}\n\n.action-btn i {\n font-size: 16px;\n transition: transform 0.2s ease;\n}\n\n.action-btn:hover i {\n transform: scale(1.1);\n}\n\n/* Ghost Button - White Background (Mark All Read) */\n.action-btn-ghost {\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.action-btn-ghost:hover {\n background: var(--mj-brand-primary);\n color: white;\n border-color: var(--mj-brand-primary);\n box-shadow: var(--mj-shadow-md);\n}\n\n.action-btn-ghost:active {\n background: var(--mj-brand-primary);\n transform: scale(0.98);\n}\n\n/* Secondary Button */\n.action-btn-secondary {\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.action-btn-secondary:hover {\n background: var(--mj-brand-primary);\n color: white;\n border-color: var(--mj-brand-primary);\n}\n\n.action-btn-secondary:active {\n transform: scale(0.98);\n}\n\n/* ===================================\n FILTERS SECTION\n =================================== */\n\n.filters-section {\n display: flex;\n flex-direction: column;\n gap: 12px;\n background: var(--mj-bg-surface-card);\n border-top: 1px solid var(--mj-border-default);\n}\n\n.filters-slider {\n overflow-x: auto;\n overflow-y: hidden;\n -webkit-overflow-scrolling: touch;\n scrollbar-width: none;\n -ms-overflow-style: none;\n}\n\n.filters-slider::-webkit-scrollbar {\n display: none;\n}\n\n.slider-content {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 16px 24px;\n min-width: min-content;\n}\n\n/* ===================================\n STATS PILLS (Filter Tabs) - Circular with mj-blue Active\n =================================== */\n\n.header-stats {\n display: flex;\n align-items: center;\n gap: 10px;\n flex-shrink: 0;\n}\n\n.hidden-radio {\n position: absolute;\n opacity: 0;\n pointer-events: none;\n}\n\n.stat-pill {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 20px;\n border-radius: 9999px; /* Circular design */\n border: 2px solid var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n font-family: inherit;\n min-height: 44px;\n}\n\n.stat-pill:hover:not(.active) {\n background: var(--mj-bg-surface-card);\n border-color: var(--mj-brand-primary);\n transform: translateY(-1px);\n}\n\n/* Active State - MJ Blue */\n.stat-pill.active {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n color: white;\n box-shadow: 0 4px 12px color-mix(in srgb, var(--mj-brand-primary) 35%, transparent);\n transform: translateY(-1px);\n}\n\n.stat-label {\n font-size: 14px;\n font-weight: 600;\n}\n\n.stat-count {\n font-size: 13px;\n font-weight: 700;\n padding: 4px 10px;\n border-radius: 9999px;\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n min-width: 28px;\n text-align: center;\n transition: all 0.2s ease;\n}\n\n.stat-pill.active .stat-count {\n background: rgba(255, 255, 255, 0.25);\n color: white;\n}\n\n.stat-count.unread-count {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-weight: 700;\n}\n\n.stat-pill.has-unread:not(.active) {\n border-color: var(--mj-brand-primary);\n}\n\n/* ===================================\n TYPE FILTER IN SLIDER\n =================================== */\n\n.type-filter-slider {\n flex-shrink: 0;\n min-width: 180px;\n}\n\n/* ===================================\n SEARCH SECTION\n =================================== */\n\n.search-section {\n padding: 0 24px 16px;\n}\n\n/* ===================================\n FILTER INFO\n =================================== */\n\n.filter-info {\n padding: 0 24px 16px;\n display: flex;\n justify-content: center;\n}\n\n/* Native Select Dropdown Styling */\n.type-select {\n width: 100%;\n padding: 10px 16px;\n border: 2px solid var(--mj-brand-primary);\n border-radius: 9999px; /* Circular design */\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n font-family: inherit;\n appearance: none;\n background-image: url(\"data:image/svg+xml,%3Csvg width='12' height='8' viewBox='0 0 12 8' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1 1.5L6 6.5L11 1.5' stroke='%230076B6' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\");\n background-repeat: no-repeat;\n background-position: right 16px center;\n padding-right: 42px;\n}\n\n.type-select:hover {\n border-color: var(--mj-brand-primary);\n background-color: var(--mj-bg-surface-card);\n}\n\n.type-select:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.search-container {\n position: relative;\n width: 100%;\n max-width: 100%;\n}\n\n.search-icon {\n position: absolute;\n left: 16px;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-secondary);\n font-size: 14px;\n pointer-events: none;\n transition: color 0.2s ease;\n}\n\n.search-input {\n width: 100%;\n padding: 10px 16px 10px 44px;\n border: 2px solid var(--mj-brand-primary);\n border-radius: 9999px; /* Circular design */\n font-size: 14px;\n font-weight: 500;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n font-family: inherit;\n}\n\n.search-input::placeholder {\n color: var(--mj-text-secondary);\n}\n\n.search-input:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface-card);\n}\n\n.search-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n background: var(--mj-bg-surface);\n}\n\n.search-container:focus-within .search-icon {\n color: var(--mj-brand-primary);\n}\n\n.filter-badge {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 14px;\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n border-radius: 9999px; /* Circular design */\n font-size: 13px;\n font-weight: 600;\n border: 1px solid var(--mj-brand-primary);\n}\n\n.filter-badge i {\n font-size: 12px;\n}\n\n/* ===================================\n NOTIFICATIONS CONTENT\n =================================== */\n\n.notifications-content {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n -webkit-overflow-scrolling: touch; /* iPhone smooth scrolling */\n}\n\n/* Custom Scrollbar */\n.notifications-content::-webkit-scrollbar {\n width: 8px;\n}\n\n.notifications-content::-webkit-scrollbar-track {\n background: var(--mj-bg-surface-card);\n}\n\n.notifications-content::-webkit-scrollbar-thumb {\n background: var(--mj-border-default);\n border-radius: 4px;\n}\n\n.notifications-content::-webkit-scrollbar-thumb:hover {\n background: var(--mj-text-muted);\n}\n\n/* ===================================\n NOTIFICATIONS LIST\n =================================== */\n\n.notifications-list {\n background: transparent;\n}\n\n/* ===================================\n NOTIFICATION CARD - iPhone UX Style\n =================================== */\n\n.notification-card {\n display: grid;\n grid-template-columns: 4px 56px 1fr auto;\n gap: 14px;\n align-items: start;\n padding: 16px 20px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n position: relative;\n}\n\n.notification-card:last-child {\n border-bottom: none;\n}\n\n.notification-card:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.notification-card.clickable {\n cursor: pointer;\n}\n\n.notification-card.clickable:active {\n background: var(--mj-bg-surface-sunken);\n transform: scale(0.995);\n}\n\n/* Unread State with Blue Highlight */\n.notification-card.unread {\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.notification-card.unread:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface-card));\n}\n\n/* Card Indicator - Blue Bar for Unread */\n.card-indicator {\n width: 4px;\n height: 100%;\n min-height: 64px;\n border-radius: 2px;\n background: transparent;\n transition: all 0.2s ease;\n align-self: stretch;\n}\n\n.notification-card.unread .card-indicator {\n background: var(--mj-brand-primary);\n box-shadow: 0 0 8px color-mix(in srgb, var(--mj-brand-primary) 50%, transparent);\n}\n\n/* Card Icon - Larger and More Prominent */\n.card-icon {\n width: 56px;\n height: 56px;\n border-radius: 14px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n transition: transform 0.2s ease;\n}\n\n.notification-card:hover .card-icon {\n transform: scale(1.05);\n}\n\n.card-icon i {\n font-size: 24px;\n}\n\n/* Card Content */\n.card-content {\n flex: 1;\n min-width: 0;\n}\n\n.card-header {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: 12px;\n margin-bottom: 6px;\n}\n\n.card-title {\n font-size: 16px;\n font-weight: 500;\n color: var(--mj-text-primary);\n margin: 0;\n line-height: 1.4;\n word-wrap: break-word;\n}\n\n.card-title-unread {\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.notification-card.clickable .card-title {\n color: var(--mj-brand-primary);\n}\n\n.notification-card.clickable:hover .card-title {\n text-decoration: underline;\n}\n\n.card-time {\n display: flex;\n align-items: center;\n gap: 5px;\n font-size: 13px;\n color: var(--mj-text-secondary);\n white-space: nowrap;\n flex-shrink: 0;\n}\n\n.card-time i {\n font-size: 12px;\n}\n\n/* Card Meta */\n.card-meta {\n margin-bottom: 8px;\n}\n\n.card-type {\n display: inline-flex;\n align-items: center;\n padding: 4px 12px;\n border-radius: 9999px; /* Circular design */\n font-size: 12px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.03em;\n}\n\n/* Card Message */\n.card-message {\n font-size: 15px;\n color: var(--mj-text-secondary);\n line-height: 1.5;\n margin: 0;\n display: -webkit-box;\n -webkit-line-clamp: 3;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n/* Card Actions - Circular Buttons */\n.card-actions {\n display: flex;\n align-items: flex-start;\n gap: 8px;\n padding-top: 6px;\n}\n\n.card-action-btn {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 16px;\n border-radius: 9999px; /* Circular design */\n font-size: 13px;\n font-weight: 600;\n border: 2px solid var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n white-space: nowrap;\n font-family: inherit;\n}\n\n.card-action-btn:hover {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n color: white;\n transform: translateY(-1px);\n box-shadow: var(--mj-shadow-md);\n}\n\n.card-action-btn:active {\n transform: translateY(0) scale(0.98);\n}\n\n.card-action-btn i {\n font-size: 13px;\n}\n\n/* ===================================\n ANIMATIONS\n =================================== */\n\n@keyframes slideInUp {\n from {\n opacity: 0;\n transform: translateY(12px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n.notification-card {\n animation: slideInUp 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n/* ===================================\n ACCESSIBILITY\n =================================== */\n\nbutton:focus-visible,\ninput:focus-visible,\nselect:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n/* Reduced Motion */\n@media (prefers-reduced-motion: reduce) {\n *,\n *::before,\n *::after {\n animation-duration: 0.01ms !important;\n animation-iteration-count: 1 !important;\n transition-duration: 0.01ms !important;\n }\n}\n\n/* ===================================\n RESPONSIVE DESIGN - iPhone UX\n =================================== */\n\n/* iPad and smaller */\n@media (max-width: 768px) {\n .notifications-container {\n border-radius: 0;\n box-shadow: none;\n }\n\n .header-top {\n padding: 20px 20px 14px;\n }\n\n .title-icon {\n width: 44px;\n height: 44px;\n }\n\n .title-icon i {\n font-size: 20px;\n }\n\n .header-title h1 {\n font-size: 1.5rem;\n }\n\n /* Horizontal Slider on Mobile */\n .slider-content {\n padding: 14px 20px;\n gap: 10px;\n }\n\n .stat-pill {\n padding: 8px 16px;\n flex-shrink: 0;\n }\n\n .type-filter-slider {\n min-width: 160px;\n }\n\n .search-section {\n padding: 0 20px 14px;\n }\n\n .filter-info {\n padding: 0 20px 14px;\n }\n\n .notification-card {\n grid-template-columns: 4px 52px 1fr;\n gap: 12px;\n padding: 14px 16px;\n }\n\n .card-actions {\n grid-column: 2 / -1;\n padding-top: 10px;\n }\n\n .card-icon {\n width: 52px;\n height: 52px;\n }\n\n .card-icon i {\n font-size: 22px;\n }\n}\n\n/* iPhone SE and smaller */\n@media (max-width: 480px) {\n .header-top {\n flex-direction: column;\n align-items: stretch;\n gap: 12px;\n padding: 16px 16px 12px;\n }\n\n .header-title {\n justify-content: flex-start;\n }\n\n .title-icon {\n width: 40px;\n height: 40px;\n }\n\n .title-icon i {\n font-size: 18px;\n }\n\n .header-title h1 {\n font-size: 1.375rem;\n }\n\n .header-actions {\n width: 100%;\n justify-content: stretch;\n gap: 8px;\n }\n\n .action-btn {\n flex: 1;\n justify-content: center;\n padding: 10px 16px;\n font-size: 13px;\n }\n\n .btn-text {\n display: none;\n }\n\n /* Horizontal Slider - iPhone */\n .slider-content {\n padding: 12px 16px;\n gap: 8px;\n }\n\n .header-stats {\n gap: 8px;\n }\n\n .stat-pill {\n padding: 8px 14px;\n min-height: 40px;\n flex-shrink: 0;\n }\n\n .stat-label {\n font-size: 13px;\n }\n\n .stat-count {\n font-size: 12px;\n padding: 3px 8px;\n min-width: 24px;\n }\n\n .type-filter-slider {\n min-width: 140px;\n }\n\n .type-select,\n .search-input {\n font-size: 16px; /* Prevent iOS zoom on focus */\n }\n\n .search-section {\n padding: 0 16px 12px;\n }\n\n .filter-info {\n padding: 0 16px 12px;\n }\n\n .notification-card {\n grid-template-columns: 3px 48px 1fr;\n gap: 10px;\n padding: 12px 12px;\n }\n\n .card-indicator {\n width: 3px;\n min-height: 56px;\n }\n\n .card-icon {\n width: 48px;\n height: 48px;\n border-radius: 12px;\n }\n\n .card-icon i {\n font-size: 20px;\n }\n\n .card-title {\n font-size: 15px;\n }\n\n .card-time {\n font-size: 12px;\n }\n\n .card-message {\n font-size: 14px;\n -webkit-line-clamp: 2;\n }\n\n .card-type {\n font-size: 11px;\n padding: 3px 10px;\n }\n\n .card-actions {\n padding-top: 8px;\n gap: 6px;\n }\n\n .action-text {\n display: none;\n }\n\n .card-action-btn {\n padding: 8px 12px;\n min-width: 40px;\n justify-content: center;\n }\n\n}\n\n/* iPhone 12/13/14 Pro Max and similar */\n@media (min-width: 390px) and (max-width: 480px) {\n .btn-text {\n display: inline;\n }\n\n .action-btn {\n font-size: 14px;\n }\n}\n\n/* Dark mode support (if needed in future) */\n@media (prefers-color-scheme: dark) {\n /* Dark mode styles would go here */\n}\n"] }]
|
|
715
|
-
}], () => [{ type: i1.SharedService }, { type: i1.NavigationService }, { type: i2.ApplicationManager }],
|
|
716
|
-
|
|
717
|
-
args: ['allRadio']
|
|
718
|
-
}], unreadRadio: [{
|
|
719
|
-
type: ViewChild,
|
|
720
|
-
args: ['unreadRadio']
|
|
721
|
-
}], readRadio: [{
|
|
722
|
-
type: ViewChild,
|
|
723
|
-
args: ['readRadio']
|
|
724
|
-
}] }); })();
|
|
725
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(UserNotificationsComponent, { className: "UserNotificationsComponent", filePath: "src/lib/user-notifications/user-notifications.component.ts", lineNumber: 56 }); })();
|
|
918
|
+
args: [{ standalone: false, selector: 'app-user-notifications', template: "<div class=\"notifications-container\">\n <!-- Header Section -->\n <div class=\"notifications-header\">\n <div class=\"header-top\">\n <div class=\"header-title\">\n <div class=\"title-icon\">\n <i class=\"fa-solid fa-bell\"></i>\n </div>\n <div class=\"title-text\">\n <h1>Notifications</h1>\n @if (UnreadNotifications.length > 0) {\n <span class=\"title-subtitle\">{{UnreadNotifications.length}} unread</span>\n } @else if (AllNotifications.length > 0) {\n <span class=\"title-subtitle\">All caught up</span>\n }\n </div>\n </div>\n\n @if (AllNotifications.length > 0) {\n <div class=\"header-actions\">\n @if (UnreadNotifications.length > 0) {\n <button class=\"action-btn action-btn-ghost\"\n type=\"button\"\n (click)=\"markAllAsRead()\"\n aria-label=\"Mark all notifications as read\">\n <i class=\"fa-solid fa-check-double\" aria-hidden=\"true\"></i>\n <span class=\"btn-text\">Mark All Read</span>\n </button>\n }\n @if (ReadNotifications.length > 0) {\n <button class=\"action-btn action-btn-secondary\"\n type=\"button\"\n (click)=\"markAllAsUnread()\"\n aria-label=\"Mark all notifications as unread\">\n <i class=\"fa-solid fa-envelope\" aria-hidden=\"true\"></i>\n <span class=\"btn-text\">Mark All Unread</span>\n </button>\n }\n </div>\n }\n </div>\n\n <!-- Filters Section -->\n @if (AllNotifications.length > 0) {\n <div class=\"filters-section\">\n <div class=\"filters-slider\">\n <div class=\"slider-content\">\n <!-- Read-status pills -->\n <div class=\"header-stats\" role=\"group\" aria-label=\"Filter notifications by read status\">\n <button class=\"stat-pill\"\n type=\"button\"\n [class.active]=\"radioSelected === 'All'\"\n (click)=\"selectReadOption('All')\"\n [attr.aria-pressed]=\"radioSelected === 'All'\"\n aria-label=\"Show all notifications\">\n <span class=\"stat-label\">All</span>\n <span class=\"stat-count\">{{AllNotifications.length}}</span>\n </button>\n\n @if (UnreadNotifications.length > 0 || ReadNotifications.length === 0) {\n <button class=\"stat-pill\"\n type=\"button\"\n [class.active]=\"radioSelected === 'Unread'\"\n [class.has-unread]=\"UnreadNotifications.length > 0\"\n (click)=\"selectReadOption('Unread')\"\n [attr.aria-pressed]=\"radioSelected === 'Unread'\"\n aria-label=\"Show unread notifications\">\n <span class=\"stat-label\">Unread</span>\n <span class=\"stat-count\" [class.unread-count]=\"UnreadNotifications.length > 0\">\n {{UnreadNotifications.length}}\n </span>\n </button>\n }\n\n @if (ReadNotifications.length > 0 || UnreadNotifications.length === 0) {\n <button class=\"stat-pill\"\n type=\"button\"\n [class.active]=\"radioSelected === 'Read'\"\n (click)=\"selectReadOption('Read')\"\n [attr.aria-pressed]=\"radioSelected === 'Read'\"\n aria-label=\"Show read notifications\">\n <span class=\"stat-label\">Read</span>\n <span class=\"stat-count\">{{ReadNotifications.length}}</span>\n </button>\n }\n </div>\n\n <!-- Type filter -->\n @if (notificationTypes.length > 0) {\n <div class=\"filter-item type-filter-slider\">\n <select class=\"type-select\"\n [(ngModel)]=\"selectedTypeFilter\"\n (change)=\"onTypeFilterChange(selectedTypeFilter)\"\n aria-label=\"Filter by notification type\">\n <option [value]=\"null\">All Types</option>\n @for (type of notificationTypes; track type.ID) {\n <option [value]=\"type.ID\">{{type.Name}}</option>\n }\n </select>\n </div>\n }\n </div>\n </div>\n\n <!-- Search -->\n <div class=\"search-section\">\n <div class=\"search-container\">\n <i class=\"fa-solid fa-magnifying-glass search-icon\" aria-hidden=\"true\"></i>\n <input type=\"text\"\n class=\"search-input\"\n placeholder=\"Search notifications...\"\n [value]=\"currentFilter\"\n (input)=\"onFilterChanged($any($event.target).value)\"\n aria-label=\"Search notifications\" />\n </div>\n </div>\n\n @if (NotificationsToShow.length !== AllNotifications.length) {\n <div class=\"filter-info\">\n <span class=\"filter-badge\">\n <i class=\"fa-solid fa-filter\" aria-hidden=\"true\"></i>\n Showing {{NotificationsToShow.length}} of {{AllNotifications.length}}\n </span>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Notifications Content -->\n <div class=\"notifications-content\">\n @if (NotificationsToShow.length === 0 && AllNotifications.length === 0) {\n <mj-empty-state\n Variant=\"success\"\n Icon=\"fa-solid fa-bell-slash\"\n Title=\"No Notifications\"\n Message=\"You're all caught up! New notifications will appear here.\" />\n } @else if (NotificationsToShow.length === 0) {\n <mj-empty-state\n Variant=\"no-results\"\n Icon=\"fa-solid fa-filter-circle-xmark\"\n Title=\"No Matching Notifications\"\n Message=\"Try adjusting your filters to see more notifications.\" />\n } @else {\n <!-- Day-grouped notification list -->\n <div class=\"notifications-list\">\n @for (group of Groups; track group.Key) {\n <div class=\"group-label\">{{group.Label}}</div>\n\n @for (vm of group.Items; track vm.N.ID) {\n <article class=\"notification-card\"\n [class.unread]=\"vm.N.Unread\"\n [class.expanded]=\"IsExpanded(vm)\"\n [class.clickable]=\"vm.Clickable\"\n role=\"article\"\n [attr.aria-label]=\"vm.N.Title\">\n\n <!-- Unread Indicator Bar -->\n <div class=\"card-indicator\" aria-hidden=\"true\"></div>\n\n <!-- Type Icon -->\n <div class=\"card-icon\" aria-hidden=\"true\">\n <i [class]=\"'fa-solid ' + getTypeIcon(vm.N)\"\n [style.color]=\"getTypeColor(vm.N)\"></i>\n </div>\n\n <!-- Content -->\n <div class=\"card-content\" (click)=\"notificationClicked(vm.N)\">\n <div class=\"card-header\">\n <h3 class=\"card-title\" [class.card-title-unread]=\"vm.N.Unread\">\n {{vm.N.Title}}\n </h3>\n <span class=\"card-time\" [title]=\"(vm.N.__mj_CreatedAt | date:'medium') ?? ''\">\n @if (vm.Relative) {\n {{vm.Relative}}\n } @else {\n <time [attr.datetime]=\"vm.N.__mj_CreatedAt\">{{vm.N.__mj_CreatedAt | date:'MMM d, h:mm a'}}</time>\n }\n </span>\n </div>\n\n <div class=\"card-meta\">\n <span class=\"card-type\">{{getTypeName(vm.N)}}</span>\n @if (vm.Clickable) {\n <span class=\"card-open-hint\">\n <i class=\"fa-solid fa-arrow-up-right-from-square\" aria-hidden=\"true\"></i> Open\n </span>\n }\n </div>\n\n @if (!IsExpanded(vm)) {\n <p class=\"card-message\">{{vm.Preview}}</p>\n } @else {\n <div class=\"card-rich\" (click)=\"$event.stopPropagation()\">\n @switch (vm.Kind) {\n @case ('html') {\n <!-- Angular sanitizes on [innerHTML] bind; chrome tags were stripped at classification -->\n <div class=\"card-rich-html\" [innerHTML]=\"vm.Body\"></div>\n }\n @case ('markdown') {\n <mj-markdown class=\"card-rich-md\" [data]=\"vm.Body\" [enableMermaid]=\"false\"></mj-markdown>\n }\n @default {\n <p class=\"card-message card-message-full\">{{vm.N.Message}}</p>\n }\n }\n </div>\n }\n\n @if (vm.Expandable) {\n <button class=\"card-expand-btn\" type=\"button\"\n (click)=\"ToggleExpanded(vm, $event)\"\n [attr.aria-expanded]=\"IsExpanded(vm)\">\n <i class=\"fa-solid\" [class.fa-chevron-down]=\"!IsExpanded(vm)\" [class.fa-chevron-up]=\"IsExpanded(vm)\" aria-hidden=\"true\"></i>\n {{ IsExpanded(vm) ? 'Show less' : 'Show more' }}\n </button>\n }\n </div>\n\n <!-- Actions -->\n <div class=\"card-actions\">\n @if (vm.N.Unread) {\n <button class=\"card-action-btn\"\n type=\"button\"\n (click)=\"markAsRead(vm.N, true, null)\"\n [attr.aria-label]=\"'Mark ' + vm.N.Title + ' as read'\"\n title=\"Mark as Read\">\n <i class=\"fa-solid fa-check\" aria-hidden=\"true\"></i>\n <span class=\"action-text\">Read</span>\n </button>\n } @else {\n <button class=\"card-action-btn\"\n type=\"button\"\n (click)=\"markAsRead(vm.N, false, null)\"\n [attr.aria-label]=\"'Mark ' + vm.N.Title + ' as unread'\"\n title=\"Mark as Unread\">\n <i class=\"fa-solid fa-envelope\" aria-hidden=\"true\"></i>\n <span class=\"action-text\">Unread</span>\n </button>\n }\n </div>\n </article>\n }\n }\n </div>\n }\n </div>\n</div>\n", styles: ["/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n User Notifications \u2014 day-grouped cards with rich (HTML/Markdown) content,\n expand/collapse, and token-driven theming (light + dark for free).\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n:host {\n display: block;\n height: 100%;\n}\n\n.notifications-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--mj-bg-page);\n}\n\n/* \u2500\u2500 Header \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.notifications-header {\n flex-shrink: 0;\n padding: 20px 24px 12px 24px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.header-top {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 16px;\n margin-bottom: 14px;\n}\n\n.header-title {\n display: flex;\n align-items: center;\n gap: 12px;\n min-width: 0;\n}\n\n.title-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 40px;\n height: 40px;\n border-radius: var(--mj-radius-lg, 12px);\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: 16px;\n}\n\n.title-text {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n\n.title-text h1 {\n margin: 0;\n font-size: 20px;\n font-weight: 700;\n color: var(--mj-text-primary);\n line-height: 1.2;\n}\n\n.title-subtitle {\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n.header-actions {\n display: flex;\n gap: 8px;\n flex-shrink: 0;\n}\n\n.action-btn {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 7px 12px;\n border-radius: var(--mj-radius-md, 8px);\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n font-size: 12px;\n font-weight: 600;\n cursor: pointer;\n transition: background-color 0.15s, color 0.15s, border-color 0.15s;\n}\n\n.action-btn:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n.action-btn-ghost {\n border-color: color-mix(in srgb, var(--mj-brand-primary) 35%, transparent);\n color: var(--mj-brand-primary);\n}\n\n.action-btn-ghost:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n/* \u2500\u2500 Filters \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.filters-section {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 10px;\n}\n\n.filters-slider {\n min-width: 0;\n}\n\n.slider-content {\n display: flex;\n align-items: center;\n gap: 10px;\n flex-wrap: wrap;\n}\n\n.header-stats {\n display: inline-flex;\n gap: 4px;\n padding: 3px;\n border-radius: var(--mj-radius-full, 999px);\n background: var(--mj-bg-surface-sunken);\n}\n\n.stat-pill {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 5px 12px;\n border: none;\n border-radius: var(--mj-radius-full, 999px);\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 12px;\n font-weight: 600;\n cursor: pointer;\n transition: background-color 0.15s, color 0.15s;\n}\n\n.stat-pill:hover {\n color: var(--mj-text-primary);\n}\n\n.stat-pill.active {\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n box-shadow: var(--mj-shadow-sm);\n}\n\n.stat-count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 18px;\n height: 18px;\n padding: 0 5px;\n border-radius: var(--mj-radius-full, 999px);\n background: color-mix(in srgb, var(--mj-text-muted) 14%, transparent);\n color: var(--mj-text-secondary);\n font-size: 10px;\n font-weight: 700;\n}\n\n.stat-count.unread-count {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n color: var(--mj-brand-primary);\n}\n\n.type-select {\n padding: 7px 10px;\n border-radius: var(--mj-radius-md, 8px);\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n font-size: 12px;\n cursor: pointer;\n}\n\n.search-section {\n flex: 1 1 220px;\n min-width: 180px;\n}\n\n.search-container {\n position: relative;\n display: flex;\n align-items: center;\n}\n\n.search-icon {\n position: absolute;\n left: 12px;\n color: var(--mj-text-muted);\n font-size: 12px;\n pointer-events: none;\n}\n\n.search-input {\n width: 100%;\n padding: 8px 12px 8px 32px;\n border-radius: var(--mj-radius-md, 8px);\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n font-size: 13px;\n}\n\n.search-input:focus {\n outline: none;\n border-color: var(--mj-border-focus);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n}\n\n.filter-info {\n flex-basis: 100%;\n}\n\n.filter-badge {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n border-radius: var(--mj-radius-full, 999px);\n background: color-mix(in srgb, var(--mj-status-info) 10%, var(--mj-bg-surface));\n color: var(--mj-status-info);\n font-size: 11px;\n font-weight: 600;\n}\n\n/* \u2500\u2500 Content / list \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.notifications-content {\n flex: 1 1 auto;\n min-height: 0;\n overflow-y: auto;\n padding: 16px 24px 32px 24px;\n}\n\n.notifications-list {\n display: flex;\n flex-direction: column;\n gap: 10px;\n max-width: 960px;\n margin: 0 auto;\n}\n\n.group-label {\n position: sticky;\n top: -16px;\n z-index: 1;\n padding: 10px 2px 4px 2px;\n background: var(--mj-bg-page);\n font-size: 11px;\n font-weight: 700;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n color: var(--mj-text-muted);\n}\n\n.group-label:not(:first-child) {\n margin-top: 8px;\n}\n\n/* \u2500\u2500 Card \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.notification-card {\n position: relative;\n display: flex;\n gap: 12px;\n padding: 14px 16px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg, 12px);\n background: var(--mj-bg-surface);\n transition: border-color 0.15s, box-shadow 0.15s, background-color 0.15s;\n overflow: hidden;\n}\n\n.notification-card:hover {\n border-color: var(--mj-border-strong);\n box-shadow: var(--mj-shadow-sm);\n}\n\n.notification-card.unread {\n background: color-mix(in srgb, var(--mj-brand-primary) 3%, var(--mj-bg-surface));\n}\n\n.card-indicator {\n display: none;\n position: absolute;\n left: 0;\n top: 0;\n bottom: 0;\n width: 3px;\n background: var(--mj-brand-primary);\n border-radius: 0 2px 2px 0;\n}\n\n.notification-card.unread .card-indicator {\n display: block;\n}\n\n.card-icon {\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 36px;\n height: 36px;\n border-radius: var(--mj-radius-md, 10px);\n background: var(--mj-bg-surface-sunken);\n font-size: 14px;\n}\n\n.card-content {\n flex: 1 1 auto;\n min-width: 0;\n}\n\n.notification-card.clickable .card-content {\n cursor: pointer;\n}\n\n.card-header {\n display: flex;\n align-items: baseline;\n justify-content: space-between;\n gap: 12px;\n}\n\n.card-title {\n margin: 0;\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-primary);\n overflow-wrap: anywhere;\n}\n\n.card-title-unread {\n font-weight: 700;\n}\n\n.card-time {\n flex-shrink: 0;\n font-size: 11px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n}\n\n.card-meta {\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 3px 0 6px 0;\n}\n\n.card-type {\n display: inline-flex;\n padding: 2px 8px;\n border-radius: var(--mj-radius-full, 999px);\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n font-size: 10px;\n font-weight: 700;\n letter-spacing: 0.04em;\n text-transform: uppercase;\n}\n\n.card-open-hint {\n display: none;\n align-items: center;\n gap: 4px;\n font-size: 10px;\n font-weight: 600;\n color: var(--mj-brand-primary);\n}\n\n.notification-card.clickable:hover .card-open-hint {\n display: inline-flex;\n}\n\n.card-message {\n margin: 0;\n font-size: 13px;\n line-height: 1.5;\n color: var(--mj-text-secondary);\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n overflow-wrap: anywhere;\n}\n\n.card-message-full {\n display: block;\n -webkit-line-clamp: unset;\n white-space: pre-wrap;\n}\n\n/* \u2500\u2500 Rich (expanded) content \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.card-rich {\n margin-top: 4px;\n padding: 12px 14px;\n border: 1px solid var(--mj-border-subtle);\n border-radius: var(--mj-radius-md, 8px);\n background: var(--mj-bg-surface-card);\n cursor: default;\n}\n\n/* Sanitized foreign markup: keep it inside the card no matter what it brought along */\n.card-rich-html {\n font-size: 13px;\n line-height: 1.55;\n color: var(--mj-text-primary);\n overflow-x: auto;\n}\n\n.card-rich-html img {\n max-width: 100%;\n height: auto;\n}\n\n.card-rich-html table {\n max-width: 100%;\n border-collapse: collapse;\n}\n\n.card-rich-html td,\n.card-rich-html th {\n padding: 4px 8px;\n border: 1px solid var(--mj-border-subtle);\n}\n\n.card-rich-html a {\n color: var(--mj-text-link);\n}\n\n.card-rich-html h1,\n.card-rich-html h2,\n.card-rich-html h3 {\n margin: 0.4em 0 0.3em 0;\n font-size: 1.05em;\n}\n\n.card-rich-md {\n display: block;\n font-size: 13px;\n}\n\n.card-expand-btn {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n margin-top: 8px;\n padding: 4px 10px;\n border: none;\n border-radius: var(--mj-radius-full, 999px);\n background: transparent;\n color: var(--mj-brand-primary);\n font-size: 11px;\n font-weight: 700;\n cursor: pointer;\n}\n\n.card-expand-btn:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n\n/* \u2500\u2500 Card actions \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.card-actions {\n flex-shrink: 0;\n display: flex;\n align-items: flex-start;\n}\n\n.card-action-btn {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 10px;\n border: 1px solid transparent;\n border-radius: var(--mj-radius-md, 8px);\n background: transparent;\n color: var(--mj-text-muted);\n font-size: 11px;\n font-weight: 600;\n cursor: pointer;\n transition: background-color 0.15s, color 0.15s;\n}\n\n.card-action-btn:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n border-color: var(--mj-border-default);\n}\n\n/* \u2500\u2500 Responsive \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n@media (max-width: 720px) {\n .notifications-header {\n padding: 14px 14px 10px 14px;\n }\n\n .notifications-content {\n padding: 12px 12px 24px 12px;\n }\n\n .btn-text,\n .action-text {\n display: none;\n }\n\n .card-header {\n flex-direction: column;\n gap: 2px;\n }\n\n .card-time {\n order: -1;\n }\n}\n"] }]
|
|
919
|
+
}], () => [{ type: i1.SharedService }, { type: i1.NavigationService }, { type: i2.ApplicationManager }], null); })();
|
|
920
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(UserNotificationsComponent, { className: "UserNotificationsComponent", filePath: "src/lib/user-notifications/user-notifications.component.ts", lineNumber: 93 }); })();
|
|
726
921
|
//# sourceMappingURL=user-notifications.component.js.map
|