@memberjunction/ng-explorer-settings 5.35.0 → 5.37.0
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/lib/application-management/application-management.component.d.ts +0 -1
- package/dist/lib/application-management/application-management.component.d.ts.map +1 -1
- package/dist/lib/application-management/application-management.component.js +151 -206
- package/dist/lib/application-management/application-management.component.js.map +1 -1
- package/dist/lib/entity-permissions/entity-permissions.component.d.ts +8 -3
- package/dist/lib/entity-permissions/entity-permissions.component.d.ts.map +1 -1
- package/dist/lib/entity-permissions/entity-permissions.component.js +247 -411
- package/dist/lib/entity-permissions/entity-permissions.component.js.map +1 -1
- package/dist/lib/module.d.ts +1 -1
- package/dist/lib/module.d.ts.map +1 -1
- package/dist/lib/module.js +31 -4
- package/dist/lib/module.js.map +1 -1
- package/dist/lib/role-management/role-management.component.d.ts +0 -2
- package/dist/lib/role-management/role-management.component.d.ts.map +1 -1
- package/dist/lib/role-management/role-management.component.js +136 -259
- package/dist/lib/role-management/role-management.component.js.map +1 -1
- package/dist/lib/sql-logging/sql-logging.component.js +221 -224
- package/dist/lib/sql-logging/sql-logging.component.js.map +1 -1
- package/dist/lib/user-management/user-management.component.d.ts +12 -3
- package/dist/lib/user-management/user-management.component.d.ts.map +1 -1
- package/dist/lib/user-management/user-management.component.js +356 -463
- package/dist/lib/user-management/user-management.component.js.map +1 -1
- package/package.json +19 -19
|
@@ -17,40 +17,40 @@ import * as i3 from "@memberjunction/ng-ui-components";
|
|
|
17
17
|
import * as i4 from "./user-dialog/user-dialog.component";
|
|
18
18
|
import * as i5 from "@angular/common";
|
|
19
19
|
const _forTrack0 = ($index, $item) => $item.ID;
|
|
20
|
-
function
|
|
20
|
+
function UserManagementComponent_Conditional_19_Template(rf, ctx) { if (rf & 1) {
|
|
21
21
|
const _r1 = i0.ɵɵgetCurrentView();
|
|
22
|
-
i0.ɵɵelementStart(0, "div",
|
|
23
|
-
i0.ɵɵelement(2, "i",
|
|
22
|
+
i0.ɵɵelementStart(0, "div", 17)(1, "div", 25);
|
|
23
|
+
i0.ɵɵelement(2, "i", 26);
|
|
24
24
|
i0.ɵɵelementStart(3, "span");
|
|
25
25
|
i0.ɵɵtext(4);
|
|
26
26
|
i0.ɵɵelementEnd();
|
|
27
|
-
i0.ɵɵelementStart(5, "button",
|
|
28
|
-
i0.ɵɵlistener("click", function
|
|
29
|
-
i0.ɵɵelement(6, "i",
|
|
27
|
+
i0.ɵɵelementStart(5, "button", 27);
|
|
28
|
+
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_19_Template_button_click_5_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.clearSelection()); });
|
|
29
|
+
i0.ɵɵelement(6, "i", 28);
|
|
30
30
|
i0.ɵɵtext(7, " Clear ");
|
|
31
31
|
i0.ɵɵelementEnd()();
|
|
32
|
-
i0.ɵɵelementStart(8, "div",
|
|
33
|
-
i0.ɵɵlistener("click", function
|
|
34
|
-
i0.ɵɵelement(10, "i",
|
|
35
|
-
i0.ɵɵelementStart(11, "span",
|
|
32
|
+
i0.ɵɵelementStart(8, "div", 29)(9, "button", 30);
|
|
33
|
+
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_19_Template_button_click_9_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.confirmBulkAction("enable")); });
|
|
34
|
+
i0.ɵɵelement(10, "i", 31);
|
|
35
|
+
i0.ɵɵelementStart(11, "span", 32);
|
|
36
36
|
i0.ɵɵtext(12, "Enable");
|
|
37
37
|
i0.ɵɵelementEnd()();
|
|
38
|
-
i0.ɵɵelementStart(13, "button",
|
|
39
|
-
i0.ɵɵlistener("click", function
|
|
40
|
-
i0.ɵɵelement(14, "i",
|
|
41
|
-
i0.ɵɵelementStart(15, "span",
|
|
38
|
+
i0.ɵɵelementStart(13, "button", 33);
|
|
39
|
+
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_19_Template_button_click_13_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.confirmBulkAction("disable")); });
|
|
40
|
+
i0.ɵɵelement(14, "i", 34);
|
|
41
|
+
i0.ɵɵelementStart(15, "span", 32);
|
|
42
42
|
i0.ɵɵtext(16, "Disable");
|
|
43
43
|
i0.ɵɵelementEnd()();
|
|
44
|
-
i0.ɵɵelementStart(17, "button",
|
|
45
|
-
i0.ɵɵlistener("click", function
|
|
46
|
-
i0.ɵɵelement(18, "i",
|
|
47
|
-
i0.ɵɵelementStart(19, "span",
|
|
44
|
+
i0.ɵɵelementStart(17, "button", 35);
|
|
45
|
+
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_19_Template_button_click_17_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.openBulkRoleAssign()); });
|
|
46
|
+
i0.ɵɵelement(18, "i", 36);
|
|
47
|
+
i0.ɵɵelementStart(19, "span", 32);
|
|
48
48
|
i0.ɵɵtext(20, "Assign Role");
|
|
49
49
|
i0.ɵɵelementEnd()();
|
|
50
|
-
i0.ɵɵelementStart(21, "button",
|
|
51
|
-
i0.ɵɵlistener("click", function
|
|
52
|
-
i0.ɵɵelement(22, "i",
|
|
53
|
-
i0.ɵɵelementStart(23, "span",
|
|
50
|
+
i0.ɵɵelementStart(21, "button", 37);
|
|
51
|
+
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_19_Template_button_click_21_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.confirmBulkAction("delete")); });
|
|
52
|
+
i0.ɵɵelement(22, "i", 38);
|
|
53
|
+
i0.ɵɵelementStart(23, "span", 32);
|
|
54
54
|
i0.ɵɵtext(24, "Delete");
|
|
55
55
|
i0.ɵɵelementEnd()()()();
|
|
56
56
|
} if (rf & 2) {
|
|
@@ -58,95 +58,21 @@ function UserManagementComponent_Conditional_15_Template(rf, ctx) { if (rf & 1)
|
|
|
58
58
|
i0.ɵɵadvance(4);
|
|
59
59
|
i0.ɵɵtextInterpolate2("", ctx_r1.selectedCount, " user", ctx_r1.selectedCount > 1 ? "s" : "", " selected");
|
|
60
60
|
} }
|
|
61
|
-
function
|
|
62
|
-
i0.ɵɵelementStart(0, "
|
|
63
|
-
i0.ɵɵ
|
|
61
|
+
function UserManagementComponent_Conditional_21_Template(rf, ctx) { if (rf & 1) {
|
|
62
|
+
i0.ɵɵelementStart(0, "div", 18);
|
|
63
|
+
i0.ɵɵelement(1, "mj-loading", 39);
|
|
64
64
|
i0.ɵɵelementEnd();
|
|
65
|
-
} if (rf & 2) {
|
|
66
|
-
const ctx_r1 = i0.ɵɵnextContext();
|
|
67
|
-
i0.ɵɵadvance();
|
|
68
|
-
i0.ɵɵtextInterpolate(ctx_r1.activeFilterCount);
|
|
69
65
|
} }
|
|
70
|
-
function
|
|
71
|
-
i0.ɵɵ
|
|
72
|
-
i0.ɵɵ
|
|
73
|
-
i0.ɵɵ
|
|
74
|
-
|
|
75
|
-
const role_r3 = ctx.$implicit;
|
|
76
|
-
i0.ɵɵproperty("value", role_r3.ID);
|
|
77
|
-
i0.ɵɵadvance();
|
|
78
|
-
i0.ɵɵtextInterpolate(role_r3.Name);
|
|
79
|
-
} }
|
|
80
|
-
function UserManagementComponent_Conditional_75_For_19_Template(rf, ctx) { if (rf & 1) {
|
|
81
|
-
i0.ɵɵelementStart(0, "option", 42);
|
|
82
|
-
i0.ɵɵtext(1);
|
|
83
|
-
i0.ɵɵelementEnd();
|
|
84
|
-
} if (rf & 2) {
|
|
85
|
-
const role_r5 = ctx.$implicit;
|
|
86
|
-
i0.ɵɵproperty("value", role_r5.ID);
|
|
87
|
-
i0.ɵɵadvance();
|
|
88
|
-
i0.ɵɵtextInterpolate(role_r5.Name);
|
|
89
|
-
} }
|
|
90
|
-
function UserManagementComponent_Conditional_75_Conditional_20_Template(rf, ctx) { if (rf & 1) {
|
|
91
|
-
const _r6 = i0.ɵɵgetCurrentView();
|
|
92
|
-
i0.ɵɵelementStart(0, "button", 75);
|
|
93
|
-
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_75_Conditional_20_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.clearFilters()); });
|
|
94
|
-
i0.ɵɵelement(1, "i", 55);
|
|
95
|
-
i0.ɵɵtext(2, " Clear Filters ");
|
|
96
|
-
i0.ɵɵelementEnd();
|
|
97
|
-
} }
|
|
98
|
-
function UserManagementComponent_Conditional_75_Template(rf, ctx) { if (rf & 1) {
|
|
99
|
-
const _r4 = i0.ɵɵgetCurrentView();
|
|
100
|
-
i0.ɵɵelementStart(0, "div", 43)(1, "div", 65)(2, "div", 66)(3, "label", 67);
|
|
101
|
-
i0.ɵɵtext(4, "Status");
|
|
102
|
-
i0.ɵɵelementEnd();
|
|
103
|
-
i0.ɵɵelementStart(5, "select", 68);
|
|
104
|
-
i0.ɵɵlistener("change", function UserManagementComponent_Conditional_75_Template_select_change_5_listener($event) { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onStatusFilterChange($event.target.value)); });
|
|
105
|
-
i0.ɵɵelementStart(6, "option", 69);
|
|
106
|
-
i0.ɵɵtext(7, "All Status");
|
|
107
|
-
i0.ɵɵelementEnd();
|
|
108
|
-
i0.ɵɵelementStart(8, "option", 70);
|
|
109
|
-
i0.ɵɵtext(9, "Active");
|
|
110
|
-
i0.ɵɵelementEnd();
|
|
111
|
-
i0.ɵɵelementStart(10, "option", 71);
|
|
112
|
-
i0.ɵɵtext(11, "Inactive");
|
|
113
|
-
i0.ɵɵelementEnd()()();
|
|
114
|
-
i0.ɵɵelementStart(12, "div", 66)(13, "label", 72);
|
|
115
|
-
i0.ɵɵtext(14, "Role");
|
|
116
|
-
i0.ɵɵelementEnd();
|
|
117
|
-
i0.ɵɵelementStart(15, "select", 73);
|
|
118
|
-
i0.ɵɵlistener("change", function UserManagementComponent_Conditional_75_Template_select_change_15_listener($event) { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onRoleFilterChange($event.target.value)); });
|
|
119
|
-
i0.ɵɵelementStart(16, "option", 41);
|
|
120
|
-
i0.ɵɵtext(17, "All Roles");
|
|
121
|
-
i0.ɵɵelementEnd();
|
|
122
|
-
i0.ɵɵrepeaterCreate(18, UserManagementComponent_Conditional_75_For_19_Template, 2, 2, "option", 42, _forTrack0);
|
|
123
|
-
i0.ɵɵelementEnd()();
|
|
124
|
-
i0.ɵɵconditionalCreate(20, UserManagementComponent_Conditional_75_Conditional_20_Template, 3, 0, "button", 74);
|
|
125
|
-
i0.ɵɵelementEnd()();
|
|
126
|
-
} if (rf & 2) {
|
|
127
|
-
const ctx_r1 = i0.ɵɵnextContext();
|
|
128
|
-
i0.ɵɵadvance(5);
|
|
129
|
-
i0.ɵɵproperty("value", ctx_r1.filters$.value.status);
|
|
130
|
-
i0.ɵɵadvance(13);
|
|
131
|
-
i0.ɵɵrepeater(ctx_r1.roles);
|
|
132
|
-
i0.ɵɵadvance(2);
|
|
133
|
-
i0.ɵɵconditional(ctx_r1.hasActiveFilters ? 20 : -1);
|
|
134
|
-
} }
|
|
135
|
-
function UserManagementComponent_Conditional_77_Template(rf, ctx) { if (rf & 1) {
|
|
136
|
-
i0.ɵɵelementStart(0, "div", 45);
|
|
137
|
-
i0.ɵɵelement(1, "mj-loading", 76);
|
|
138
|
-
i0.ɵɵelementEnd();
|
|
139
|
-
} }
|
|
140
|
-
function UserManagementComponent_Conditional_78_Template(rf, ctx) { if (rf & 1) {
|
|
141
|
-
const _r7 = i0.ɵɵgetCurrentView();
|
|
142
|
-
i0.ɵɵelementStart(0, "div", 46)(1, "div", 77);
|
|
143
|
-
i0.ɵɵelement(2, "i", 78);
|
|
144
|
-
i0.ɵɵelementStart(3, "p", 79);
|
|
66
|
+
function UserManagementComponent_Conditional_22_Template(rf, ctx) { if (rf & 1) {
|
|
67
|
+
const _r3 = i0.ɵɵgetCurrentView();
|
|
68
|
+
i0.ɵɵelementStart(0, "div", 19)(1, "div", 40);
|
|
69
|
+
i0.ɵɵelement(2, "i", 41);
|
|
70
|
+
i0.ɵɵelementStart(3, "p", 42);
|
|
145
71
|
i0.ɵɵtext(4);
|
|
146
72
|
i0.ɵɵelementEnd();
|
|
147
|
-
i0.ɵɵelementStart(5, "button",
|
|
148
|
-
i0.ɵɵlistener("click", function
|
|
149
|
-
i0.ɵɵelement(6, "i",
|
|
73
|
+
i0.ɵɵelementStart(5, "button", 43);
|
|
74
|
+
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_22_Template_button_click_5_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.loadInitialData()); });
|
|
75
|
+
i0.ɵɵelement(6, "i", 44);
|
|
150
76
|
i0.ɵɵtext(7, " Try Again ");
|
|
151
77
|
i0.ɵɵelementEnd()()();
|
|
152
78
|
} if (rf & 2) {
|
|
@@ -154,8 +80,8 @@ function UserManagementComponent_Conditional_78_Template(rf, ctx) { if (rf & 1)
|
|
|
154
80
|
i0.ɵɵadvance(4);
|
|
155
81
|
i0.ɵɵtextInterpolate(ctx_r1.error);
|
|
156
82
|
} }
|
|
157
|
-
function
|
|
158
|
-
i0.ɵɵelementStart(0, "span",
|
|
83
|
+
function UserManagementComponent_Conditional_23_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
84
|
+
i0.ɵɵelementStart(0, "span", 49);
|
|
159
85
|
i0.ɵɵtext(1);
|
|
160
86
|
i0.ɵɵelementEnd();
|
|
161
87
|
} if (rf & 2) {
|
|
@@ -163,271 +89,271 @@ function UserManagementComponent_Conditional_79_Conditional_7_Template(rf, ctx)
|
|
|
163
89
|
i0.ɵɵadvance();
|
|
164
90
|
i0.ɵɵtextInterpolate1("", ctx_r1.selectedCount, " selected");
|
|
165
91
|
} }
|
|
166
|
-
function
|
|
167
|
-
i0.ɵɵelementStart(0, "div",
|
|
168
|
-
i0.ɵɵelement(1, "i",
|
|
92
|
+
function UserManagementComponent_Conditional_23_For_8_Conditional_25_Conditional_50_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
93
|
+
i0.ɵɵelementStart(0, "div", 89);
|
|
94
|
+
i0.ɵɵelement(1, "i", 90);
|
|
169
95
|
i0.ɵɵtext(2);
|
|
170
96
|
i0.ɵɵelementEnd();
|
|
171
97
|
} if (rf & 2) {
|
|
172
|
-
const
|
|
98
|
+
const role_r8 = ctx.$implicit;
|
|
173
99
|
i0.ɵɵadvance(2);
|
|
174
|
-
i0.ɵɵtextInterpolate1(" ",
|
|
100
|
+
i0.ɵɵtextInterpolate1(" ", role_r8.Name, " ");
|
|
175
101
|
} }
|
|
176
|
-
function
|
|
177
|
-
i0.ɵɵelementStart(0, "div",
|
|
178
|
-
i0.ɵɵrepeaterCreate(1,
|
|
102
|
+
function UserManagementComponent_Conditional_23_For_8_Conditional_25_Conditional_50_Template(rf, ctx) { if (rf & 1) {
|
|
103
|
+
i0.ɵɵelementStart(0, "div", 87);
|
|
104
|
+
i0.ɵɵrepeaterCreate(1, UserManagementComponent_Conditional_23_For_8_Conditional_25_Conditional_50_For_2_Template, 3, 1, "div", 89, _forTrack0);
|
|
179
105
|
i0.ɵɵelementEnd();
|
|
180
106
|
} if (rf & 2) {
|
|
181
|
-
const
|
|
107
|
+
const user_r6 = i0.ɵɵnextContext(2).$implicit;
|
|
182
108
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
183
109
|
i0.ɵɵadvance();
|
|
184
|
-
i0.ɵɵrepeater(ctx_r1.getUserRoles(
|
|
110
|
+
i0.ɵɵrepeater(ctx_r1.getUserRoles(user_r6.ID));
|
|
185
111
|
} }
|
|
186
|
-
function
|
|
187
|
-
i0.ɵɵelementStart(0, "p",
|
|
112
|
+
function UserManagementComponent_Conditional_23_For_8_Conditional_25_Conditional_51_Template(rf, ctx) { if (rf & 1) {
|
|
113
|
+
i0.ɵɵelementStart(0, "p", 88);
|
|
188
114
|
i0.ɵɵtext(1, "No roles assigned to this user");
|
|
189
115
|
i0.ɵɵelementEnd();
|
|
190
116
|
} }
|
|
191
|
-
function
|
|
192
|
-
const
|
|
193
|
-
i0.ɵɵelementStart(0, "div",
|
|
194
|
-
i0.ɵɵlistener("click", function
|
|
195
|
-
i0.ɵɵelementStart(2, "span",
|
|
196
|
-
i0.ɵɵelement(3, "i",
|
|
117
|
+
function UserManagementComponent_Conditional_23_For_8_Conditional_25_Template(rf, ctx) { if (rf & 1) {
|
|
118
|
+
const _r7 = i0.ɵɵgetCurrentView();
|
|
119
|
+
i0.ɵɵelementStart(0, "div", 71)(1, "div", 72);
|
|
120
|
+
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_23_For_8_Conditional_25_Template_div_click_1_listener($event) { i0.ɵɵrestoreView(_r7); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
121
|
+
i0.ɵɵelementStart(2, "span", 62);
|
|
122
|
+
i0.ɵɵelement(3, "i", 63);
|
|
197
123
|
i0.ɵɵtext(4);
|
|
198
124
|
i0.ɵɵelementEnd();
|
|
199
|
-
i0.ɵɵelementStart(5, "div",
|
|
200
|
-
i0.ɵɵlistener("click", function
|
|
201
|
-
i0.ɵɵelement(7, "i",
|
|
202
|
-
i0.ɵɵelementStart(8, "span",
|
|
125
|
+
i0.ɵɵelementStart(5, "div", 73)(6, "button", 74);
|
|
126
|
+
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_23_For_8_Conditional_25_Template_button_click_6_listener() { i0.ɵɵrestoreView(_r7); const user_r6 = i0.ɵɵnextContext().$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.editUser(user_r6)); });
|
|
127
|
+
i0.ɵɵelement(7, "i", 66);
|
|
128
|
+
i0.ɵɵelementStart(8, "span", 75);
|
|
203
129
|
i0.ɵɵtext(9, "Edit");
|
|
204
130
|
i0.ɵɵelementEnd()();
|
|
205
|
-
i0.ɵɵelementStart(10, "button",
|
|
206
|
-
i0.ɵɵlistener("click", function
|
|
207
|
-
i0.ɵɵelement(11, "i",
|
|
208
|
-
i0.ɵɵelementStart(12, "span",
|
|
131
|
+
i0.ɵɵelementStart(10, "button", 74);
|
|
132
|
+
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_23_For_8_Conditional_25_Template_button_click_10_listener() { i0.ɵɵrestoreView(_r7); const user_r6 = i0.ɵɵnextContext().$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleUserStatus(user_r6)); });
|
|
133
|
+
i0.ɵɵelement(11, "i", 63);
|
|
134
|
+
i0.ɵɵelementStart(12, "span", 75);
|
|
209
135
|
i0.ɵɵtext(13);
|
|
210
136
|
i0.ɵɵelementEnd()();
|
|
211
|
-
i0.ɵɵelementStart(14, "button",
|
|
212
|
-
i0.ɵɵlistener("click", function
|
|
213
|
-
i0.ɵɵelement(15, "i",
|
|
214
|
-
i0.ɵɵelementStart(16, "span",
|
|
137
|
+
i0.ɵɵelementStart(14, "button", 76);
|
|
138
|
+
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_23_For_8_Conditional_25_Template_button_click_14_listener() { i0.ɵɵrestoreView(_r7); const user_r6 = i0.ɵɵnextContext().$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.confirmDeleteUser(user_r6)); });
|
|
139
|
+
i0.ɵɵelement(15, "i", 38);
|
|
140
|
+
i0.ɵɵelementStart(16, "span", 75);
|
|
215
141
|
i0.ɵɵtext(17, "Delete");
|
|
216
142
|
i0.ɵɵelementEnd()()()();
|
|
217
|
-
i0.ɵɵelementStart(18, "div",
|
|
218
|
-
i0.ɵɵelement(20, "i",
|
|
219
|
-
i0.ɵɵelementStart(21, "span",
|
|
143
|
+
i0.ɵɵelementStart(18, "div", 77)(19, "div", 78);
|
|
144
|
+
i0.ɵɵelement(20, "i", 36);
|
|
145
|
+
i0.ɵɵelementStart(21, "span", 79);
|
|
220
146
|
i0.ɵɵtext(22, "Type:");
|
|
221
147
|
i0.ɵɵelementEnd();
|
|
222
|
-
i0.ɵɵelementStart(23, "span",
|
|
223
|
-
i0.ɵɵelement(24, "i",
|
|
148
|
+
i0.ɵɵelementStart(23, "span", 80);
|
|
149
|
+
i0.ɵɵelement(24, "i", 63);
|
|
224
150
|
i0.ɵɵtext(25);
|
|
225
151
|
i0.ɵɵelementEnd()();
|
|
226
|
-
i0.ɵɵelementStart(26, "div",
|
|
227
|
-
i0.ɵɵelement(27, "i",
|
|
228
|
-
i0.ɵɵelementStart(28, "span",
|
|
152
|
+
i0.ɵɵelementStart(26, "div", 78);
|
|
153
|
+
i0.ɵɵelement(27, "i", 81);
|
|
154
|
+
i0.ɵɵelementStart(28, "span", 79);
|
|
229
155
|
i0.ɵɵtext(29, "Full Name:");
|
|
230
156
|
i0.ɵɵelementEnd();
|
|
231
|
-
i0.ɵɵelementStart(30, "span",
|
|
157
|
+
i0.ɵɵelementStart(30, "span", 80);
|
|
232
158
|
i0.ɵɵtext(31);
|
|
233
159
|
i0.ɵɵelementEnd()();
|
|
234
|
-
i0.ɵɵelementStart(32, "div",
|
|
235
|
-
i0.ɵɵelement(33, "i",
|
|
236
|
-
i0.ɵɵelementStart(34, "span",
|
|
160
|
+
i0.ɵɵelementStart(32, "div", 78);
|
|
161
|
+
i0.ɵɵelement(33, "i", 82);
|
|
162
|
+
i0.ɵɵelementStart(34, "span", 79);
|
|
237
163
|
i0.ɵɵtext(35, "Created:");
|
|
238
164
|
i0.ɵɵelementEnd();
|
|
239
|
-
i0.ɵɵelementStart(36, "span",
|
|
165
|
+
i0.ɵɵelementStart(36, "span", 80);
|
|
240
166
|
i0.ɵɵtext(37);
|
|
241
167
|
i0.ɵɵpipe(38, "date");
|
|
242
168
|
i0.ɵɵelementEnd()();
|
|
243
|
-
i0.ɵɵelementStart(39, "div",
|
|
244
|
-
i0.ɵɵelement(40, "i",
|
|
245
|
-
i0.ɵɵelementStart(41, "span",
|
|
169
|
+
i0.ɵɵelementStart(39, "div", 78);
|
|
170
|
+
i0.ɵɵelement(40, "i", 83);
|
|
171
|
+
i0.ɵɵelementStart(41, "span", 79);
|
|
246
172
|
i0.ɵɵtext(42, "Updated:");
|
|
247
173
|
i0.ɵɵelementEnd();
|
|
248
|
-
i0.ɵɵelementStart(43, "span",
|
|
174
|
+
i0.ɵɵelementStart(43, "span", 80);
|
|
249
175
|
i0.ɵɵtext(44);
|
|
250
176
|
i0.ɵɵpipe(45, "date");
|
|
251
177
|
i0.ɵɵelementEnd()()();
|
|
252
|
-
i0.ɵɵelementStart(46, "div",
|
|
253
|
-
i0.ɵɵelement(48, "i",
|
|
178
|
+
i0.ɵɵelementStart(46, "div", 84)(47, "h4", 85);
|
|
179
|
+
i0.ɵɵelement(48, "i", 86);
|
|
254
180
|
i0.ɵɵtext(49, " Assigned Roles ");
|
|
255
181
|
i0.ɵɵelementEnd();
|
|
256
|
-
i0.ɵɵconditionalCreate(50,
|
|
182
|
+
i0.ɵɵconditionalCreate(50, UserManagementComponent_Conditional_23_For_8_Conditional_25_Conditional_50_Template, 3, 0, "div", 87)(51, UserManagementComponent_Conditional_23_For_8_Conditional_25_Conditional_51_Template, 2, 0, "p", 88);
|
|
257
183
|
i0.ɵɵelementEnd()();
|
|
258
184
|
} if (rf & 2) {
|
|
259
|
-
const
|
|
185
|
+
const user_r6 = i0.ɵɵnextContext().$implicit;
|
|
260
186
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
261
187
|
i0.ɵɵadvance(2);
|
|
262
|
-
i0.ɵɵclassMap(ctx_r1.getStatusClass(
|
|
188
|
+
i0.ɵɵclassMap(ctx_r1.getStatusClass(user_r6));
|
|
263
189
|
i0.ɵɵadvance();
|
|
264
|
-
i0.ɵɵclassMap("fa-solid " + ctx_r1.getStatusIcon(
|
|
190
|
+
i0.ɵɵclassMap("fa-solid " + ctx_r1.getStatusIcon(user_r6));
|
|
265
191
|
i0.ɵɵadvance();
|
|
266
|
-
i0.ɵɵtextInterpolate1(" ",
|
|
192
|
+
i0.ɵɵtextInterpolate1(" ", user_r6.IsActive ? "Active" : "Inactive", " ");
|
|
267
193
|
i0.ɵɵadvance(2);
|
|
268
|
-
i0.ɵɵattribute("aria-label", "Edit " +
|
|
194
|
+
i0.ɵɵattribute("aria-label", "Edit " + user_r6.Name);
|
|
269
195
|
i0.ɵɵadvance(4);
|
|
270
|
-
i0.ɵɵattribute("aria-label", (
|
|
196
|
+
i0.ɵɵattribute("aria-label", (user_r6.IsActive ? "Deactivate " : "Activate ") + user_r6.Name);
|
|
271
197
|
i0.ɵɵadvance();
|
|
272
|
-
i0.ɵɵclassMap(
|
|
198
|
+
i0.ɵɵclassMap(user_r6.IsActive ? "fa-solid fa-toggle-on" : "fa-solid fa-toggle-off");
|
|
273
199
|
i0.ɵɵadvance(2);
|
|
274
|
-
i0.ɵɵtextInterpolate(
|
|
200
|
+
i0.ɵɵtextInterpolate(user_r6.IsActive ? "Disable" : "Enable");
|
|
275
201
|
i0.ɵɵadvance();
|
|
276
|
-
i0.ɵɵattribute("aria-label", "Delete " +
|
|
202
|
+
i0.ɵɵattribute("aria-label", "Delete " + user_r6.Name);
|
|
277
203
|
i0.ɵɵadvance(10);
|
|
278
|
-
i0.ɵɵclassMap("fa-solid " + ctx_r1.getUserTypeIcon(
|
|
204
|
+
i0.ɵɵclassMap("fa-solid " + ctx_r1.getUserTypeIcon(user_r6));
|
|
279
205
|
i0.ɵɵadvance();
|
|
280
|
-
i0.ɵɵtextInterpolate1(" ",
|
|
206
|
+
i0.ɵɵtextInterpolate1(" ", user_r6.Type, " ");
|
|
281
207
|
i0.ɵɵadvance(6);
|
|
282
|
-
i0.ɵɵtextInterpolate2("",
|
|
208
|
+
i0.ɵɵtextInterpolate2("", user_r6.FirstName, " ", user_r6.LastName);
|
|
283
209
|
i0.ɵɵadvance(6);
|
|
284
|
-
i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(38, 19,
|
|
210
|
+
i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(38, 19, user_r6.__mj_CreatedAt, "short"));
|
|
285
211
|
i0.ɵɵadvance(7);
|
|
286
|
-
i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(45, 22,
|
|
212
|
+
i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(45, 22, user_r6.__mj_UpdatedAt, "short"));
|
|
287
213
|
i0.ɵɵadvance(6);
|
|
288
|
-
i0.ɵɵconditional(ctx_r1.getUserRoles(
|
|
214
|
+
i0.ɵɵconditional(ctx_r1.getUserRoles(user_r6.ID).length > 0 ? 50 : 51);
|
|
289
215
|
} }
|
|
290
|
-
function
|
|
291
|
-
const
|
|
292
|
-
i0.ɵɵelementStart(0, "div",
|
|
293
|
-
i0.ɵɵlistener("click", function
|
|
294
|
-
i0.ɵɵelementStart(2, "div",
|
|
295
|
-
i0.ɵɵlistener("click", function
|
|
296
|
-
i0.ɵɵelementStart(3, "input",
|
|
297
|
-
i0.ɵɵlistener("change", function
|
|
216
|
+
function UserManagementComponent_Conditional_23_For_8_Template(rf, ctx) { if (rf & 1) {
|
|
217
|
+
const _r5 = i0.ɵɵgetCurrentView();
|
|
218
|
+
i0.ɵɵelementStart(0, "div", 52)(1, "div", 53);
|
|
219
|
+
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_23_For_8_Template_div_click_1_listener() { const user_r6 = i0.ɵɵrestoreView(_r5).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleUserExpansion(user_r6.ID)); })("keydown.enter", function UserManagementComponent_Conditional_23_For_8_Template_div_keydown_enter_1_listener() { const user_r6 = i0.ɵɵrestoreView(_r5).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleUserExpansion(user_r6.ID)); });
|
|
220
|
+
i0.ɵɵelementStart(2, "div", 54);
|
|
221
|
+
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_23_For_8_Template_div_click_2_listener($event) { i0.ɵɵrestoreView(_r5); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
222
|
+
i0.ɵɵelementStart(3, "input", 55);
|
|
223
|
+
i0.ɵɵlistener("change", function UserManagementComponent_Conditional_23_For_8_Template_input_change_3_listener($event) { const user_r6 = i0.ɵɵrestoreView(_r5).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleUserSelection(user_r6.ID, $event)); });
|
|
298
224
|
i0.ɵɵelementEnd()();
|
|
299
|
-
i0.ɵɵelementStart(4, "div",
|
|
225
|
+
i0.ɵɵelementStart(4, "div", 56)(5, "div", 57);
|
|
300
226
|
i0.ɵɵtext(6);
|
|
301
227
|
i0.ɵɵelementEnd();
|
|
302
|
-
i0.ɵɵelementStart(7, "div",
|
|
228
|
+
i0.ɵɵelementStart(7, "div", 58)(8, "h3", 59);
|
|
303
229
|
i0.ɵɵtext(9);
|
|
304
230
|
i0.ɵɵelementEnd();
|
|
305
|
-
i0.ɵɵelementStart(10, "p",
|
|
231
|
+
i0.ɵɵelementStart(10, "p", 60);
|
|
306
232
|
i0.ɵɵtext(11);
|
|
307
233
|
i0.ɵɵelementEnd()()();
|
|
308
|
-
i0.ɵɵelementStart(12, "div",
|
|
309
|
-
i0.ɵɵelement(14, "i",
|
|
234
|
+
i0.ɵɵelementStart(12, "div", 61)(13, "span", 62);
|
|
235
|
+
i0.ɵɵelement(14, "i", 63);
|
|
310
236
|
i0.ɵɵtext(15);
|
|
311
237
|
i0.ɵɵelementEnd();
|
|
312
|
-
i0.ɵɵelementStart(16, "div",
|
|
313
|
-
i0.ɵɵlistener("click", function
|
|
314
|
-
i0.ɵɵelementStart(17, "button",
|
|
315
|
-
i0.ɵɵlistener("click", function
|
|
316
|
-
i0.ɵɵelement(18, "i",
|
|
238
|
+
i0.ɵɵelementStart(16, "div", 64);
|
|
239
|
+
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_23_For_8_Template_div_click_16_listener($event) { i0.ɵɵrestoreView(_r5); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
240
|
+
i0.ɵɵelementStart(17, "button", 65);
|
|
241
|
+
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_23_For_8_Template_button_click_17_listener() { const user_r6 = i0.ɵɵrestoreView(_r5).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.editUser(user_r6)); });
|
|
242
|
+
i0.ɵɵelement(18, "i", 66);
|
|
317
243
|
i0.ɵɵelementEnd();
|
|
318
|
-
i0.ɵɵelementStart(19, "button",
|
|
319
|
-
i0.ɵɵlistener("click", function
|
|
320
|
-
i0.ɵɵelement(20, "i",
|
|
244
|
+
i0.ɵɵelementStart(19, "button", 67);
|
|
245
|
+
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_23_For_8_Template_button_click_19_listener() { const user_r6 = i0.ɵɵrestoreView(_r5).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleUserStatus(user_r6)); });
|
|
246
|
+
i0.ɵɵelement(20, "i", 63);
|
|
321
247
|
i0.ɵɵelementEnd();
|
|
322
|
-
i0.ɵɵelementStart(21, "button",
|
|
323
|
-
i0.ɵɵlistener("click", function
|
|
324
|
-
i0.ɵɵelement(22, "i",
|
|
248
|
+
i0.ɵɵelementStart(21, "button", 68);
|
|
249
|
+
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_23_For_8_Template_button_click_21_listener() { const user_r6 = i0.ɵɵrestoreView(_r5).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.confirmDeleteUser(user_r6)); });
|
|
250
|
+
i0.ɵɵelement(22, "i", 38);
|
|
325
251
|
i0.ɵɵelementEnd()();
|
|
326
|
-
i0.ɵɵelementStart(23, "button",
|
|
327
|
-
i0.ɵɵelement(24, "i",
|
|
252
|
+
i0.ɵɵelementStart(23, "button", 69);
|
|
253
|
+
i0.ɵɵelement(24, "i", 70);
|
|
328
254
|
i0.ɵɵelementEnd()()();
|
|
329
|
-
i0.ɵɵconditionalCreate(25,
|
|
255
|
+
i0.ɵɵconditionalCreate(25, UserManagementComponent_Conditional_23_For_8_Conditional_25_Template, 52, 25, "div", 71);
|
|
330
256
|
i0.ɵɵelementEnd();
|
|
331
257
|
} if (rf & 2) {
|
|
332
|
-
const
|
|
258
|
+
const user_r6 = ctx.$implicit;
|
|
333
259
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
334
|
-
i0.ɵɵclassProp("expanded", ctx_r1.isUserExpanded(
|
|
260
|
+
i0.ɵɵclassProp("expanded", ctx_r1.isUserExpanded(user_r6.ID))("selected", ctx_r1.isUserSelected(user_r6.ID));
|
|
335
261
|
i0.ɵɵadvance();
|
|
336
|
-
i0.ɵɵattribute("aria-expanded", ctx_r1.isUserExpanded(
|
|
262
|
+
i0.ɵɵattribute("aria-expanded", ctx_r1.isUserExpanded(user_r6.ID));
|
|
337
263
|
i0.ɵɵadvance(2);
|
|
338
|
-
i0.ɵɵproperty("checked", ctx_r1.isUserSelected(
|
|
339
|
-
i0.ɵɵattribute("aria-label", "Select " +
|
|
264
|
+
i0.ɵɵproperty("checked", ctx_r1.isUserSelected(user_r6.ID));
|
|
265
|
+
i0.ɵɵattribute("aria-label", "Select " + user_r6.Name);
|
|
340
266
|
i0.ɵɵadvance(3);
|
|
341
|
-
i0.ɵɵtextInterpolate1(" ", ctx_r1.getUserInitials(
|
|
267
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r1.getUserInitials(user_r6), " ");
|
|
342
268
|
i0.ɵɵadvance(3);
|
|
343
|
-
i0.ɵɵtextInterpolate(
|
|
269
|
+
i0.ɵɵtextInterpolate(user_r6.Name);
|
|
344
270
|
i0.ɵɵadvance(2);
|
|
345
|
-
i0.ɵɵtextInterpolate(
|
|
271
|
+
i0.ɵɵtextInterpolate(user_r6.Email);
|
|
346
272
|
i0.ɵɵadvance(2);
|
|
347
|
-
i0.ɵɵclassMap(ctx_r1.getStatusClass(
|
|
273
|
+
i0.ɵɵclassMap(ctx_r1.getStatusClass(user_r6));
|
|
348
274
|
i0.ɵɵadvance();
|
|
349
|
-
i0.ɵɵclassMap("fa-solid " + ctx_r1.getStatusIcon(
|
|
275
|
+
i0.ɵɵclassMap("fa-solid " + ctx_r1.getStatusIcon(user_r6));
|
|
350
276
|
i0.ɵɵadvance();
|
|
351
|
-
i0.ɵɵtextInterpolate1(" ",
|
|
277
|
+
i0.ɵɵtextInterpolate1(" ", user_r6.IsActive ? "Active" : "Inactive", " ");
|
|
352
278
|
i0.ɵɵadvance(2);
|
|
353
|
-
i0.ɵɵattribute("aria-label", "Edit " +
|
|
279
|
+
i0.ɵɵattribute("aria-label", "Edit " + user_r6.Name);
|
|
354
280
|
i0.ɵɵadvance(2);
|
|
355
|
-
i0.ɵɵproperty("title",
|
|
356
|
-
i0.ɵɵattribute("aria-label", (
|
|
281
|
+
i0.ɵɵproperty("title", user_r6.IsActive ? "Deactivate" : "Activate");
|
|
282
|
+
i0.ɵɵattribute("aria-label", (user_r6.IsActive ? "Deactivate " : "Activate ") + user_r6.Name);
|
|
357
283
|
i0.ɵɵadvance();
|
|
358
|
-
i0.ɵɵclassMap(
|
|
284
|
+
i0.ɵɵclassMap(user_r6.IsActive ? "fa-solid fa-toggle-on" : "fa-solid fa-toggle-off");
|
|
359
285
|
i0.ɵɵadvance();
|
|
360
|
-
i0.ɵɵattribute("aria-label", "Delete " +
|
|
286
|
+
i0.ɵɵattribute("aria-label", "Delete " + user_r6.Name);
|
|
361
287
|
i0.ɵɵadvance(4);
|
|
362
|
-
i0.ɵɵconditional(ctx_r1.isUserExpanded(
|
|
288
|
+
i0.ɵɵconditional(ctx_r1.isUserExpanded(user_r6.ID) ? 25 : -1);
|
|
363
289
|
} }
|
|
364
|
-
function
|
|
365
|
-
i0.ɵɵelementStart(0, "div",
|
|
366
|
-
i0.ɵɵelement(1, "i",
|
|
367
|
-
i0.ɵɵelementStart(2, "p",
|
|
290
|
+
function UserManagementComponent_Conditional_23_Conditional_9_Template(rf, ctx) { if (rf & 1) {
|
|
291
|
+
i0.ɵɵelementStart(0, "div", 51);
|
|
292
|
+
i0.ɵɵelement(1, "i", 91);
|
|
293
|
+
i0.ɵɵelementStart(2, "p", 92);
|
|
368
294
|
i0.ɵɵtext(3, "No users found");
|
|
369
295
|
i0.ɵɵelementEnd();
|
|
370
|
-
i0.ɵɵelementStart(4, "p",
|
|
296
|
+
i0.ɵɵelementStart(4, "p", 93);
|
|
371
297
|
i0.ɵɵtext(5, "Try adjusting your filters or add a new user");
|
|
372
298
|
i0.ɵɵelementEnd()();
|
|
373
299
|
} }
|
|
374
|
-
function
|
|
375
|
-
const
|
|
376
|
-
i0.ɵɵelementStart(0, "div",
|
|
377
|
-
i0.ɵɵlistener("change", function
|
|
300
|
+
function UserManagementComponent_Conditional_23_Template(rf, ctx) { if (rf & 1) {
|
|
301
|
+
const _r4 = i0.ɵɵgetCurrentView();
|
|
302
|
+
i0.ɵɵelementStart(0, "div", 20)(1, "div", 45)(2, "label", 46)(3, "input", 47);
|
|
303
|
+
i0.ɵɵlistener("change", function UserManagementComponent_Conditional_23_Template_input_change_3_listener() { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.toggleSelectAll()); });
|
|
378
304
|
i0.ɵɵelementEnd();
|
|
379
|
-
i0.ɵɵelementStart(
|
|
380
|
-
i0.ɵɵtext(
|
|
305
|
+
i0.ɵɵelementStart(4, "span", 48);
|
|
306
|
+
i0.ɵɵtext(5);
|
|
381
307
|
i0.ɵɵelementEnd()();
|
|
382
|
-
i0.ɵɵconditionalCreate(
|
|
308
|
+
i0.ɵɵconditionalCreate(6, UserManagementComponent_Conditional_23_Conditional_6_Template, 2, 1, "span", 49);
|
|
309
|
+
i0.ɵɵelementEnd();
|
|
310
|
+
i0.ɵɵrepeaterCreate(7, UserManagementComponent_Conditional_23_For_8_Template, 26, 22, "div", 50, _forTrack0);
|
|
311
|
+
i0.ɵɵconditionalCreate(9, UserManagementComponent_Conditional_23_Conditional_9_Template, 6, 0, "div", 51);
|
|
383
312
|
i0.ɵɵelementEnd();
|
|
384
|
-
i0.ɵɵrepeaterCreate(8, UserManagementComponent_Conditional_79_For_9_Template, 26, 22, "div", 87, _forTrack0);
|
|
385
|
-
i0.ɵɵconditionalCreate(10, UserManagementComponent_Conditional_79_Conditional_10_Template, 6, 0, "div", 88);
|
|
386
|
-
i0.ɵɵelementEnd()();
|
|
387
313
|
} if (rf & 2) {
|
|
388
314
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
389
|
-
i0.ɵɵadvance(
|
|
315
|
+
i0.ɵɵadvance(3);
|
|
390
316
|
i0.ɵɵproperty("checked", ctx_r1.isAllSelected)("indeterminate", ctx_r1.isIndeterminate);
|
|
391
317
|
i0.ɵɵadvance(2);
|
|
392
318
|
i0.ɵɵtextInterpolate1("Select All (", ctx_r1.filteredUsers.length, ")");
|
|
393
319
|
i0.ɵɵadvance();
|
|
394
|
-
i0.ɵɵconditional(ctx_r1.hasSelection ?
|
|
320
|
+
i0.ɵɵconditional(ctx_r1.hasSelection ? 6 : -1);
|
|
395
321
|
i0.ɵɵadvance();
|
|
396
322
|
i0.ɵɵrepeater(ctx_r1.filteredUsers);
|
|
397
323
|
i0.ɵɵadvance(2);
|
|
398
|
-
i0.ɵɵconditional(ctx_r1.filteredUsers.length === 0 ?
|
|
324
|
+
i0.ɵɵconditional(ctx_r1.filteredUsers.length === 0 ? 9 : -1);
|
|
399
325
|
} }
|
|
400
|
-
function
|
|
401
|
-
const
|
|
402
|
-
i0.ɵɵelementStart(0, "div",
|
|
403
|
-
i0.ɵɵlistener("click", function
|
|
404
|
-
i0.ɵɵelementStart(1, "div",
|
|
405
|
-
i0.ɵɵlistener("click", function
|
|
406
|
-
i0.ɵɵelementStart(2, "div",
|
|
407
|
-
i0.ɵɵelement(4, "i",
|
|
326
|
+
function UserManagementComponent_Conditional_25_Template(rf, ctx) { if (rf & 1) {
|
|
327
|
+
const _r9 = i0.ɵɵgetCurrentView();
|
|
328
|
+
i0.ɵɵelementStart(0, "div", 94);
|
|
329
|
+
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_25_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.showDeleteConfirm = false); });
|
|
330
|
+
i0.ɵɵelementStart(1, "div", 95);
|
|
331
|
+
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_25_Template_div_click_1_listener($event) { i0.ɵɵrestoreView(_r9); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
332
|
+
i0.ɵɵelementStart(2, "div", 96)(3, "h3", 97);
|
|
333
|
+
i0.ɵɵelement(4, "i", 98);
|
|
408
334
|
i0.ɵɵtext(5, " Confirm Delete ");
|
|
409
335
|
i0.ɵɵelementEnd();
|
|
410
|
-
i0.ɵɵelementStart(6, "button",
|
|
411
|
-
i0.ɵɵlistener("click", function
|
|
412
|
-
i0.ɵɵelement(7, "i",
|
|
336
|
+
i0.ɵɵelementStart(6, "button", 99);
|
|
337
|
+
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_25_Template_button_click_6_listener() { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.showDeleteConfirm = false); });
|
|
338
|
+
i0.ɵɵelement(7, "i", 28);
|
|
413
339
|
i0.ɵɵelementEnd()();
|
|
414
|
-
i0.ɵɵelementStart(8, "div",
|
|
340
|
+
i0.ɵɵelementStart(8, "div", 100)(9, "p");
|
|
415
341
|
i0.ɵɵtext(10, "Are you sure you want to delete user ");
|
|
416
342
|
i0.ɵɵelementStart(11, "strong");
|
|
417
343
|
i0.ɵɵtext(12);
|
|
418
344
|
i0.ɵɵelementEnd();
|
|
419
345
|
i0.ɵɵtext(13, "?");
|
|
420
346
|
i0.ɵɵelementEnd();
|
|
421
|
-
i0.ɵɵelementStart(14, "p",
|
|
347
|
+
i0.ɵɵelementStart(14, "p", 101);
|
|
422
348
|
i0.ɵɵtext(15, "This action cannot be undone.");
|
|
423
349
|
i0.ɵɵelementEnd()();
|
|
424
|
-
i0.ɵɵelementStart(16, "div",
|
|
425
|
-
i0.ɵɵlistener("click", function
|
|
426
|
-
i0.ɵɵelement(18, "i",
|
|
350
|
+
i0.ɵɵelementStart(16, "div", 102)(17, "button", 103);
|
|
351
|
+
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_25_Template_button_click_17_listener() { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.deleteUser()); });
|
|
352
|
+
i0.ɵɵelement(18, "i", 38);
|
|
427
353
|
i0.ɵɵtext(19, " Delete User ");
|
|
428
354
|
i0.ɵɵelementEnd();
|
|
429
|
-
i0.ɵɵelementStart(20, "button",
|
|
430
|
-
i0.ɵɵlistener("click", function
|
|
355
|
+
i0.ɵɵelementStart(20, "button", 104);
|
|
356
|
+
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_25_Template_button_click_20_listener() { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.showDeleteConfirm = false); });
|
|
431
357
|
i0.ɵɵtext(21, " Cancel ");
|
|
432
358
|
i0.ɵɵelementEnd()()()();
|
|
433
359
|
} if (rf & 2) {
|
|
@@ -435,35 +361,35 @@ function UserManagementComponent_Conditional_81_Template(rf, ctx) { if (rf & 1)
|
|
|
435
361
|
i0.ɵɵadvance(12);
|
|
436
362
|
i0.ɵɵtextInterpolate(ctx_r1.selectedUser.Name);
|
|
437
363
|
} }
|
|
438
|
-
function
|
|
439
|
-
i0.ɵɵelement(0, "i",
|
|
364
|
+
function UserManagementComponent_Conditional_26_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
365
|
+
i0.ɵɵelement(0, "i", 98);
|
|
440
366
|
} }
|
|
441
|
-
function
|
|
442
|
-
i0.ɵɵelement(0, "i",
|
|
367
|
+
function UserManagementComponent_Conditional_26_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
368
|
+
i0.ɵɵelement(0, "i", 107);
|
|
443
369
|
} }
|
|
444
|
-
function
|
|
445
|
-
i0.ɵɵelement(0, "i",
|
|
370
|
+
function UserManagementComponent_Conditional_26_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
371
|
+
i0.ɵɵelement(0, "i", 108);
|
|
446
372
|
} }
|
|
447
|
-
function
|
|
448
|
-
i0.ɵɵelementStart(0, "p",
|
|
373
|
+
function UserManagementComponent_Conditional_26_Conditional_13_Template(rf, ctx) { if (rf & 1) {
|
|
374
|
+
i0.ɵɵelementStart(0, "p", 101);
|
|
449
375
|
i0.ɵɵtext(1, "This action cannot be undone.");
|
|
450
376
|
i0.ɵɵelementEnd();
|
|
451
377
|
} }
|
|
452
|
-
function
|
|
453
|
-
i0.ɵɵelement(0, "i",
|
|
378
|
+
function UserManagementComponent_Conditional_26_Conditional_16_Template(rf, ctx) { if (rf & 1) {
|
|
379
|
+
i0.ɵɵelement(0, "i", 112);
|
|
454
380
|
i0.ɵɵtext(1, " Processing... ");
|
|
455
381
|
} }
|
|
456
|
-
function
|
|
457
|
-
i0.ɵɵelement(0, "i",
|
|
382
|
+
function UserManagementComponent_Conditional_26_Conditional_17_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
383
|
+
i0.ɵɵelement(0, "i", 38);
|
|
458
384
|
} }
|
|
459
|
-
function
|
|
460
|
-
i0.ɵɵelement(0, "i",
|
|
385
|
+
function UserManagementComponent_Conditional_26_Conditional_17_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
386
|
+
i0.ɵɵelement(0, "i", 31);
|
|
461
387
|
} }
|
|
462
|
-
function
|
|
463
|
-
i0.ɵɵelement(0, "i",
|
|
388
|
+
function UserManagementComponent_Conditional_26_Conditional_17_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
389
|
+
i0.ɵɵelement(0, "i", 34);
|
|
464
390
|
} }
|
|
465
|
-
function
|
|
466
|
-
i0.ɵɵconditionalCreate(0,
|
|
391
|
+
function UserManagementComponent_Conditional_26_Conditional_17_Template(rf, ctx) { if (rf & 1) {
|
|
392
|
+
i0.ɵɵconditionalCreate(0, UserManagementComponent_Conditional_26_Conditional_17_Conditional_0_Template, 1, 0, "i", 38)(1, UserManagementComponent_Conditional_26_Conditional_17_Conditional_1_Template, 1, 0, "i", 31)(2, UserManagementComponent_Conditional_26_Conditional_17_Conditional_2_Template, 1, 0, "i", 34);
|
|
467
393
|
i0.ɵɵtext(3);
|
|
468
394
|
} if (rf & 2) {
|
|
469
395
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
@@ -471,31 +397,31 @@ function UserManagementComponent_Conditional_82_Conditional_17_Template(rf, ctx)
|
|
|
471
397
|
i0.ɵɵadvance(3);
|
|
472
398
|
i0.ɵɵtextInterpolate1(" ", ctx_r1.getBulkActionButtonText(), " ");
|
|
473
399
|
} }
|
|
474
|
-
function
|
|
475
|
-
const
|
|
476
|
-
i0.ɵɵelementStart(0, "div",
|
|
477
|
-
i0.ɵɵlistener("click", function
|
|
478
|
-
i0.ɵɵelementStart(1, "div",
|
|
479
|
-
i0.ɵɵlistener("click", function
|
|
480
|
-
i0.ɵɵelementStart(2, "div",
|
|
481
|
-
i0.ɵɵconditionalCreate(4,
|
|
400
|
+
function UserManagementComponent_Conditional_26_Template(rf, ctx) { if (rf & 1) {
|
|
401
|
+
const _r10 = i0.ɵɵgetCurrentView();
|
|
402
|
+
i0.ɵɵelementStart(0, "div", 105);
|
|
403
|
+
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_26_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.cancelBulkAction()); });
|
|
404
|
+
i0.ɵɵelementStart(1, "div", 95);
|
|
405
|
+
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_26_Template_div_click_1_listener($event) { i0.ɵɵrestoreView(_r10); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
406
|
+
i0.ɵɵelementStart(2, "div", 96)(3, "h3", 106);
|
|
407
|
+
i0.ɵɵconditionalCreate(4, UserManagementComponent_Conditional_26_Conditional_4_Template, 1, 0, "i", 98)(5, UserManagementComponent_Conditional_26_Conditional_5_Template, 1, 0, "i", 107)(6, UserManagementComponent_Conditional_26_Conditional_6_Template, 1, 0, "i", 108);
|
|
482
408
|
i0.ɵɵtext(7);
|
|
483
409
|
i0.ɵɵelementEnd();
|
|
484
|
-
i0.ɵɵelementStart(8, "button",
|
|
485
|
-
i0.ɵɵlistener("click", function
|
|
486
|
-
i0.ɵɵelement(9, "i",
|
|
410
|
+
i0.ɵɵelementStart(8, "button", 99);
|
|
411
|
+
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_26_Template_button_click_8_listener() { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.cancelBulkAction()); });
|
|
412
|
+
i0.ɵɵelement(9, "i", 28);
|
|
487
413
|
i0.ɵɵelementEnd()();
|
|
488
|
-
i0.ɵɵelementStart(10, "div",
|
|
414
|
+
i0.ɵɵelementStart(10, "div", 109)(11, "p");
|
|
489
415
|
i0.ɵɵtext(12);
|
|
490
416
|
i0.ɵɵelementEnd();
|
|
491
|
-
i0.ɵɵconditionalCreate(13,
|
|
417
|
+
i0.ɵɵconditionalCreate(13, UserManagementComponent_Conditional_26_Conditional_13_Template, 2, 0, "p", 101);
|
|
492
418
|
i0.ɵɵelementEnd();
|
|
493
|
-
i0.ɵɵelementStart(14, "div",
|
|
494
|
-
i0.ɵɵlistener("click", function
|
|
495
|
-
i0.ɵɵconditionalCreate(16,
|
|
419
|
+
i0.ɵɵelementStart(14, "div", 102)(15, "button", 110);
|
|
420
|
+
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_26_Template_button_click_15_listener() { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.executeBulkAction()); });
|
|
421
|
+
i0.ɵɵconditionalCreate(16, UserManagementComponent_Conditional_26_Conditional_16_Template, 2, 0)(17, UserManagementComponent_Conditional_26_Conditional_17_Template, 4, 2);
|
|
496
422
|
i0.ɵɵelementEnd();
|
|
497
|
-
i0.ɵɵelementStart(18, "button",
|
|
498
|
-
i0.ɵɵlistener("click", function
|
|
423
|
+
i0.ɵɵelementStart(18, "button", 111);
|
|
424
|
+
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_26_Template_button_click_18_listener() { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.cancelBulkAction()); });
|
|
499
425
|
i0.ɵɵtext(19, " Cancel ");
|
|
500
426
|
i0.ɵɵelementEnd()()()();
|
|
501
427
|
} if (rf & 2) {
|
|
@@ -515,57 +441,57 @@ function UserManagementComponent_Conditional_82_Template(rf, ctx) { if (rf & 1)
|
|
|
515
441
|
i0.ɵɵadvance(2);
|
|
516
442
|
i0.ɵɵproperty("disabled", ctx_r1.isLoading);
|
|
517
443
|
} }
|
|
518
|
-
function
|
|
519
|
-
i0.ɵɵelementStart(0, "option",
|
|
444
|
+
function UserManagementComponent_Conditional_27_For_18_Template(rf, ctx) { if (rf & 1) {
|
|
445
|
+
i0.ɵɵelementStart(0, "option", 120);
|
|
520
446
|
i0.ɵɵtext(1);
|
|
521
447
|
i0.ɵɵelementEnd();
|
|
522
448
|
} if (rf & 2) {
|
|
523
|
-
const
|
|
524
|
-
i0.ɵɵproperty("value",
|
|
449
|
+
const role_r12 = ctx.$implicit;
|
|
450
|
+
i0.ɵɵproperty("value", role_r12.ID);
|
|
525
451
|
i0.ɵɵadvance();
|
|
526
|
-
i0.ɵɵtextInterpolate(
|
|
452
|
+
i0.ɵɵtextInterpolate(role_r12.Name);
|
|
527
453
|
} }
|
|
528
|
-
function
|
|
529
|
-
i0.ɵɵelement(0, "i",
|
|
454
|
+
function UserManagementComponent_Conditional_27_Conditional_21_Template(rf, ctx) { if (rf & 1) {
|
|
455
|
+
i0.ɵɵelement(0, "i", 112);
|
|
530
456
|
i0.ɵɵtext(1, " Assigning... ");
|
|
531
457
|
} }
|
|
532
|
-
function
|
|
533
|
-
i0.ɵɵelement(0, "i",
|
|
458
|
+
function UserManagementComponent_Conditional_27_Conditional_22_Template(rf, ctx) { if (rf & 1) {
|
|
459
|
+
i0.ɵɵelement(0, "i", 36);
|
|
534
460
|
i0.ɵɵtext(1, " Assign Role ");
|
|
535
461
|
} }
|
|
536
|
-
function
|
|
537
|
-
const
|
|
538
|
-
i0.ɵɵelementStart(0, "div",
|
|
539
|
-
i0.ɵɵlistener("click", function
|
|
540
|
-
i0.ɵɵelementStart(1, "div",
|
|
541
|
-
i0.ɵɵlistener("click", function
|
|
542
|
-
i0.ɵɵelementStart(2, "div",
|
|
543
|
-
i0.ɵɵelement(4, "i",
|
|
462
|
+
function UserManagementComponent_Conditional_27_Template(rf, ctx) { if (rf & 1) {
|
|
463
|
+
const _r11 = i0.ɵɵgetCurrentView();
|
|
464
|
+
i0.ɵɵelementStart(0, "div", 113);
|
|
465
|
+
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_27_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r11); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.cancelBulkRoleAssign()); });
|
|
466
|
+
i0.ɵɵelementStart(1, "div", 95);
|
|
467
|
+
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_27_Template_div_click_1_listener($event) { i0.ɵɵrestoreView(_r11); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
468
|
+
i0.ɵɵelementStart(2, "div", 96)(3, "h3", 114);
|
|
469
|
+
i0.ɵɵelement(4, "i", 36);
|
|
544
470
|
i0.ɵɵtext(5);
|
|
545
471
|
i0.ɵɵelementEnd();
|
|
546
|
-
i0.ɵɵelementStart(6, "button",
|
|
547
|
-
i0.ɵɵlistener("click", function
|
|
548
|
-
i0.ɵɵelement(7, "i",
|
|
472
|
+
i0.ɵɵelementStart(6, "button", 99);
|
|
473
|
+
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_27_Template_button_click_6_listener() { i0.ɵɵrestoreView(_r11); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.cancelBulkRoleAssign()); });
|
|
474
|
+
i0.ɵɵelement(7, "i", 28);
|
|
549
475
|
i0.ɵɵelementEnd()();
|
|
550
|
-
i0.ɵɵelementStart(8, "div",
|
|
476
|
+
i0.ɵɵelementStart(8, "div", 115)(9, "p");
|
|
551
477
|
i0.ɵɵtext(10, "Select a role to assign to the selected users:");
|
|
552
478
|
i0.ɵɵelementEnd();
|
|
553
|
-
i0.ɵɵelementStart(11, "div",
|
|
479
|
+
i0.ɵɵelementStart(11, "div", 116)(12, "label", 117);
|
|
554
480
|
i0.ɵɵtext(13, "Role");
|
|
555
481
|
i0.ɵɵelementEnd();
|
|
556
|
-
i0.ɵɵelementStart(14, "select",
|
|
557
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
558
|
-
i0.ɵɵelementStart(15, "option",
|
|
482
|
+
i0.ɵɵelementStart(14, "select", 118);
|
|
483
|
+
i0.ɵɵtwoWayListener("ngModelChange", function UserManagementComponent_Conditional_27_Template_select_ngModelChange_14_listener($event) { i0.ɵɵrestoreView(_r11); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.bulkRoleId, $event) || (ctx_r1.bulkRoleId = $event); return i0.ɵɵresetView($event); });
|
|
484
|
+
i0.ɵɵelementStart(15, "option", 119);
|
|
559
485
|
i0.ɵɵtext(16, "Select a role...");
|
|
560
486
|
i0.ɵɵelementEnd();
|
|
561
|
-
i0.ɵɵrepeaterCreate(17,
|
|
487
|
+
i0.ɵɵrepeaterCreate(17, UserManagementComponent_Conditional_27_For_18_Template, 2, 2, "option", 120, _forTrack0);
|
|
562
488
|
i0.ɵɵelementEnd()()();
|
|
563
|
-
i0.ɵɵelementStart(19, "div",
|
|
564
|
-
i0.ɵɵlistener("click", function
|
|
565
|
-
i0.ɵɵconditionalCreate(21,
|
|
489
|
+
i0.ɵɵelementStart(19, "div", 102)(20, "button", 121);
|
|
490
|
+
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_27_Template_button_click_20_listener() { i0.ɵɵrestoreView(_r11); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.executeBulkRoleAssign()); });
|
|
491
|
+
i0.ɵɵconditionalCreate(21, UserManagementComponent_Conditional_27_Conditional_21_Template, 2, 0)(22, UserManagementComponent_Conditional_27_Conditional_22_Template, 2, 0);
|
|
566
492
|
i0.ɵɵelementEnd();
|
|
567
|
-
i0.ɵɵelementStart(23, "button",
|
|
568
|
-
i0.ɵɵlistener("click", function
|
|
493
|
+
i0.ɵɵelementStart(23, "button", 111);
|
|
494
|
+
i0.ɵɵlistener("click", function UserManagementComponent_Conditional_27_Template_button_click_23_listener() { i0.ɵɵrestoreView(_r11); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.cancelBulkRoleAssign()); });
|
|
569
495
|
i0.ɵɵtext(24, " Cancel ");
|
|
570
496
|
i0.ɵɵelementEnd()()()();
|
|
571
497
|
} if (rf & 2) {
|
|
@@ -620,7 +546,6 @@ let UserManagementComponent = class UserManagementComponent extends BaseDashboar
|
|
|
620
546
|
showCreateDialog = false;
|
|
621
547
|
showEditDialog = false;
|
|
622
548
|
showDeleteConfirm = false;
|
|
623
|
-
showMobileFilters = false;
|
|
624
549
|
// Mobile expansion state
|
|
625
550
|
expandedUserIds = new Set();
|
|
626
551
|
// User-Role mapping
|
|
@@ -756,21 +681,21 @@ let UserManagementComponent = class UserManagementComponent extends BaseDashboar
|
|
|
756
681
|
};
|
|
757
682
|
}
|
|
758
683
|
// Public methods for template
|
|
759
|
-
onSearchChange(event) {
|
|
760
|
-
const value = event.target.value;
|
|
761
|
-
this.updateFilter({ search: value });
|
|
762
|
-
}
|
|
763
684
|
onStatusFilterChange(status) {
|
|
764
685
|
this.updateFilter({ status });
|
|
765
686
|
}
|
|
766
|
-
onRoleFilterChange(role) {
|
|
767
|
-
this.updateFilter({ role });
|
|
768
|
-
}
|
|
769
687
|
updateFilter(partial) {
|
|
770
688
|
this.filters$.next({
|
|
771
689
|
...this.filters$.value,
|
|
772
690
|
...partial
|
|
773
691
|
});
|
|
692
|
+
// Discrete changes (chips, popover dropdowns) apply immediately. Text search
|
|
693
|
+
// still goes through the 300ms debounce in setupFilterSubscription so we
|
|
694
|
+
// don't re-filter on every keystroke.
|
|
695
|
+
if (!('search' in partial)) {
|
|
696
|
+
this.applyFilters();
|
|
697
|
+
this.cdr.markForCheck();
|
|
698
|
+
}
|
|
774
699
|
}
|
|
775
700
|
selectUser(user) {
|
|
776
701
|
this.selectedUser = user;
|
|
@@ -956,7 +881,50 @@ let UserManagementComponent = class UserManagementComponent extends BaseDashboar
|
|
|
956
881
|
status: 'all',
|
|
957
882
|
role: ''
|
|
958
883
|
});
|
|
959
|
-
this.
|
|
884
|
+
this.applyFilters();
|
|
885
|
+
this.cdr.markForCheck();
|
|
886
|
+
}
|
|
887
|
+
// -- Filter panel binding (mj-filter-panel inside the popover) -------------
|
|
888
|
+
//
|
|
889
|
+
// Only Role lives inside the popover — Status is exposed as visible chips
|
|
890
|
+
// in the filter card alongside search (the standardized "quick toggle"
|
|
891
|
+
// pattern used by Scheduling's exterior chrome). The popover badge counts
|
|
892
|
+
// only popover-resident filters (Role), so Status changes don't ghost
|
|
893
|
+
// the badge.
|
|
894
|
+
/**
|
|
895
|
+
* FilterFieldConfig[] describing the popover's Role field. Driven off
|
|
896
|
+
* `roles[]` so the dropdown stays in sync as roles load.
|
|
897
|
+
*/
|
|
898
|
+
get filterFields() {
|
|
899
|
+
return [
|
|
900
|
+
{
|
|
901
|
+
key: 'role',
|
|
902
|
+
type: 'dropdown',
|
|
903
|
+
label: 'Role',
|
|
904
|
+
icon: 'fa-solid fa-user-shield',
|
|
905
|
+
placeholder: 'All Roles',
|
|
906
|
+
filterable: this.roles.length > 10,
|
|
907
|
+
options: [
|
|
908
|
+
{ text: 'All Roles', value: '' },
|
|
909
|
+
...this.roles.map(r => ({ text: r.Name ?? '', value: r.ID }))
|
|
910
|
+
]
|
|
911
|
+
}
|
|
912
|
+
];
|
|
913
|
+
}
|
|
914
|
+
/** Current popover field values keyed by FilterFieldConfig.key. */
|
|
915
|
+
get filterValues() {
|
|
916
|
+
return { role: this.filters$.value.role };
|
|
917
|
+
}
|
|
918
|
+
/** Number of active filters INSIDE the popover only — drives the popover badge. */
|
|
919
|
+
get popoverActiveFilterCount() {
|
|
920
|
+
return this.filters$.value.role !== '' ? 1 : 0;
|
|
921
|
+
}
|
|
922
|
+
/** Apply a value change from <mj-filter-panel>. */
|
|
923
|
+
onFilterPanelChange(values) {
|
|
924
|
+
const role = values['role'] ?? '';
|
|
925
|
+
this.filters$.next({ ...this.filters$.value, role });
|
|
926
|
+
this.applyFilters();
|
|
927
|
+
this.cdr.markForCheck();
|
|
960
928
|
}
|
|
961
929
|
toggleSelectAll() {
|
|
962
930
|
if (this.isAllSelected) {
|
|
@@ -1174,161 +1142,86 @@ let UserManagementComponent = class UserManagementComponent extends BaseDashboar
|
|
|
1174
1142
|
return this.roles.filter(role => roleIds.some(id => UUIDsEqual(id, role.ID)));
|
|
1175
1143
|
}
|
|
1176
1144
|
static ɵfac = function UserManagementComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || UserManagementComponent)(i0.ɵɵdirectiveInject(i0.ChangeDetectorRef), i0.ɵɵdirectiveInject(i0.NgZone)); };
|
|
1177
|
-
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: UserManagementComponent, selectors: [["mj-user-management"]], standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls:
|
|
1178
|
-
i0.ɵɵelementStart(0, "
|
|
1179
|
-
i0.ɵɵ
|
|
1180
|
-
i0.ɵɵelement(4, "i", 4);
|
|
1181
|
-
i0.ɵɵelementStart(5, "span", 5);
|
|
1182
|
-
i0.ɵɵtext(6, "Refresh");
|
|
1183
|
-
i0.ɵɵelementEnd()();
|
|
1184
|
-
i0.ɵɵelementStart(7, "button", 6);
|
|
1185
|
-
i0.ɵɵlistener("click", function UserManagementComponent_Template_button_click_7_listener() { return ctx.exportUsers(); });
|
|
1186
|
-
i0.ɵɵelement(8, "i", 7);
|
|
1187
|
-
i0.ɵɵelementStart(9, "span", 5);
|
|
1188
|
-
i0.ɵɵtext(10, "Export");
|
|
1189
|
-
i0.ɵɵelementEnd()();
|
|
1190
|
-
i0.ɵɵelementStart(11, "button", 8);
|
|
1191
|
-
i0.ɵɵlistener("click", function UserManagementComponent_Template_button_click_11_listener() { return ctx.createNewUser(); });
|
|
1192
|
-
i0.ɵɵelement(12, "i", 9);
|
|
1193
|
-
i0.ɵɵelementStart(13, "span", 5);
|
|
1194
|
-
i0.ɵɵtext(14, "Add User");
|
|
1195
|
-
i0.ɵɵelementEnd()()();
|
|
1196
|
-
i0.ɵɵconditionalCreate(15, UserManagementComponent_Conditional_15_Template, 25, 2, "div", 10);
|
|
1197
|
-
i0.ɵɵelementStart(16, "div", 11)(17, "div", 12)(18, "div", 13);
|
|
1198
|
-
i0.ɵɵelement(19, "i", 14);
|
|
1145
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: UserManagementComponent, selectors: [["mj-user-management"]], standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 28, vars: 20, consts: [["AriaLabel", "Filter users", "Title", "Users", "Subtitle", "Manage user accounts, roles, and access"], ["meta", ""], ["Label", "users", 3, "Count", "Total"], ["toolbar", ""], ["Placeholder", "Search users by name or email...", 3, "ValueChange", "Value"], ["role", "group", "aria-label", "Filter by status", 1, "status-chips"], ["Label", "All", 3, "Clicked", "Active"], ["Label", "Active", 3, "Clicked", "Active"], ["Label", "Inactive", 3, "Clicked", "Active"], ["actions", ""], [3, "ClearAllRequested", "ActiveCount", "ShowClearAll"], [3, "ValuesChange", "Reset", "Fields", "Values"], [3, "Clicked", "Loading"], ["mjButton", "", "variant", "secondary", "size", "sm", "aria-label", "Export users to file", 3, "click"], [1, "fa-solid", "fa-download"], ["mjButton", "", "variant", "primary", "size", "sm", "aria-label", "Add new user", 3, "click"], [1, "fa-solid", "fa-plus"], ["role", "toolbar", "aria-label", "Bulk actions", 1, "bulk-action-toolbar"], ["role", "status", "aria-live", "polite", "aria-busy", "true", 1, "loading-container"], ["role", "alert", "aria-live", "assertive", 1, "error-container"], ["role", "list", "aria-label", "Users list", 1, "users-list"], [3, "result", "data", "visible"], ["role", "dialog", "aria-modal", "true", "aria-labelledby", "delete-dialog-title", "aria-describedby", "delete-dialog-desc", 1, "modal-backdrop"], ["role", "dialog", "aria-modal", "true", "aria-labelledby", "bulk-action-dialog-title", "aria-describedby", "bulk-action-dialog-desc", 1, "modal-backdrop"], ["role", "dialog", "aria-modal", "true", "aria-labelledby", "bulk-role-dialog-title", "aria-describedby", "bulk-role-dialog-desc", 1, "modal-backdrop"], [1, "bulk-selection-info"], ["aria-hidden", "true", 1, "fa-solid", "fa-check-square"], ["mjButton", "", "variant", "flat", "size", "sm", "aria-label", "Clear selection", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-times"], [1, "bulk-action-buttons"], ["mjButton", "", "variant", "secondary", "size", "sm", "aria-label", "Enable selected users", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-toggle-on"], [1, "btn-text"], ["mjButton", "", "variant", "secondary", "size", "sm", "aria-label", "Disable selected users", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-toggle-off"], ["mjButton", "", "variant", "secondary", "size", "sm", "aria-label", "Assign role to selected users", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-user-tag"], ["mjButton", "", "variant", "danger", "size", "sm", "aria-label", "Delete selected users", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-trash"], ["text", "Loading users...", "size", "medium"], [1, "error-content"], ["aria-hidden", "true", 1, "fa-solid", "fa-exclamation-triangle", "error-icon"], [1, "error-message"], ["aria-label", "Retry loading users", 1, "retry-button", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-refresh"], [1, "list-header"], [1, "select-all-label"], ["type", "checkbox", "aria-label", "Select all users", 1, "checkbox", 3, "change", "checked", "indeterminate"], [1, "select-all-text"], [1, "selection-count"], ["role", "listitem", 1, "user-card", 3, "expanded", "selected"], ["role", "status", 1, "empty-state"], ["role", "listitem", 1, "user-card"], ["role", "button", "tabindex", "0", 1, "user-header", 3, "click", "keydown.enter"], [1, "user-selection", 3, "click"], ["type", "checkbox", 1, "checkbox", 3, "change", "checked"], [1, "user-info"], ["aria-hidden", "true", 1, "user-avatar"], [1, "user-details"], [1, "user-name"], [1, "user-email"], [1, "user-meta"], [1, "status-badge"], ["aria-hidden", "true"], [1, "user-actions", "desktop-only", 3, "click"], ["mjButton", "", "variant", "flat", "size", "sm", "title", "Edit", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-edit"], ["mjButton", "", "variant", "flat", "size", "sm", 3, "click", "title"], ["mjButton", "", "variant", "danger", "size", "sm", "title", "Delete", 3, "click"], ["aria-label", "Toggle user details", 1, "expand-btn"], ["aria-hidden", "true", 1, "fa-solid", "fa-chevron-down"], [1, "user-content"], [1, "mobile-actions-bar", 3, "click"], [1, "mobile-action-buttons"], ["mjButton", "", "variant", "flat", "size", "sm", 3, "click"], [1, "btn-label"], ["mjButton", "", "variant", "danger", "size", "sm", 3, "click"], [1, "user-stats"], [1, "stat-item"], [1, "stat-label"], [1, "stat-value"], ["aria-hidden", "true", 1, "fa-solid", "fa-id-card"], ["aria-hidden", "true", 1, "fa-solid", "fa-calendar"], ["aria-hidden", "true", 1, "fa-solid", "fa-clock"], [1, "roles-section"], [1, "section-title"], ["aria-hidden", "true", 1, "fa-solid", "fa-user-shield"], [1, "roles-grid"], [1, "no-roles"], [1, "role-item"], ["aria-hidden", "true", 1, "fa-solid", "fa-shield"], ["aria-hidden", "true", 1, "fa-solid", "fa-users-slash", "empty-icon"], [1, "empty-text"], [1, "empty-subtext"], ["role", "dialog", "aria-modal", "true", "aria-labelledby", "delete-dialog-title", "aria-describedby", "delete-dialog-desc", 1, "modal-backdrop", 3, "click"], [1, "modal-dialog", 3, "click"], [1, "modal-header"], ["id", "delete-dialog-title", 1, "modal-title"], ["aria-hidden", "true", 1, "fa-solid", "fa-exclamation-triangle", "text-danger"], ["aria-label", "Close dialog", 1, "modal-close", 3, "click"], ["id", "delete-dialog-desc", 1, "modal-body"], [1, "text-muted"], [1, "modal-footer"], ["mjButton", "", "variant", "danger", 3, "click"], ["mjButton", "", 3, "click"], ["role", "dialog", "aria-modal", "true", "aria-labelledby", "bulk-action-dialog-title", "aria-describedby", "bulk-action-dialog-desc", 1, "modal-backdrop", 3, "click"], ["id", "bulk-action-dialog-title", 1, "modal-title"], ["aria-hidden", "true", 1, "fa-solid", "fa-toggle-on", "text-success"], ["aria-hidden", "true", 1, "fa-solid", "fa-toggle-off", "text-warning"], ["id", "bulk-action-dialog-desc", 1, "modal-body"], ["mjButton", "", 3, "click", "variant", "disabled"], ["mjButton", "", 3, "click", "disabled"], ["aria-hidden", "true", 1, "fa-solid", "fa-spinner", "fa-spin"], ["role", "dialog", "aria-modal", "true", "aria-labelledby", "bulk-role-dialog-title", "aria-describedby", "bulk-role-dialog-desc", 1, "modal-backdrop", 3, "click"], ["id", "bulk-role-dialog-title", 1, "modal-title"], ["id", "bulk-role-dialog-desc", 1, "modal-body"], [1, "form-field"], ["for", "bulk-role-select", 1, "field-label"], ["id", "bulk-role-select", "aria-label", "Select role to assign", 1, "field-select", 3, "ngModelChange", "ngModel"], ["value", ""], [3, "value"], ["mjButton", "", "variant", "primary", 3, "click", "disabled"]], template: function UserManagementComponent_Template(rf, ctx) { if (rf & 1) {
|
|
1146
|
+
i0.ɵɵelementStart(0, "mj-page-header-interior", 0)(1, "div", 1);
|
|
1147
|
+
i0.ɵɵelement(2, "mj-stat-badge", 2);
|
|
1199
1148
|
i0.ɵɵelementEnd();
|
|
1200
|
-
i0.ɵɵelementStart(
|
|
1201
|
-
i0.ɵɵ
|
|
1149
|
+
i0.ɵɵelementStart(3, "div", 3)(4, "mj-page-search", 4);
|
|
1150
|
+
i0.ɵɵlistener("ValueChange", function UserManagementComponent_Template_mj_page_search_ValueChange_4_listener($event) { return ctx.updateFilter({ search: $event }); });
|
|
1202
1151
|
i0.ɵɵelementEnd();
|
|
1203
|
-
i0.ɵɵelementStart(
|
|
1204
|
-
i0.ɵɵ
|
|
1205
|
-
i0.ɵɵelementEnd()()();
|
|
1206
|
-
i0.ɵɵelementStart(25, "div", 12)(26, "div", 18);
|
|
1207
|
-
i0.ɵɵelement(27, "i", 19);
|
|
1152
|
+
i0.ɵɵelementStart(5, "div", 5)(6, "mj-filter-chip", 6);
|
|
1153
|
+
i0.ɵɵlistener("Clicked", function UserManagementComponent_Template_mj_filter_chip_Clicked_6_listener() { return ctx.onStatusFilterChange("all"); });
|
|
1208
1154
|
i0.ɵɵelementEnd();
|
|
1209
|
-
i0.ɵɵelementStart(
|
|
1210
|
-
i0.ɵɵ
|
|
1155
|
+
i0.ɵɵelementStart(7, "mj-filter-chip", 7);
|
|
1156
|
+
i0.ɵɵlistener("Clicked", function UserManagementComponent_Template_mj_filter_chip_Clicked_7_listener() { return ctx.onStatusFilterChange("active"); });
|
|
1211
1157
|
i0.ɵɵelementEnd();
|
|
1212
|
-
i0.ɵɵelementStart(
|
|
1213
|
-
i0.ɵɵ
|
|
1158
|
+
i0.ɵɵelementStart(8, "mj-filter-chip", 8);
|
|
1159
|
+
i0.ɵɵlistener("Clicked", function UserManagementComponent_Template_mj_filter_chip_Clicked_8_listener() { return ctx.onStatusFilterChange("inactive"); });
|
|
1214
1160
|
i0.ɵɵelementEnd()()();
|
|
1215
|
-
i0.ɵɵelementStart(
|
|
1216
|
-
i0.ɵɵ
|
|
1217
|
-
i0.ɵɵ
|
|
1218
|
-
i0.ɵɵ
|
|
1219
|
-
i0.ɵɵtext(38);
|
|
1220
|
-
i0.ɵɵelementEnd();
|
|
1221
|
-
i0.ɵɵelementStart(39, "div", 17);
|
|
1222
|
-
i0.ɵɵtext(40, "Inactive Users");
|
|
1223
|
-
i0.ɵɵelementEnd()()();
|
|
1224
|
-
i0.ɵɵelementStart(41, "div", 12)(42, "div", 24);
|
|
1225
|
-
i0.ɵɵelement(43, "i", 25);
|
|
1226
|
-
i0.ɵɵelementEnd();
|
|
1227
|
-
i0.ɵɵelementStart(44, "div", 15)(45, "div", 26);
|
|
1228
|
-
i0.ɵɵtext(46);
|
|
1229
|
-
i0.ɵɵelementEnd();
|
|
1230
|
-
i0.ɵɵelementStart(47, "div", 17);
|
|
1231
|
-
i0.ɵɵtext(48, "Owners");
|
|
1232
|
-
i0.ɵɵelementEnd()()()();
|
|
1233
|
-
i0.ɵɵelementStart(49, "div", 27)(50, "div", 28)(51, "div", 29);
|
|
1234
|
-
i0.ɵɵelement(52, "i", 30);
|
|
1235
|
-
i0.ɵɵelementStart(53, "input", 31);
|
|
1236
|
-
i0.ɵɵlistener("input", function UserManagementComponent_Template_input_input_53_listener($event) { return ctx.onSearchChange($event); });
|
|
1161
|
+
i0.ɵɵelementStart(9, "div", 9)(10, "mj-filter-popover", 10);
|
|
1162
|
+
i0.ɵɵlistener("ClearAllRequested", function UserManagementComponent_Template_mj_filter_popover_ClearAllRequested_10_listener() { return ctx.onFilterPanelChange({ role: "" }); });
|
|
1163
|
+
i0.ɵɵelementStart(11, "mj-filter-panel", 11);
|
|
1164
|
+
i0.ɵɵlistener("ValuesChange", function UserManagementComponent_Template_mj_filter_panel_ValuesChange_11_listener($event) { return ctx.onFilterPanelChange($event); })("Reset", function UserManagementComponent_Template_mj_filter_panel_Reset_11_listener() { return ctx.onFilterPanelChange({ role: "" }); });
|
|
1237
1165
|
i0.ɵɵelementEnd()();
|
|
1238
|
-
i0.ɵɵelementStart(
|
|
1239
|
-
i0.ɵɵlistener("
|
|
1240
|
-
i0.ɵɵelement(55, "i", 33);
|
|
1241
|
-
i0.ɵɵconditionalCreate(56, UserManagementComponent_Conditional_56_Template, 2, 1, "span", 34);
|
|
1242
|
-
i0.ɵɵelementEnd();
|
|
1243
|
-
i0.ɵɵelementStart(57, "div", 35)(58, "label", 36);
|
|
1244
|
-
i0.ɵɵtext(59, "Status");
|
|
1166
|
+
i0.ɵɵelementStart(12, "mj-refresh-button", 12);
|
|
1167
|
+
i0.ɵɵlistener("Clicked", function UserManagementComponent_Template_mj_refresh_button_Clicked_12_listener() { return ctx.refreshData(); });
|
|
1245
1168
|
i0.ɵɵelementEnd();
|
|
1246
|
-
i0.ɵɵelementStart(
|
|
1247
|
-
i0.ɵɵlistener("click", function
|
|
1248
|
-
i0.ɵɵ
|
|
1169
|
+
i0.ɵɵelementStart(13, "button", 13);
|
|
1170
|
+
i0.ɵɵlistener("click", function UserManagementComponent_Template_button_click_13_listener() { return ctx.exportUsers(); });
|
|
1171
|
+
i0.ɵɵelement(14, "i", 14);
|
|
1172
|
+
i0.ɵɵtext(15, " Export ");
|
|
1249
1173
|
i0.ɵɵelementEnd();
|
|
1250
|
-
i0.ɵɵelementStart(
|
|
1251
|
-
i0.ɵɵlistener("click", function
|
|
1252
|
-
i0.ɵɵ
|
|
1253
|
-
i0.ɵɵ
|
|
1254
|
-
i0.ɵɵelementStart(65, "button", 38);
|
|
1255
|
-
i0.ɵɵlistener("click", function UserManagementComponent_Template_button_click_65_listener() { return ctx.onStatusFilterChange("inactive"); });
|
|
1256
|
-
i0.ɵɵtext(66, " Inactive ");
|
|
1174
|
+
i0.ɵɵelementStart(16, "button", 15);
|
|
1175
|
+
i0.ɵɵlistener("click", function UserManagementComponent_Template_button_click_16_listener() { return ctx.createNewUser(); });
|
|
1176
|
+
i0.ɵɵelement(17, "i", 16);
|
|
1177
|
+
i0.ɵɵtext(18, " Add User ");
|
|
1257
1178
|
i0.ɵɵelementEnd()()();
|
|
1258
|
-
i0.ɵɵ
|
|
1259
|
-
i0.ɵɵ
|
|
1260
|
-
i0.ɵɵ
|
|
1261
|
-
i0.ɵɵ
|
|
1262
|
-
i0.ɵɵ
|
|
1263
|
-
i0.ɵɵelementStart(71, "option", 41);
|
|
1264
|
-
i0.ɵɵtext(72, "All Roles");
|
|
1265
|
-
i0.ɵɵelementEnd();
|
|
1266
|
-
i0.ɵɵrepeaterCreate(73, UserManagementComponent_For_74_Template, 2, 2, "option", 42, _forTrack0);
|
|
1267
|
-
i0.ɵɵelementEnd()()();
|
|
1268
|
-
i0.ɵɵconditionalCreate(75, UserManagementComponent_Conditional_75_Template, 21, 2, "div", 43);
|
|
1269
|
-
i0.ɵɵelementEnd()();
|
|
1270
|
-
i0.ɵɵelementStart(76, "div", 44);
|
|
1271
|
-
i0.ɵɵconditionalCreate(77, UserManagementComponent_Conditional_77_Template, 2, 0, "div", 45);
|
|
1272
|
-
i0.ɵɵconditionalCreate(78, UserManagementComponent_Conditional_78_Template, 8, 1, "div", 46);
|
|
1273
|
-
i0.ɵɵconditionalCreate(79, UserManagementComponent_Conditional_79_Template, 11, 5, "div", 47);
|
|
1179
|
+
i0.ɵɵconditionalCreate(19, UserManagementComponent_Conditional_19_Template, 25, 2, "div", 17);
|
|
1180
|
+
i0.ɵɵelementStart(20, "mj-page-body-interior");
|
|
1181
|
+
i0.ɵɵconditionalCreate(21, UserManagementComponent_Conditional_21_Template, 2, 0, "div", 18);
|
|
1182
|
+
i0.ɵɵconditionalCreate(22, UserManagementComponent_Conditional_22_Template, 8, 1, "div", 19);
|
|
1183
|
+
i0.ɵɵconditionalCreate(23, UserManagementComponent_Conditional_23_Template, 10, 5, "div", 20);
|
|
1274
1184
|
i0.ɵɵelementEnd();
|
|
1275
|
-
i0.ɵɵelementStart(
|
|
1276
|
-
i0.ɵɵlistener("result", function
|
|
1277
|
-
i0.ɵɵelementEnd();
|
|
1278
|
-
i0.ɵɵconditionalCreate(81, UserManagementComponent_Conditional_81_Template, 22, 1, "div", 49);
|
|
1279
|
-
i0.ɵɵconditionalCreate(82, UserManagementComponent_Conditional_82_Template, 20, 8, "div", 50);
|
|
1280
|
-
i0.ɵɵconditionalCreate(83, UserManagementComponent_Conditional_83_Template, 25, 6, "div", 51);
|
|
1185
|
+
i0.ɵɵelementStart(24, "mj-user-dialog", 21);
|
|
1186
|
+
i0.ɵɵlistener("result", function UserManagementComponent_Template_mj_user_dialog_result_24_listener($event) { return ctx.onUserDialogResult($event); });
|
|
1281
1187
|
i0.ɵɵelementEnd();
|
|
1188
|
+
i0.ɵɵconditionalCreate(25, UserManagementComponent_Conditional_25_Template, 22, 1, "div", 22);
|
|
1189
|
+
i0.ɵɵconditionalCreate(26, UserManagementComponent_Conditional_26_Template, 20, 8, "div", 23);
|
|
1190
|
+
i0.ɵɵconditionalCreate(27, UserManagementComponent_Conditional_27_Template, 25, 6, "div", 24);
|
|
1282
1191
|
} if (rf & 2) {
|
|
1283
|
-
i0.ɵɵadvance(3);
|
|
1284
|
-
i0.ɵɵproperty("disabled", ctx.isLoading);
|
|
1285
|
-
i0.ɵɵadvance();
|
|
1286
|
-
i0.ɵɵclassProp("fa-spin", ctx.isLoading);
|
|
1287
|
-
i0.ɵɵadvance(11);
|
|
1288
|
-
i0.ɵɵconditional(ctx.hasSelection ? 15 : -1);
|
|
1289
|
-
i0.ɵɵadvance(7);
|
|
1290
|
-
i0.ɵɵtextInterpolate(ctx.stats.totalUsers);
|
|
1291
|
-
i0.ɵɵadvance(8);
|
|
1292
|
-
i0.ɵɵtextInterpolate(ctx.stats.activeUsers);
|
|
1293
|
-
i0.ɵɵadvance(8);
|
|
1294
|
-
i0.ɵɵtextInterpolate(ctx.stats.inactiveUsers);
|
|
1295
|
-
i0.ɵɵadvance(8);
|
|
1296
|
-
i0.ɵɵtextInterpolate(ctx.stats.adminUsers);
|
|
1297
|
-
i0.ɵɵadvance(7);
|
|
1298
|
-
i0.ɵɵproperty("value", ctx.filters$.value.search);
|
|
1299
|
-
i0.ɵɵadvance();
|
|
1300
|
-
i0.ɵɵclassProp("active", ctx.showMobileFilters);
|
|
1301
|
-
i0.ɵɵattribute("aria-expanded", ctx.showMobileFilters);
|
|
1302
1192
|
i0.ɵɵadvance(2);
|
|
1303
|
-
i0.ɵɵ
|
|
1304
|
-
i0.ɵɵadvance(5);
|
|
1305
|
-
i0.ɵɵproperty("variant", ctx.filters$.value.status === "all" ? "primary" : "flat");
|
|
1306
|
-
i0.ɵɵattribute("aria-pressed", ctx.filters$.value.status === "all");
|
|
1193
|
+
i0.ɵɵproperty("Count", ctx.filteredUsers.length)("Total", ctx.users.length);
|
|
1307
1194
|
i0.ɵɵadvance(2);
|
|
1308
|
-
i0.ɵɵproperty("
|
|
1309
|
-
i0.ɵɵattribute("aria-pressed", ctx.filters$.value.status === "active");
|
|
1195
|
+
i0.ɵɵproperty("Value", ctx.filters$.value.search);
|
|
1310
1196
|
i0.ɵɵadvance(2);
|
|
1311
|
-
i0.ɵɵproperty("
|
|
1312
|
-
i0.ɵɵ
|
|
1313
|
-
i0.ɵɵ
|
|
1314
|
-
i0.ɵɵ
|
|
1197
|
+
i0.ɵɵproperty("Active", ctx.filters$.value.status === "all");
|
|
1198
|
+
i0.ɵɵadvance();
|
|
1199
|
+
i0.ɵɵproperty("Active", ctx.filters$.value.status === "active");
|
|
1200
|
+
i0.ɵɵadvance();
|
|
1201
|
+
i0.ɵɵproperty("Active", ctx.filters$.value.status === "inactive");
|
|
1315
1202
|
i0.ɵɵadvance(2);
|
|
1316
|
-
i0.ɵɵ
|
|
1203
|
+
i0.ɵɵproperty("ActiveCount", ctx.popoverActiveFilterCount)("ShowClearAll", ctx.popoverActiveFilterCount > 0);
|
|
1204
|
+
i0.ɵɵadvance();
|
|
1205
|
+
i0.ɵɵproperty("Fields", ctx.filterFields)("Values", ctx.filterValues);
|
|
1206
|
+
i0.ɵɵadvance();
|
|
1207
|
+
i0.ɵɵproperty("Loading", ctx.isLoading);
|
|
1208
|
+
i0.ɵɵadvance(7);
|
|
1209
|
+
i0.ɵɵconditional(ctx.hasSelection ? 19 : -1);
|
|
1317
1210
|
i0.ɵɵadvance(2);
|
|
1318
|
-
i0.ɵɵconditional(ctx.isLoading ?
|
|
1211
|
+
i0.ɵɵconditional(ctx.isLoading ? 21 : -1);
|
|
1319
1212
|
i0.ɵɵadvance();
|
|
1320
|
-
i0.ɵɵconditional(ctx.error && !ctx.isLoading ?
|
|
1213
|
+
i0.ɵɵconditional(ctx.error && !ctx.isLoading ? 22 : -1);
|
|
1321
1214
|
i0.ɵɵadvance();
|
|
1322
|
-
i0.ɵɵconditional(!ctx.isLoading && !ctx.error ?
|
|
1215
|
+
i0.ɵɵconditional(!ctx.isLoading && !ctx.error ? 23 : -1);
|
|
1323
1216
|
i0.ɵɵadvance();
|
|
1324
1217
|
i0.ɵɵproperty("data", ctx.userDialogData)("visible", ctx.showUserDialog);
|
|
1325
1218
|
i0.ɵɵadvance();
|
|
1326
|
-
i0.ɵɵconditional(ctx.showDeleteConfirm && ctx.selectedUser ?
|
|
1219
|
+
i0.ɵɵconditional(ctx.showDeleteConfirm && ctx.selectedUser ? 25 : -1);
|
|
1327
1220
|
i0.ɵɵadvance();
|
|
1328
|
-
i0.ɵɵconditional(ctx.showBulkActionConfirm ?
|
|
1221
|
+
i0.ɵɵconditional(ctx.showBulkActionConfirm ? 26 : -1);
|
|
1329
1222
|
i0.ɵɵadvance();
|
|
1330
|
-
i0.ɵɵconditional(ctx.showBulkRoleAssign ?
|
|
1331
|
-
} }, dependencies: [i1.NgSelectOption, i1.ɵNgSelectMultipleOption, i1.SelectControlValueAccessor, i1.NgControlStatus, i1.NgModel, i2.LoadingComponent, i3.MJButtonDirective, i4.UserDialogComponent, i5.DatePipe], styles: ["\n\n\n\n\n\n\n\n\n\n\n[_nghost-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n width: 100%;\n overflow: hidden;\n}\n\n\n\n\n\n.sticky-header[_ngcontent-%COMP%] {\n flex-shrink: 0;\n background: var(--mj-bg-page);\n border-bottom: 1px solid var(--mj-border-default);\n box-shadow: var(--mj-shadow-sm);\n z-index: 10;\n}\n\n\n\n\n\n.scrollable-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n -webkit-overflow-scrolling: touch;\n padding: 1rem;\n background: var(--mj-bg-surface-sunken);\n}\n\n@media (min-width: 768px) {\n .scrollable-content[_ngcontent-%COMP%] {\n padding: 1.5rem 2rem;\n }\n}\n\n@media (min-width: 1024px) {\n .scrollable-content[_ngcontent-%COMP%] {\n padding: 2rem;\n }\n}\n\n@media (min-width: 1440px) {\n .scrollable-content[_ngcontent-%COMP%] {\n padding: 2rem 2.5rem;\n }\n}\n\n\n\n\n\n.action-buttons[_ngcontent-%COMP%] {\n flex-shrink: 0;\n display: flex;\n gap: 0.75rem;\n justify-content: flex-end;\n padding: 0.75rem 1rem;\n background: var(--mj-bg-page);\n}\n\n@media (min-width: 768px) {\n .action-buttons[_ngcontent-%COMP%] {\n padding: 1rem 1.5rem;\n }\n}\n\n@media (max-width: 639px) {\n .action-buttons[_ngcontent-%COMP%] {\n justify-content: center;\n flex-wrap: wrap;\n }\n\n .mj-btn-icon-mobile[_ngcontent-%COMP%] .btn-text[_ngcontent-%COMP%] {\n display: none;\n }\n\n .mj-btn-icon-mobile[_ngcontent-%COMP%] {\n padding: 0.5rem 0.75rem;\n min-height: 40px;\n gap: 0;\n border-radius: var(--mj-radius-full);\n }\n\n .mj-btn-icon-mobile[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 1.125rem;\n }\n}\n\n\n\n\n\n.mj-grid-4[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 0.5rem;\n padding: 0 1rem 0.75rem 1rem;\n background: var(--mj-bg-page);\n}\n\n@media (min-width: 768px) {\n .mj-grid-4[_ngcontent-%COMP%] {\n grid-template-columns: repeat(4, 1fr);\n padding: 0 1.5rem 1rem 1.5rem;\n gap: 0.75rem;\n }\n}\n\n@media (min-width: 1024px) {\n .mj-grid-4[_ngcontent-%COMP%] {\n gap: 1rem;\n }\n}\n\n\n\n.mj-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n border-radius: var(--mj-radius-lg);\n padding: 1rem;\n box-shadow: var(--mj-shadow-sm);\n display: flex;\n align-items: center;\n gap: 1rem;\n border: 1px solid var(--mj-border-default);\n cursor: default;\n pointer-events: none;\n}\n\n@media (min-width: 768px) {\n .mj-card[_ngcontent-%COMP%] {\n padding: 1rem 1.25rem;\n }\n}\n\n\n\n\n\n.stat-icon[_ngcontent-%COMP%] {\n width: 48px;\n height: 48px;\n border-radius: var(--mj-radius-lg);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 1.25rem;\n flex-shrink: 0;\n}\n\n@media (min-width: 768px) {\n .stat-icon[_ngcontent-%COMP%] {\n width: 52px;\n height: 52px;\n font-size: 1.375rem;\n }\n}\n\n.stat-icon-total[_ngcontent-%COMP%] {\n background: var(--mj-color-accent-300);\n color: var(--mj-brand-primary);\n}\n\n.stat-icon-active[_ngcontent-%COMP%] {\n background: var(--mj-color-success-100);\n color: var(--mj-status-success);\n}\n\n\n\n\n\n.stat-content[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.stat-content[_ngcontent-%COMP%] .stat-value[_ngcontent-%COMP%] {\n font-size: 1.75rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n line-height: 1;\n letter-spacing: -0.02em;\n}\n\n@media (min-width: 768px) {\n .stat-content[_ngcontent-%COMP%] .stat-value[_ngcontent-%COMP%] {\n font-size: 2rem;\n }\n}\n\n.stat-content[_ngcontent-%COMP%] .stat-label[_ngcontent-%COMP%] {\n font-size: 0.75rem;\n font-weight: 500;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin-top: 0.25rem;\n}\n\n@media (min-width: 768px) {\n .stat-content[_ngcontent-%COMP%] .stat-label[_ngcontent-%COMP%] {\n font-size: 0.8125rem;\n }\n}\n\n\n\n\n\n.filters-section[_ngcontent-%COMP%] {\n flex-shrink: 0;\n background: var(--mj-bg-surface-card);\n margin: 0 1rem 0.75rem 1rem;\n padding: 0.75rem;\n border-radius: var(--mj-radius-lg);\n border: 1px solid var(--mj-border-default);\n}\n\n@media (min-width: 768px) {\n .filters-section[_ngcontent-%COMP%] {\n margin: 0 1.5rem 1rem 1.5rem;\n padding: 1rem 1.25rem;\n }\n}\n\n.filters-row[_ngcontent-%COMP%] {\n display: flex;\n gap: 1rem;\n align-items: flex-end;\n flex-wrap: wrap;\n}\n\n@media (min-width: 768px) {\n .filters-row[_ngcontent-%COMP%] {\n gap: 1.5rem;\n }\n}\n\n.mj-filter-group[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.mj-filter-label[_ngcontent-%COMP%] {\n font-size: 0.75rem;\n font-weight: 500;\n color: var(--mj-text-primary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n.mj-filter-buttons[_ngcontent-%COMP%] {\n display: flex;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-full);\n padding: 4px;\n gap: 2px;\n}\n\n.mj-filter-buttons[_ngcontent-%COMP%] .mj-btn[_ngcontent-%COMP%] {\n border-radius: var(--mj-radius-full);\n}\n\n.mj-filter-buttons[_ngcontent-%COMP%] .mj-btn-primary[_ngcontent-%COMP%] {\n background-color: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n box-shadow: var(--mj-shadow-sm);\n}\n\n\n\n\n\n.mj-search[_ngcontent-%COMP%] {\n position: relative;\n flex: 1;\n min-width: 200px;\n}\n\n@media (min-width: 640px) {\n .mj-search[_ngcontent-%COMP%] {\n min-width: 280px;\n }\n}\n\n@media (min-width: 1024px) {\n .mj-search[_ngcontent-%COMP%] {\n min-width: 400px;\n max-width: 600px;\n }\n}\n\n@media (min-width: 1440px) {\n .mj-search[_ngcontent-%COMP%] {\n min-width: 500px;\n max-width: 800px;\n }\n}\n\n.mj-search[_ngcontent-%COMP%] .mj-search-icon[_ngcontent-%COMP%] {\n position: absolute;\n left: 1rem;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-secondary);\n font-size: 1rem;\n pointer-events: none;\n transition: color 0.2s ease;\n}\n\n@media (min-width: 1024px) {\n .mj-search[_ngcontent-%COMP%] .mj-search-icon[_ngcontent-%COMP%] {\n left: 1.25rem;\n font-size: 1.125rem;\n }\n}\n\n.mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 0.875rem 1rem 0.875rem 2.75rem;\n border: 2px solid var(--mj-border-default);\n border-radius: var(--mj-radius-full);\n font-size: 1rem;\n background: var(--mj-bg-page);\n color: var(--mj-text-primary);\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 44px;\n}\n\n@media (min-width: 1024px) {\n .mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%] {\n padding: 1rem 1.25rem 1rem 3.25rem;\n font-size: 1.0625rem;\n }\n}\n\n@media (min-width: 1440px) {\n .mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%] {\n padding: 1.125rem 1.5rem 1.125rem 3.5rem;\n }\n}\n\n.mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%]::placeholder {\n color: var(--mj-text-secondary);\n}\n\n.mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n}\n\n.mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px rgba(0, 118, 182, 0.2);\n background: var(--mj-bg-page);\n}\n\n.mj-search[_ngcontent-%COMP%]:focus-within .mj-search-icon[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n\n\n\n\n.content-area[_ngcontent-%COMP%] {\n flex: 1 1 auto;\n overflow: visible;\n position: relative;\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-xl);\n box-shadow: var(--mj-shadow-sm);\n padding: 1rem;\n border: 1px solid var(--mj-border-default);\n}\n\n@media (min-width: 768px) {\n .content-area[_ngcontent-%COMP%] {\n padding: 1.5rem;\n }\n}\n\n\n\n\n\n.expand-btn[_ngcontent-%COMP%] {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 1rem;\n cursor: pointer;\n transition: all 0.2s ease;\n border-radius: var(--mj-radius-full);\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.expand-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.expand-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n transition: transform 0.3s cubic-bezier(0, 0, 0.2, 1);\n}\n\n\n\n\n\n.status-badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.375rem 0.875rem;\n border-radius: var(--mj-radius-full);\n font-size: 0.75rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.03em;\n}\n\n.status-badge.status-active[_ngcontent-%COMP%] {\n background: var(--mj-color-success-100);\n color: var(--mj-color-success-800);\n border: 1px solid var(--mj-status-success);\n}\n\n.status-badge.status-inactive[_ngcontent-%COMP%] {\n background: var(--mj-color-error-100);\n color: var(--mj-status-error);\n border: 1px solid var(--mj-status-error);\n}\n\n.status-badge[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 0.625rem;\n}\n\n\n\n\n\n.mobile-actions-bar[_ngcontent-%COMP%] {\n display: none;\n}\n\n.mobile-action-buttons[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.5rem;\n}\n\n\n\n\n\n.empty-state[_ngcontent-%COMP%] {\n text-align: center;\n padding: 4rem 2rem;\n}\n\n.empty-state[_ngcontent-%COMP%] .empty-icon[_ngcontent-%COMP%] {\n font-size: 4rem;\n color: var(--mj-border-default);\n margin-bottom: 1.5rem;\n}\n\n.empty-state[_ngcontent-%COMP%] .empty-text[_ngcontent-%COMP%] {\n font-size: 1.25rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0 0 0.5rem 0;\n}\n\n.empty-state[_ngcontent-%COMP%] .empty-subtext[_ngcontent-%COMP%] {\n font-size: 1rem;\n color: var(--mj-text-secondary);\n margin: 0;\n}\n\n\n\n\n\n.loading-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 4rem 2rem;\n}\n\n\n\n\n\n.error-container[_ngcontent-%COMP%] {\n text-align: center;\n padding: 4rem 2rem;\n}\n\n.error-container[_ngcontent-%COMP%] .error-content[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 1rem;\n}\n\n.error-container[_ngcontent-%COMP%] .error-icon[_ngcontent-%COMP%] {\n font-size: 3.5rem;\n color: var(--mj-status-error);\n margin-bottom: 1rem;\n}\n\n.error-container[_ngcontent-%COMP%] .error-message[_ngcontent-%COMP%] {\n font-size: 1.0625rem;\n color: var(--mj-text-primary);\n margin: 0 0 1.5rem 0;\n}\n\n\n\n\n\n.modal-backdrop[_ngcontent-%COMP%] {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.4);\n backdrop-filter: blur(4px);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n padding: 1rem;\n animation: _ngcontent-%COMP%_fadeIn 0.2s cubic-bezier(0, 0, 0.2, 1);\n}\n\n.modal-dialog[_ngcontent-%COMP%] {\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-2xl);\n box-shadow: var(--mj-shadow-2xl);\n max-width: 500px;\n width: 100%;\n max-height: 90vh;\n overflow: hidden;\n animation: _ngcontent-%COMP%_slideUp 0.3s cubic-bezier(0, 0, 0.2, 1);\n}\n\n.modal-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 1.5rem;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.modal-header[_ngcontent-%COMP%] .modal-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n font-size: 1.375rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0;\n}\n\n.modal-header[_ngcontent-%COMP%] .modal-close[_ngcontent-%COMP%] {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 1.25rem;\n cursor: pointer;\n border-radius: var(--mj-radius-full);\n transition: all 0.2s ease;\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.modal-header[_ngcontent-%COMP%] .modal-close[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.modal-body[_ngcontent-%COMP%] {\n padding: 1.5rem;\n}\n\n.modal-body[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n font-size: 1rem;\n color: var(--mj-text-primary);\n margin: 0 0 1rem 0;\n line-height: 1.5;\n}\n\n.modal-body[_ngcontent-%COMP%] p[_ngcontent-%COMP%]:last-child {\n margin-bottom: 0;\n}\n\n.modal-footer[_ngcontent-%COMP%] {\n display: flex;\n justify-content: flex-start;\n gap: 0.75rem;\n padding: 1.5rem;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n}\n\n@media (max-width: 639px) {\n .modal-dialog[_ngcontent-%COMP%] {\n width: 95%;\n max-height: 85vh;\n }\n\n .modal-header[_ngcontent-%COMP%] {\n padding: 1rem;\n }\n\n .modal-header[_ngcontent-%COMP%] .modal-title[_ngcontent-%COMP%] {\n font-size: 1.125rem;\n }\n\n .modal-body[_ngcontent-%COMP%] {\n padding: 1rem;\n }\n\n .modal-footer[_ngcontent-%COMP%] {\n padding: 1rem;\n flex-direction: column;\n }\n\n .modal-footer[_ngcontent-%COMP%] .mj-btn[_ngcontent-%COMP%] {\n width: 100%;\n justify-content: center;\n }\n}\n\n\n\n\n\n.mj-btn[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n padding: 0.75rem 1.5rem;\n font-size: 0.875rem;\n font-weight: 600;\n border: none;\n border-radius: var(--mj-radius-full);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n white-space: nowrap;\n min-height: 44px;\n}\n\n.mj-btn[_ngcontent-%COMP%]:disabled {\n opacity: 0.38;\n cursor: not-allowed;\n}\n\n\n\n.mj-btn-primary[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n box-shadow: var(--mj-shadow-sm);\n}\n\n.mj-btn-primary[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-brand-primary-light);\n box-shadow: var(--mj-shadow-md);\n}\n\n.mj-btn-primary[_ngcontent-%COMP%]:active:not(:disabled) {\n background: var(--mj-color-brand-400);\n transform: scale(0.98);\n}\n\n\n\n.mj-btn-secondary[_ngcontent-%COMP%] {\n background: var(--mj-bg-page);\n color: var(--mj-brand-primary);\n border: 1px solid var(--mj-color-neutral-400);\n}\n\n.mj-btn-secondary[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.mj-btn-secondary[_ngcontent-%COMP%]:active:not(:disabled) {\n background: var(--mj-color-brand-700);\n border-color: var(--mj-color-brand-700);\n}\n\n\n\n.mj-btn-ghost[_ngcontent-%COMP%] {\n background: transparent;\n color: var(--mj-text-secondary);\n}\n\n.mj-btn-ghost[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.mj-btn-ghost[_ngcontent-%COMP%]:active:not(:disabled) {\n background: var(--mj-color-brand-700);\n}\n\n\n\n.mj-btn-danger[_ngcontent-%COMP%] {\n background: var(--mj-status-error);\n color: var(--mj-text-inverse);\n box-shadow: var(--mj-shadow-sm);\n}\n\n.mj-btn-danger[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-color-error-300);\n box-shadow: var(--mj-shadow-md);\n}\n\n.mj-btn-danger[_ngcontent-%COMP%]:active:not(:disabled) {\n background: var(--mj-color-error-200);\n transform: scale(0.98);\n}\n\n\n\n.mj-btn-sm[_ngcontent-%COMP%] {\n padding: 0.5rem 0.875rem;\n font-size: 0.8125rem;\n min-height: 36px;\n}\n\n\n\n.mj-btn-icon-only[_ngcontent-%COMP%] {\n padding: 0.625rem;\n min-width: 44px;\n min-height: 44px;\n}\n\n\n\n.mj-btn-icon-mobile[_ngcontent-%COMP%] {\n gap: 0.5rem;\n}\n\n.mj-btn-icon-mobile[_ngcontent-%COMP%] .btn-text[_ngcontent-%COMP%] {\n display: inline;\n}\n\n\n\n.mj-btn-ghost.mj-btn-danger[_ngcontent-%COMP%] {\n background: transparent;\n color: var(--mj-status-error);\n box-shadow: none;\n}\n\n.mj-btn-ghost.mj-btn-danger[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-color-error-100);\n color: var(--mj-status-error);\n}\n\n\n\n\n\n.filter-button[_ngcontent-%COMP%] {\n display: none;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n padding: 0.75rem 1.25rem;\n border: 2px solid var(--mj-border-default);\n background: var(--mj-bg-page);\n color: var(--mj-text-primary);\n border-radius: var(--mj-radius-full);\n font-size: 0.875rem;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 44px;\n min-width: 44px;\n}\n\n.filter-button[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n}\n\n.filter-button[_ngcontent-%COMP%]:active {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.filter-button[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 1rem;\n}\n\n\n\n\n\n.filter-modal-backdrop[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.4);\n backdrop-filter: blur(4px);\n display: flex;\n align-items: flex-end;\n justify-content: center;\n z-index: 1000;\n animation: _ngcontent-%COMP%_fadeIn 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n padding: 0;\n}\n\n.filter-modal[_ngcontent-%COMP%] {\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-2xl) var(--mj-radius-2xl) 0 0;\n box-shadow: var(--mj-shadow-2xl);\n width: 100%;\n max-height: 80vh;\n overflow: hidden;\n animation: _ngcontent-%COMP%_slideUpFromBottom 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n display: flex;\n flex-direction: column;\n}\n\n.filter-modal-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 1.25rem 1.5rem;\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.filter-modal-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n font-size: 1.25rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0;\n}\n\n.filter-modal-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 1.375rem;\n}\n\n.filter-modal-close[_ngcontent-%COMP%] {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 1.25rem;\n cursor: pointer;\n border-radius: var(--mj-radius-full);\n transition: all 0.2s ease;\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.filter-modal-close[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.filter-modal-body[_ngcontent-%COMP%] {\n padding: 1.5rem;\n overflow-y: auto;\n -webkit-overflow-scrolling: touch;\n flex: 1;\n}\n\n.filter-modal-footer[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.75rem;\n padding: 1.25rem 1.5rem;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n flex-shrink: 0;\n}\n\n.filter-modal-footer[_ngcontent-%COMP%] button[_ngcontent-%COMP%] {\n flex: 1;\n margin: 0;\n}\n\n\n\n.filter-options-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n.filter-group[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n}\n\n.filter-group-label[_ngcontent-%COMP%] {\n font-size: 0.875rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin: 0;\n}\n\n.filter-group-options[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.filter-option[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 0.875rem 1rem;\n background: var(--mj-bg-surface-sunken);\n border: 2px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 56px;\n}\n\n.filter-option[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface-sunken);\n}\n\n.filter-option.selected[_ngcontent-%COMP%] {\n background: var(--mj-color-accent-300);\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.filter-option[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%], \n.filter-option[_ngcontent-%COMP%] input[type=\"radio\"][_ngcontent-%COMP%] {\n width: 20px;\n height: 20px;\n cursor: pointer;\n accent-color: var(--mj-brand-primary);\n flex-shrink: 0;\n}\n\n.filter-option-label[_ngcontent-%COMP%] {\n flex: 1;\n font-size: 1rem;\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.filter-option.selected[_ngcontent-%COMP%] .filter-option-label[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n\n\n\n\n.text-danger[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n.text-warning[_ngcontent-%COMP%] {\n color: var(--mj-color-warning-500);\n}\n\n.text-success[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n\n\n\n\n\n@keyframes _ngcontent-%COMP%_fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n@keyframes _ngcontent-%COMP%_slideUp {\n from {\n transform: translateY(20px);\n opacity: 0;\n }\n to {\n transform: translateY(0);\n opacity: 1;\n }\n}\n\n@keyframes _ngcontent-%COMP%_slideDown {\n from {\n opacity: 0;\n transform: translateY(-10px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes _ngcontent-%COMP%_slideUpFromBottom {\n from {\n transform: translateY(100%);\n opacity: 0;\n }\n to {\n transform: translateY(0);\n opacity: 1;\n }\n}\n\n\n\n\n\n.mj-search-input[_ngcontent-%COMP%]:focus-visible, \nbutton[_ngcontent-%COMP%]:focus-visible, \n.mj-btn[_ngcontent-%COMP%]:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\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\n.user-management-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n position: relative;\n width: 100%;\n background: var(--mj-bg-page);\n}\n\n\n\n\n\n.mj-grid-4[_ngcontent-%COMP%] {\n display: none;\n}\n\n@media (min-width: 768px) {\n .mj-grid-4[_ngcontent-%COMP%] {\n display: grid;\n }\n}\n\n\n\n@media (min-width: 768px) {\n .stat-icon[_ngcontent-%COMP%] {\n width: 48px;\n height: 48px;\n font-size: 1.25rem;\n }\n}\n\n\n\n.stat-icon-total[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-accent) 25%, transparent);\n color: var(--mj-brand-primary);\n}\n\n.stat-icon-inactive[_ngcontent-%COMP%] {\n background: var(--mj-color-error-100);\n color: var(--mj-status-error);\n}\n\n.stat-icon-admin[_ngcontent-%COMP%] {\n background: var(--mj-color-warning-50);\n color: var(--mj-color-warning-700);\n}\n\n\n\n\n\n@media (max-width: 767px) {\n .filters-section[_ngcontent-%COMP%] {\n padding: 0.75rem;\n }\n\n .filters-row[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: row;\n gap: 0.75rem;\n align-items: center;\n }\n\n .filters-row[_ngcontent-%COMP%] .mj-search[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n }\n}\n\n@media (max-width: 767px) {\n .mj-search[_ngcontent-%COMP%] {\n width: 100%;\n max-width: none;\n min-width: 0;\n }\n}\n\n\n\n@media (min-width: 768px) {\n .mj-search[_ngcontent-%COMP%] {\n min-width: 320px;\n max-width: 600px;\n }\n\n .mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%] {\n padding: 1rem 1.25rem 1rem 3rem;\n min-height: 52px;\n font-size: 1.0625rem;\n }\n\n .mj-search[_ngcontent-%COMP%] .mj-search-icon[_ngcontent-%COMP%] {\n left: 1.125rem;\n font-size: 1.125rem;\n }\n}\n\n\n\n.mobile-filter-toggle[_ngcontent-%COMP%] {\n display: none;\n align-items: center;\n justify-content: center;\n position: relative;\n width: 48px;\n height: 48px;\n min-width: 48px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n font-size: 1.125rem;\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n box-shadow: var(--mj-shadow-sm);\n flex-shrink: 0;\n}\n\n.mobile-filter-toggle[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.mobile-filter-toggle.active[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.filter-badge[_ngcontent-%COMP%] {\n position: absolute;\n top: -4px;\n right: -4px;\n min-width: 18px;\n height: 18px;\n padding: 0 5px;\n border-radius: var(--mj-radius-full);\n background: var(--mj-status-error);\n color: var(--mj-text-inverse);\n font-size: 0.6875rem;\n font-weight: 700;\n display: flex;\n align-items: center;\n justify-content: center;\n line-height: 1;\n}\n\n\n\n.mobile-filter-dropdown[_ngcontent-%COMP%] {\n display: none;\n margin-top: 0.75rem;\n padding-top: 0.75rem;\n border-top: 1px solid var(--mj-border-default);\n animation: slideDown 0.2s ease;\n}\n\n@media (max-width: 767px) {\n .mobile-filter-toggle[_ngcontent-%COMP%] {\n display: flex !important;\n }\n\n .mobile-filter-dropdown[_ngcontent-%COMP%] {\n display: block;\n }\n\n .desktop-filter-group[_ngcontent-%COMP%] {\n display: none !important;\n }\n}\n\n.mobile-filter-content[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n}\n\n.mobile-filter-content[_ngcontent-%COMP%] .mj-filter-group[_ngcontent-%COMP%] {\n width: 100%;\n}\n\n.mobile-filter-content[_ngcontent-%COMP%] .mj-filter-select[_ngcontent-%COMP%] {\n width: 100%;\n}\n\n.clear-filters-btn[_ngcontent-%COMP%] {\n align-self: flex-start;\n margin-top: 0.25rem;\n}\n\n\n\n.desktop-filter-group[_ngcontent-%COMP%] {\n display: none !important;\n}\n\n@media screen and (min-width: 768px) {\n .desktop-filter-group[_ngcontent-%COMP%] {\n display: flex !important;\n flex-direction: column;\n gap: 0.375rem;\n }\n\n .mobile-filter-toggle[_ngcontent-%COMP%] {\n display: none !important;\n }\n\n .mobile-filter-dropdown[_ngcontent-%COMP%] {\n display: none !important;\n }\n}\n\n@media (max-width: 767px) {\n .mj-filter-group[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 100px;\n }\n}\n\n.mj-filter-select[_ngcontent-%COMP%] {\n padding: 0.625rem 1rem;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n background: var(--mj-bg-surface-sunken);\n font-size: 0.875rem;\n font-weight: 500;\n color: var(--mj-text-primary);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-width: 120px;\n box-shadow: var(--mj-shadow-sm);\n}\n\n.mj-filter-select[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-brand-primary);\n}\n\n@media (max-width: 767px) {\n .mj-filter-select[_ngcontent-%COMP%] {\n width: 100%;\n padding: 0.5rem 0.75rem;\n font-size: 0.8125rem;\n }\n}\n\n.mj-filter-select[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px rgba(0, 118, 182, 0.2);\n}\n\n\n\n\n\n.bulk-action-toolbar[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n padding: 0.75rem 1rem;\n background: var(--mj-brand-accent-subtle);\n border-bottom: 1px solid var(--mj-border-default);\n animation: slideDown 0.2s ease;\n}\n\n@media (min-width: 768px) {\n .bulk-action-toolbar[_ngcontent-%COMP%] {\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n padding: 1rem 1.5rem;\n }\n}\n\n.bulk-selection-info[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n font-size: 0.875rem;\n font-weight: 600;\n color: var(--mj-brand-primary);\n}\n\n.bulk-selection-info[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 1.25rem;\n}\n\n.bulk-action-buttons[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.5rem;\n flex-wrap: wrap;\n}\n\n@media (max-width: 639px) {\n .bulk-action-buttons[_ngcontent-%COMP%] .btn-text[_ngcontent-%COMP%] {\n display: none;\n }\n\n .bulk-action-buttons[_ngcontent-%COMP%] .mj-btn-sm[_ngcontent-%COMP%] {\n padding: 0.5rem;\n min-width: 36px;\n }\n}\n\n\n\n\n\n.users-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n}\n\n.list-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.75rem 1rem;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-md);\n border: 1px solid var(--mj-border-default);\n margin-bottom: 0.5rem;\n}\n\n.select-all-label[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n cursor: pointer;\n font-size: 0.875rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.select-all-text[_ngcontent-%COMP%] {\n font-weight: 500;\n}\n\n.selection-count[_ngcontent-%COMP%] {\n font-size: 0.75rem;\n font-weight: 600;\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-accent) 25%, transparent);\n padding: 0.25rem 0.75rem;\n border-radius: var(--mj-radius-full);\n}\n\n.user-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-xl);\n overflow: hidden;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.user-card[_ngcontent-%COMP%]:hover {\n box-shadow: var(--mj-shadow-md);\n border-color: var(--mj-brand-primary);\n}\n\n.user-card.expanded[_ngcontent-%COMP%] {\n box-shadow: var(--mj-shadow-lg);\n border-color: var(--mj-brand-primary);\n}\n\n.user-card.selected[_ngcontent-%COMP%] {\n background: var(--mj-brand-accent-subtle);\n border-color: var(--mj-brand-primary);\n}\n\n.user-card.selected[_ngcontent-%COMP%] .user-header[_ngcontent-%COMP%] {\n background: transparent;\n}\n\n.user-card.selected[_ngcontent-%COMP%]:hover .user-header[_ngcontent-%COMP%] {\n background: rgba(0, 118, 182, 0.08);\n}\n\n.user-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 1.25rem 1.5rem;\n cursor: pointer;\n background: var(--mj-bg-surface);\n transition: background-color 0.2s ease;\n}\n\n.user-header[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n@media (max-width: 639px) {\n .user-header[_ngcontent-%COMP%] {\n padding: 0.875rem 1rem;\n gap: 0.625rem;\n }\n}\n\n.user-selection[_ngcontent-%COMP%] {\n flex-shrink: 0;\n}\n\n.checkbox[_ngcontent-%COMP%] {\n width: 20px;\n height: 20px;\n cursor: pointer;\n accent-color: var(--mj-brand-primary);\n}\n\n.user-info[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n flex: 1;\n min-width: 0;\n}\n\n.user-avatar[_ngcontent-%COMP%] {\n width: 48px;\n height: 48px;\n border-radius: var(--mj-radius-full);\n background: linear-gradient(135deg, var(--mj-brand-primary) 0%, var(--mj-brand-primary-light) 100%);\n color: var(--mj-brand-on-primary);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 0.875rem;\n font-weight: 600;\n flex-shrink: 0;\n}\n\n@media (max-width: 639px) {\n .user-avatar[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n font-size: 0.8125rem;\n }\n\n .user-details[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n }\n\n .user-name[_ngcontent-%COMP%] {\n font-size: 0.9375rem;\n font-weight: 600;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .user-email[_ngcontent-%COMP%] {\n font-size: 0.8125rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n}\n\n.user-details[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.user-name[_ngcontent-%COMP%] {\n font-size: 1rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.user-email[_ngcontent-%COMP%] {\n font-size: 0.875rem;\n color: var(--mj-text-secondary);\n margin: 0.125rem 0 0 0;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.user-meta[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n flex-shrink: 0;\n}\n\n@media (max-width: 767px) {\n .user-meta[_ngcontent-%COMP%] .status-badge[_ngcontent-%COMP%], \n .user-meta[_ngcontent-%COMP%] .user-actions[_ngcontent-%COMP%] {\n display: none !important;\n }\n\n .user-meta[_ngcontent-%COMP%] {\n gap: 0;\n }\n}\n\n.desktop-only[_ngcontent-%COMP%] {\n display: none;\n}\n\n@media (min-width: 768px) {\n .desktop-only[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.25rem;\n }\n}\n\n.user-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.25rem;\n}\n\n.user-card.expanded[_ngcontent-%COMP%] .expand-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n transform: rotate(180deg);\n}\n\n\n\n.user-content[_ngcontent-%COMP%] {\n padding: 1.25rem 1.5rem;\n background: var(--mj-bg-page);\n border-top: 1px solid var(--mj-border-default);\n animation: slideDown 0.3s cubic-bezier(0, 0, 0.2, 1);\n}\n\n\n\n.mobile-actions-bar[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding-bottom: 1rem;\n margin-bottom: 1rem;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n@media (min-width: 768px) {\n .mobile-actions-bar[_ngcontent-%COMP%] {\n display: none;\n }\n}\n\n.mobile-action-buttons[_ngcontent-%COMP%] .btn-label[_ngcontent-%COMP%] {\n margin-left: 0.375rem;\n}\n\n\n\n.user-stats[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n gap: 1rem;\n margin-bottom: 1rem;\n}\n\n.user-stats[_ngcontent-%COMP%] .stat-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n font-size: 0.875rem;\n color: var(--mj-text-secondary);\n}\n\n.user-stats[_ngcontent-%COMP%] .stat-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 0.875rem;\n}\n\n.user-stats[_ngcontent-%COMP%] .stat-label[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n}\n\n.user-stats[_ngcontent-%COMP%] .stat-value[_ngcontent-%COMP%] {\n color: var(--mj-text-primary);\n font-weight: 500;\n display: flex;\n align-items: center;\n gap: 0.25rem;\n}\n\n.user-stats[_ngcontent-%COMP%] .stat-value[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 0.75rem;\n}\n\n\n\n.roles-section[_ngcontent-%COMP%] {\n padding-top: 1rem;\n border-top: 1px solid var(--mj-border-default);\n}\n\n.section-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.625rem;\n font-size: 1rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0 0 0.75rem 0;\n}\n\n.section-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 1.125rem;\n}\n\n.roles-grid[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n gap: 0.5rem;\n}\n\n.role-item[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.375rem 0.875rem;\n background: var(--mj-color-warning-50);\n color: var(--mj-color-warning-800);\n border: 1px solid var(--mj-color-warning-500);\n border-radius: var(--mj-radius-full);\n font-size: 0.75rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.03em;\n}\n\n.role-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 0.625rem;\n}\n\n.no-roles[_ngcontent-%COMP%] {\n font-size: 0.875rem;\n color: var(--mj-text-secondary);\n margin: 0;\n}\n\n\n\n\n\n.error-container[_ngcontent-%COMP%] .retry-button[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n padding: 0.75rem 1.5rem;\n font-size: 0.875rem;\n font-weight: 600;\n border: none;\n border-radius: var(--mj-radius-full);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n box-shadow: var(--mj-shadow-sm);\n min-height: 44px;\n}\n\n.error-container[_ngcontent-%COMP%] .retry-button[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary-light);\n box-shadow: var(--mj-shadow-md);\n}\n\n.error-container[_ngcontent-%COMP%] .retry-button[_ngcontent-%COMP%]:active {\n background: var(--mj-color-brand-400);\n transform: scale(0.98);\n}\n\n\n\n\n\n.form-field[_ngcontent-%COMP%] {\n margin-bottom: 1rem;\n}\n\n.form-field[_ngcontent-%COMP%] .field-label[_ngcontent-%COMP%] {\n display: block;\n font-size: 0.75rem;\n font-weight: 500;\n color: var(--mj-text-primary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin-bottom: 0.5rem;\n}\n\n.form-field[_ngcontent-%COMP%] .field-select[_ngcontent-%COMP%] {\n width: 100%;\n padding: 0.75rem 1rem;\n border: 1px solid var(--mj-color-neutral-400);\n border-radius: var(--mj-radius-md);\n background: var(--mj-bg-page);\n font-size: 1rem;\n color: var(--mj-text-primary);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.form-field[_ngcontent-%COMP%] .field-select[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px rgba(0, 118, 182, 0.2);\n}\n\n\n\n@media (max-width: 639px) {\n .mj-btn-primary.mj-btn-icon-mobile[_ngcontent-%COMP%] {\n box-shadow: var(--mj-shadow-md);\n }\n\n .mj-btn-primary.mj-btn-icon-mobile[_ngcontent-%COMP%]:hover {\n box-shadow: var(--mj-shadow-lg);\n transform: scale(1.05);\n }\n\n .mj-btn-secondary.mj-btn-icon-mobile[_ngcontent-%COMP%] {\n background: var(--mj-bg-page);\n border: 1px solid var(--mj-color-neutral-400);\n }\n\n .mj-btn-secondary.mj-btn-icon-mobile[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n border-color: var(--mj-brand-primary);\n }\n\n .mj-btn-icon-mobile[_ngcontent-%COMP%] {\n width: 48px;\n height: 48px;\n padding: 0;\n border-radius: var(--mj-radius-full);\n min-width: 48px;\n min-height: 48px;\n }\n\n .mj-btn-icon-mobile[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 1.25rem;\n }\n}\n\n\n\n.checkbox[_ngcontent-%COMP%]:focus-visible, \n.user-header[_ngcontent-%COMP%]:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n\n\n.mj-filter-select[_ngcontent-%COMP%]:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n\n\n\n\n@media (min-width: 1440px) {\n .user-management-container[_ngcontent-%COMP%] {\n margin: 0 auto;\n }\n\n .action-buttons[_ngcontent-%COMP%] {\n padding: 1.25rem 2rem;\n }\n\n .bulk-action-toolbar[_ngcontent-%COMP%] {\n padding: 1.25rem 2rem;\n }\n\n .mj-grid-4[_ngcontent-%COMP%] {\n gap: 1.5rem;\n padding: 0 2rem 1rem 2rem;\n }\n\n .filters-section[_ngcontent-%COMP%] {\n margin: 0 2rem 1rem 2rem;\n padding: 1rem 1.5rem;\n }\n\n .scrollable-content[_ngcontent-%COMP%] {\n padding: 2rem;\n }\n}\n\n\n\n\n\n@media (max-width: 639px) {\n .sticky-header[_ngcontent-%COMP%] {\n padding-bottom: 0;\n }\n\n .mj-grid-4[_ngcontent-%COMP%] {\n grid-template-columns: repeat(2, 1fr);\n gap: 0.5rem;\n padding: 0 0.75rem 0.5rem 0.75rem;\n }\n\n .mj-card[_ngcontent-%COMP%] {\n padding: 0.75rem;\n gap: 0.75rem;\n }\n\n .stat-icon[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n font-size: 1.125rem;\n }\n\n .stat-content[_ngcontent-%COMP%] .stat-value[_ngcontent-%COMP%] {\n font-size: 1.5rem;\n }\n\n .stat-content[_ngcontent-%COMP%] .stat-label[_ngcontent-%COMP%] {\n font-size: 0.6875rem;\n }\n\n .filters-section[_ngcontent-%COMP%] {\n margin: 0 0.75rem 0.5rem 0.75rem;\n padding: 0.75rem;\n }\n\n .scrollable-content[_ngcontent-%COMP%] {\n padding: 0.75rem;\n }\n\n .content-area[_ngcontent-%COMP%] {\n padding: 0.875rem;\n border-radius: var(--mj-radius-lg);\n }\n\n .list-header[_ngcontent-%COMP%] {\n padding: 0.625rem 0.75rem;\n }\n\n .empty-state[_ngcontent-%COMP%] {\n padding: 2rem 1rem;\n }\n\n .empty-state[_ngcontent-%COMP%] .empty-icon[_ngcontent-%COMP%] {\n font-size: 3rem;\n }\n\n .empty-state[_ngcontent-%COMP%] .empty-text[_ngcontent-%COMP%] {\n font-size: 1.0625rem;\n }\n\n .empty-state[_ngcontent-%COMP%] .empty-subtext[_ngcontent-%COMP%] {\n font-size: 0.875rem;\n }\n}"] });
|
|
1223
|
+
i0.ɵɵconditional(ctx.showBulkRoleAssign ? 27 : -1);
|
|
1224
|
+
} }, dependencies: [i1.NgSelectOption, i1.ɵNgSelectMultipleOption, i1.SelectControlValueAccessor, i1.NgControlStatus, i1.NgModel, i2.LoadingComponent, i3.MJButtonDirective, i3.MJPageHeaderInteriorComponent, i3.MJPageBodyInteriorComponent, i3.MJPageSearchComponent, i3.MJFilterPopoverComponent, i3.MJFilterPanelComponent, i3.MJFilterChipComponent, i3.MJRefreshButtonComponent, i3.MJStatBadgeComponent, i4.UserDialogComponent, i5.DatePipe], styles: ["\n\n\n\n\n\n\n\n\n\n\n[_nghost-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n width: 100%;\n overflow: hidden;\n}\n\n\n\n\n\n.sticky-header[_ngcontent-%COMP%] {\n flex-shrink: 0;\n background: var(--mj-bg-page);\n border-bottom: 1px solid var(--mj-border-default);\n box-shadow: var(--mj-shadow-sm);\n z-index: 10;\n}\n\n\n\n\n\n.scrollable-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n -webkit-overflow-scrolling: touch;\n padding: 1rem;\n background: var(--mj-bg-surface-sunken);\n}\n\n@media (min-width: 768px) {\n .scrollable-content[_ngcontent-%COMP%] {\n padding: 1.5rem 2rem;\n }\n}\n\n@media (min-width: 1024px) {\n .scrollable-content[_ngcontent-%COMP%] {\n padding: 2rem;\n }\n}\n\n@media (min-width: 1440px) {\n .scrollable-content[_ngcontent-%COMP%] {\n padding: 2rem 2.5rem;\n }\n}\n\n\n\n\n\n.action-buttons[_ngcontent-%COMP%] {\n flex-shrink: 0;\n display: flex;\n gap: 0.75rem;\n justify-content: flex-end;\n padding: 0.75rem 1rem;\n background: var(--mj-bg-page);\n}\n\n@media (min-width: 768px) {\n .action-buttons[_ngcontent-%COMP%] {\n padding: 1rem 1.5rem;\n }\n}\n\n@media (max-width: 639px) {\n .action-buttons[_ngcontent-%COMP%] {\n justify-content: center;\n flex-wrap: wrap;\n }\n}\n\n\n\n\n\n.mj-grid-4[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 0.5rem;\n padding: 0 1rem 0.75rem 1rem;\n background: var(--mj-bg-page);\n}\n\n@media (min-width: 768px) {\n .mj-grid-4[_ngcontent-%COMP%] {\n grid-template-columns: repeat(4, 1fr);\n padding: 0 1.5rem 1rem 1.5rem;\n gap: 0.75rem;\n }\n}\n\n@media (min-width: 1024px) {\n .mj-grid-4[_ngcontent-%COMP%] {\n gap: 1rem;\n }\n}\n\n\n\n.mj-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n border-radius: var(--mj-radius-lg);\n padding: 1rem;\n box-shadow: var(--mj-shadow-sm);\n display: flex;\n align-items: center;\n gap: 1rem;\n border: 1px solid var(--mj-border-default);\n cursor: default;\n pointer-events: none;\n}\n\n@media (min-width: 768px) {\n .mj-card[_ngcontent-%COMP%] {\n padding: 1rem 1.25rem;\n }\n}\n\n\n\n\n\n.stat-icon[_ngcontent-%COMP%] {\n width: 48px;\n height: 48px;\n border-radius: var(--mj-radius-lg);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 1.25rem;\n flex-shrink: 0;\n}\n\n@media (min-width: 768px) {\n .stat-icon[_ngcontent-%COMP%] {\n width: 52px;\n height: 52px;\n font-size: 1.375rem;\n }\n}\n\n.stat-icon-total[_ngcontent-%COMP%] {\n background: var(--mj-color-accent-300);\n color: var(--mj-brand-primary);\n}\n\n.stat-icon-active[_ngcontent-%COMP%] {\n background: var(--mj-color-success-100);\n color: var(--mj-status-success);\n}\n\n\n\n\n\n.stat-content[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.stat-content[_ngcontent-%COMP%] .stat-value[_ngcontent-%COMP%] {\n font-size: 1.75rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n line-height: 1;\n letter-spacing: -0.02em;\n}\n\n@media (min-width: 768px) {\n .stat-content[_ngcontent-%COMP%] .stat-value[_ngcontent-%COMP%] {\n font-size: 2rem;\n }\n}\n\n.stat-content[_ngcontent-%COMP%] .stat-label[_ngcontent-%COMP%] {\n font-size: 0.75rem;\n font-weight: 500;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin-top: 0.25rem;\n}\n\n@media (min-width: 768px) {\n .stat-content[_ngcontent-%COMP%] .stat-label[_ngcontent-%COMP%] {\n font-size: 0.8125rem;\n }\n}\n\n\n\n\n\n.filters-section[_ngcontent-%COMP%] {\n flex-shrink: 0;\n background: var(--mj-bg-surface-card);\n margin: 0 1rem 0.75rem 1rem;\n padding: 0.75rem;\n border-radius: var(--mj-radius-lg);\n border: 1px solid var(--mj-border-default);\n}\n\n@media (min-width: 768px) {\n .filters-section[_ngcontent-%COMP%] {\n margin: 0 1.5rem 1rem 1.5rem;\n padding: 1rem 1.25rem;\n }\n}\n\n.filters-row[_ngcontent-%COMP%] {\n display: flex;\n gap: 1rem;\n align-items: flex-end;\n flex-wrap: wrap;\n}\n\n@media (min-width: 768px) {\n .filters-row[_ngcontent-%COMP%] {\n gap: 1.5rem;\n }\n}\n\n.mj-filter-group[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.mj-filter-label[_ngcontent-%COMP%] {\n font-size: 0.75rem;\n font-weight: 500;\n color: var(--mj-text-primary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n.mj-filter-buttons[_ngcontent-%COMP%] {\n display: flex;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-full);\n padding: 4px;\n gap: 2px;\n}\n\n\n\n\n\n.mj-search[_ngcontent-%COMP%] {\n position: relative;\n flex: 1;\n min-width: 200px;\n}\n\n@media (min-width: 640px) {\n .mj-search[_ngcontent-%COMP%] {\n min-width: 280px;\n }\n}\n\n@media (min-width: 1024px) {\n .mj-search[_ngcontent-%COMP%] {\n min-width: 400px;\n max-width: 600px;\n }\n}\n\n@media (min-width: 1440px) {\n .mj-search[_ngcontent-%COMP%] {\n min-width: 500px;\n max-width: 800px;\n }\n}\n\n.mj-search[_ngcontent-%COMP%] .mj-search-icon[_ngcontent-%COMP%] {\n position: absolute;\n left: 1rem;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-secondary);\n font-size: 1rem;\n pointer-events: none;\n transition: color 0.2s ease;\n}\n\n@media (min-width: 1024px) {\n .mj-search[_ngcontent-%COMP%] .mj-search-icon[_ngcontent-%COMP%] {\n left: 1.25rem;\n font-size: 1.125rem;\n }\n}\n\n.mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 0.875rem 1rem 0.875rem 2.75rem;\n border: 2px solid var(--mj-border-default);\n border-radius: var(--mj-radius-full);\n font-size: 1rem;\n background: var(--mj-bg-page);\n color: var(--mj-text-primary);\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 44px;\n}\n\n@media (min-width: 1024px) {\n .mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%] {\n padding: 1rem 1.25rem 1rem 3.25rem;\n font-size: 1.0625rem;\n }\n}\n\n@media (min-width: 1440px) {\n .mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%] {\n padding: 1.125rem 1.5rem 1.125rem 3.5rem;\n }\n}\n\n.mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%]::placeholder {\n color: var(--mj-text-secondary);\n}\n\n.mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n}\n\n.mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px rgba(0, 118, 182, 0.2);\n background: var(--mj-bg-page);\n}\n\n.mj-search[_ngcontent-%COMP%]:focus-within .mj-search-icon[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n\n\n\n\n.content-area[_ngcontent-%COMP%] {\n flex: 1 1 auto;\n overflow: visible;\n position: relative;\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-xl);\n box-shadow: var(--mj-shadow-sm);\n padding: 1rem;\n border: 1px solid var(--mj-border-default);\n}\n\n@media (min-width: 768px) {\n .content-area[_ngcontent-%COMP%] {\n padding: 1.5rem;\n }\n}\n\n\n\n\n\n.expand-btn[_ngcontent-%COMP%] {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 1rem;\n cursor: pointer;\n transition: all 0.2s ease;\n border-radius: var(--mj-radius-full);\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.expand-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.expand-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n transition: transform 0.3s cubic-bezier(0, 0, 0.2, 1);\n}\n\n\n\n\n\n.status-badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.375rem 0.875rem;\n border-radius: var(--mj-radius-full);\n font-size: 0.75rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.03em;\n}\n\n.status-badge.status-active[_ngcontent-%COMP%] {\n background: var(--mj-color-success-100);\n color: var(--mj-color-success-800);\n border: 1px solid var(--mj-status-success);\n}\n\n.status-badge.status-inactive[_ngcontent-%COMP%] {\n background: var(--mj-color-error-100);\n color: var(--mj-status-error);\n border: 1px solid var(--mj-status-error);\n}\n\n.status-badge[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 0.625rem;\n}\n\n\n\n\n\n.mobile-actions-bar[_ngcontent-%COMP%] {\n display: none;\n}\n\n.mobile-action-buttons[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.5rem;\n}\n\n\n\n\n\n.empty-state[_ngcontent-%COMP%] {\n text-align: center;\n padding: 4rem 2rem;\n}\n\n.empty-state[_ngcontent-%COMP%] .empty-icon[_ngcontent-%COMP%] {\n font-size: 4rem;\n color: var(--mj-border-default);\n margin-bottom: 1.5rem;\n}\n\n.empty-state[_ngcontent-%COMP%] .empty-text[_ngcontent-%COMP%] {\n font-size: 1.25rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0 0 0.5rem 0;\n}\n\n.empty-state[_ngcontent-%COMP%] .empty-subtext[_ngcontent-%COMP%] {\n font-size: 1rem;\n color: var(--mj-text-secondary);\n margin: 0;\n}\n\n\n\n\n\n.loading-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 4rem 2rem;\n}\n\n\n\n\n\n.error-container[_ngcontent-%COMP%] {\n text-align: center;\n padding: 4rem 2rem;\n}\n\n.error-container[_ngcontent-%COMP%] .error-content[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 1rem;\n}\n\n.error-container[_ngcontent-%COMP%] .error-icon[_ngcontent-%COMP%] {\n font-size: 3.5rem;\n color: var(--mj-status-error);\n margin-bottom: 1rem;\n}\n\n.error-container[_ngcontent-%COMP%] .error-message[_ngcontent-%COMP%] {\n font-size: 1.0625rem;\n color: var(--mj-text-primary);\n margin: 0 0 1.5rem 0;\n}\n\n\n\n\n\n.modal-backdrop[_ngcontent-%COMP%] {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.4);\n backdrop-filter: blur(4px);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n padding: 1rem;\n animation: _ngcontent-%COMP%_fadeIn 0.2s cubic-bezier(0, 0, 0.2, 1);\n}\n\n.modal-dialog[_ngcontent-%COMP%] {\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-2xl);\n box-shadow: var(--mj-shadow-2xl);\n max-width: 500px;\n width: 100%;\n max-height: 90vh;\n overflow: hidden;\n animation: _ngcontent-%COMP%_slideUp 0.3s cubic-bezier(0, 0, 0.2, 1);\n}\n\n.modal-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 1.5rem;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.modal-header[_ngcontent-%COMP%] .modal-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n font-size: 1.375rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0;\n}\n\n.modal-header[_ngcontent-%COMP%] .modal-close[_ngcontent-%COMP%] {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 1.25rem;\n cursor: pointer;\n border-radius: var(--mj-radius-full);\n transition: all 0.2s ease;\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.modal-header[_ngcontent-%COMP%] .modal-close[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.modal-body[_ngcontent-%COMP%] {\n padding: 1.5rem;\n}\n\n.modal-body[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n font-size: 1rem;\n color: var(--mj-text-primary);\n margin: 0 0 1rem 0;\n line-height: 1.5;\n}\n\n.modal-body[_ngcontent-%COMP%] p[_ngcontent-%COMP%]:last-child {\n margin-bottom: 0;\n}\n\n.modal-footer[_ngcontent-%COMP%] {\n display: flex;\n justify-content: flex-start;\n gap: 0.75rem;\n padding: 1.5rem;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n}\n\n@media (max-width: 639px) {\n .modal-dialog[_ngcontent-%COMP%] {\n width: 95%;\n max-height: 85vh;\n }\n\n .modal-header[_ngcontent-%COMP%] {\n padding: 1rem;\n }\n\n .modal-header[_ngcontent-%COMP%] .modal-title[_ngcontent-%COMP%] {\n font-size: 1.125rem;\n }\n\n .modal-body[_ngcontent-%COMP%] {\n padding: 1rem;\n }\n\n .modal-footer[_ngcontent-%COMP%] {\n padding: 1rem;\n flex-direction: column;\n }\n\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n.filter-button[_ngcontent-%COMP%] {\n display: none;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n padding: 0.75rem 1.25rem;\n border: 2px solid var(--mj-border-default);\n background: var(--mj-bg-page);\n color: var(--mj-text-primary);\n border-radius: var(--mj-radius-full);\n font-size: 0.875rem;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 44px;\n min-width: 44px;\n}\n\n.filter-button[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n}\n\n.filter-button[_ngcontent-%COMP%]:active {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.filter-button[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 1rem;\n}\n\n\n\n\n\n.filter-modal-backdrop[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.4);\n backdrop-filter: blur(4px);\n display: flex;\n align-items: flex-end;\n justify-content: center;\n z-index: 1000;\n animation: _ngcontent-%COMP%_fadeIn 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n padding: 0;\n}\n\n.filter-modal[_ngcontent-%COMP%] {\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-2xl) var(--mj-radius-2xl) 0 0;\n box-shadow: var(--mj-shadow-2xl);\n width: 100%;\n max-height: 80vh;\n overflow: hidden;\n animation: _ngcontent-%COMP%_slideUpFromBottom 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n display: flex;\n flex-direction: column;\n}\n\n.filter-modal-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 1.25rem 1.5rem;\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.filter-modal-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n font-size: 1.25rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0;\n}\n\n.filter-modal-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 1.375rem;\n}\n\n.filter-modal-close[_ngcontent-%COMP%] {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 1.25rem;\n cursor: pointer;\n border-radius: var(--mj-radius-full);\n transition: all 0.2s ease;\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.filter-modal-close[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.filter-modal-body[_ngcontent-%COMP%] {\n padding: 1.5rem;\n overflow-y: auto;\n -webkit-overflow-scrolling: touch;\n flex: 1;\n}\n\n.filter-modal-footer[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.75rem;\n padding: 1.25rem 1.5rem;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n flex-shrink: 0;\n}\n\n.filter-modal-footer[_ngcontent-%COMP%] button[_ngcontent-%COMP%] {\n flex: 1;\n margin: 0;\n}\n\n\n\n.filter-options-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n.filter-group[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n}\n\n.filter-group-label[_ngcontent-%COMP%] {\n font-size: 0.875rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin: 0;\n}\n\n.filter-group-options[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.filter-option[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 0.875rem 1rem;\n background: var(--mj-bg-surface-sunken);\n border: 2px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 56px;\n}\n\n.filter-option[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface-sunken);\n}\n\n.filter-option.selected[_ngcontent-%COMP%] {\n background: var(--mj-color-accent-300);\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.filter-option[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%], \n.filter-option[_ngcontent-%COMP%] input[type=\"radio\"][_ngcontent-%COMP%] {\n width: 20px;\n height: 20px;\n cursor: pointer;\n accent-color: var(--mj-brand-primary);\n flex-shrink: 0;\n}\n\n.filter-option-label[_ngcontent-%COMP%] {\n flex: 1;\n font-size: 1rem;\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.filter-option.selected[_ngcontent-%COMP%] .filter-option-label[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n\n\n\n\n.text-danger[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n.text-warning[_ngcontent-%COMP%] {\n color: var(--mj-color-warning-500);\n}\n\n.text-success[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n\n\n\n\n\n@keyframes _ngcontent-%COMP%_fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n@keyframes _ngcontent-%COMP%_slideUp {\n from {\n transform: translateY(20px);\n opacity: 0;\n }\n to {\n transform: translateY(0);\n opacity: 1;\n }\n}\n\n@keyframes _ngcontent-%COMP%_slideDown {\n from {\n opacity: 0;\n transform: translateY(-10px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes _ngcontent-%COMP%_slideUpFromBottom {\n from {\n transform: translateY(100%);\n opacity: 0;\n }\n to {\n transform: translateY(0);\n opacity: 1;\n }\n}\n\n\n\n\n\n.mj-search-input[_ngcontent-%COMP%]:focus-visible, \nbutton[_ngcontent-%COMP%]:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\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\n\n\n.status-chips[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: var(--mj-space-2);\n flex-shrink: 0;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n.mj-grid-4[_ngcontent-%COMP%] {\n display: none;\n}\n\n@media (min-width: 768px) {\n .mj-grid-4[_ngcontent-%COMP%] {\n display: grid;\n }\n}\n\n\n\n@media (min-width: 768px) {\n .stat-icon[_ngcontent-%COMP%] {\n width: 48px;\n height: 48px;\n font-size: 1.25rem;\n }\n}\n\n\n\n.stat-icon-total[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-accent) 25%, transparent);\n color: var(--mj-brand-primary);\n}\n\n.stat-icon-inactive[_ngcontent-%COMP%] {\n background: var(--mj-color-error-100);\n color: var(--mj-status-error);\n}\n\n.stat-icon-admin[_ngcontent-%COMP%] {\n background: var(--mj-color-warning-50);\n color: var(--mj-color-warning-700);\n}\n\n\n\n\n\n.bulk-action-toolbar[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n padding: 0.75rem 1rem;\n background: var(--mj-brand-accent-subtle);\n border-bottom: 1px solid var(--mj-border-default);\n animation: slideDown 0.2s ease;\n}\n\n@media (min-width: 768px) {\n .bulk-action-toolbar[_ngcontent-%COMP%] {\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n padding: 1rem 1.5rem;\n }\n}\n\n.bulk-selection-info[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n font-size: 0.875rem;\n font-weight: 600;\n color: var(--mj-brand-primary);\n}\n\n.bulk-selection-info[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 1.25rem;\n}\n\n.bulk-action-buttons[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.5rem;\n flex-wrap: wrap;\n}\n\n@media (max-width: 639px) {\n .bulk-action-buttons[_ngcontent-%COMP%] .btn-text[_ngcontent-%COMP%] {\n display: none;\n }\n\n .bulk-action-buttons[_ngcontent-%COMP%] .mj-btn-sm[_ngcontent-%COMP%] {\n padding: 0.5rem;\n min-width: 36px;\n }\n}\n\n\n\n\n\n.users-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n}\n\n.list-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.75rem 1rem;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-md);\n border: 1px solid var(--mj-border-default);\n margin-bottom: 0.5rem;\n}\n\n.select-all-label[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n cursor: pointer;\n font-size: 0.875rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.select-all-text[_ngcontent-%COMP%] {\n font-weight: 500;\n}\n\n.selection-count[_ngcontent-%COMP%] {\n font-size: 0.75rem;\n font-weight: 600;\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-accent) 25%, transparent);\n padding: 0.25rem 0.75rem;\n border-radius: var(--mj-radius-full);\n}\n\n.user-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-xl);\n overflow: hidden;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.user-card[_ngcontent-%COMP%]:hover {\n box-shadow: var(--mj-shadow-md);\n border-color: var(--mj-brand-primary);\n}\n\n.user-card.expanded[_ngcontent-%COMP%] {\n box-shadow: var(--mj-shadow-lg);\n border-color: var(--mj-brand-primary);\n}\n\n.user-card.selected[_ngcontent-%COMP%] {\n background: var(--mj-brand-accent-subtle);\n border-color: var(--mj-brand-primary);\n}\n\n.user-card.selected[_ngcontent-%COMP%] .user-header[_ngcontent-%COMP%] {\n background: transparent;\n}\n\n.user-card.selected[_ngcontent-%COMP%]:hover .user-header[_ngcontent-%COMP%] {\n background: rgba(0, 118, 182, 0.08);\n}\n\n.user-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 1.25rem 1.5rem;\n cursor: pointer;\n background: var(--mj-bg-surface);\n transition: background-color 0.2s ease;\n}\n\n.user-header[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n@media (max-width: 639px) {\n .user-header[_ngcontent-%COMP%] {\n padding: 0.875rem 1rem;\n gap: 0.625rem;\n }\n}\n\n.user-selection[_ngcontent-%COMP%] {\n flex-shrink: 0;\n}\n\n.checkbox[_ngcontent-%COMP%] {\n width: 20px;\n height: 20px;\n cursor: pointer;\n accent-color: var(--mj-brand-primary);\n}\n\n.user-info[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n flex: 1;\n min-width: 0;\n}\n\n.user-avatar[_ngcontent-%COMP%] {\n width: 48px;\n height: 48px;\n border-radius: var(--mj-radius-full);\n background: linear-gradient(135deg, var(--mj-brand-primary) 0%, var(--mj-brand-primary-light) 100%);\n color: var(--mj-brand-on-primary);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 0.875rem;\n font-weight: 600;\n flex-shrink: 0;\n}\n\n@media (max-width: 639px) {\n .user-avatar[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n font-size: 0.8125rem;\n }\n\n .user-details[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n }\n\n .user-name[_ngcontent-%COMP%] {\n font-size: 0.9375rem;\n font-weight: 600;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .user-email[_ngcontent-%COMP%] {\n font-size: 0.8125rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n}\n\n.user-details[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.user-name[_ngcontent-%COMP%] {\n font-size: 1rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.user-email[_ngcontent-%COMP%] {\n font-size: 0.875rem;\n color: var(--mj-text-secondary);\n margin: 0.125rem 0 0 0;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.user-meta[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n flex-shrink: 0;\n}\n\n@media (max-width: 767px) {\n .user-meta[_ngcontent-%COMP%] .status-badge[_ngcontent-%COMP%], \n .user-meta[_ngcontent-%COMP%] .user-actions[_ngcontent-%COMP%] {\n display: none !important;\n }\n\n .user-meta[_ngcontent-%COMP%] {\n gap: 0;\n }\n}\n\n.desktop-only[_ngcontent-%COMP%] {\n display: none;\n}\n\n@media (min-width: 768px) {\n .desktop-only[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.25rem;\n }\n}\n\n.user-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.25rem;\n}\n\n.user-card.expanded[_ngcontent-%COMP%] .expand-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n transform: rotate(180deg);\n}\n\n\n\n.user-content[_ngcontent-%COMP%] {\n padding: 1.25rem 1.5rem;\n background: var(--mj-bg-page);\n border-top: 1px solid var(--mj-border-default);\n animation: slideDown 0.3s cubic-bezier(0, 0, 0.2, 1);\n}\n\n\n\n.mobile-actions-bar[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding-bottom: 1rem;\n margin-bottom: 1rem;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n@media (min-width: 768px) {\n .mobile-actions-bar[_ngcontent-%COMP%] {\n display: none;\n }\n}\n\n.mobile-action-buttons[_ngcontent-%COMP%] .btn-label[_ngcontent-%COMP%] {\n margin-left: 0.375rem;\n}\n\n\n\n.user-stats[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n gap: 1rem;\n margin-bottom: 1rem;\n}\n\n.user-stats[_ngcontent-%COMP%] .stat-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n font-size: 0.875rem;\n color: var(--mj-text-secondary);\n}\n\n.user-stats[_ngcontent-%COMP%] .stat-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 0.875rem;\n}\n\n.user-stats[_ngcontent-%COMP%] .stat-label[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n}\n\n.user-stats[_ngcontent-%COMP%] .stat-value[_ngcontent-%COMP%] {\n color: var(--mj-text-primary);\n font-weight: 500;\n display: flex;\n align-items: center;\n gap: 0.25rem;\n}\n\n.user-stats[_ngcontent-%COMP%] .stat-value[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 0.75rem;\n}\n\n\n\n.roles-section[_ngcontent-%COMP%] {\n padding-top: 1rem;\n border-top: 1px solid var(--mj-border-default);\n}\n\n.section-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.625rem;\n font-size: 1rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0 0 0.75rem 0;\n}\n\n.section-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 1.125rem;\n}\n\n.roles-grid[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n gap: 0.5rem;\n}\n\n.role-item[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.375rem 0.875rem;\n background: var(--mj-color-warning-50);\n color: var(--mj-color-warning-800);\n border: 1px solid var(--mj-color-warning-500);\n border-radius: var(--mj-radius-full);\n font-size: 0.75rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.03em;\n}\n\n.role-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 0.625rem;\n}\n\n.no-roles[_ngcontent-%COMP%] {\n font-size: 0.875rem;\n color: var(--mj-text-secondary);\n margin: 0;\n}\n\n\n\n\n\n.error-container[_ngcontent-%COMP%] .retry-button[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n padding: 0.75rem 1.5rem;\n font-size: 0.875rem;\n font-weight: 600;\n border: none;\n border-radius: var(--mj-radius-full);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n box-shadow: var(--mj-shadow-sm);\n min-height: 44px;\n}\n\n.error-container[_ngcontent-%COMP%] .retry-button[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary-light);\n box-shadow: var(--mj-shadow-md);\n}\n\n.error-container[_ngcontent-%COMP%] .retry-button[_ngcontent-%COMP%]:active {\n background: var(--mj-color-brand-400);\n transform: scale(0.98);\n}\n\n\n\n\n\n.form-field[_ngcontent-%COMP%] {\n margin-bottom: 1rem;\n}\n\n.form-field[_ngcontent-%COMP%] .field-label[_ngcontent-%COMP%] {\n display: block;\n font-size: 0.75rem;\n font-weight: 500;\n color: var(--mj-text-primary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin-bottom: 0.5rem;\n}\n\n.form-field[_ngcontent-%COMP%] .field-select[_ngcontent-%COMP%] {\n width: 100%;\n padding: 0.75rem 1rem;\n border: 1px solid var(--mj-color-neutral-400);\n border-radius: var(--mj-radius-md);\n background: var(--mj-bg-page);\n font-size: 1rem;\n color: var(--mj-text-primary);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.form-field[_ngcontent-%COMP%] .field-select[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px rgba(0, 118, 182, 0.2);\n}\n\n\n\n.checkbox[_ngcontent-%COMP%]:focus-visible, \n.user-header[_ngcontent-%COMP%]:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n\n\n\n\n@media (min-width: 1440px) {\n .bulk-action-toolbar[_ngcontent-%COMP%] {\n padding: 1.25rem 2rem;\n }\n\n .mj-grid-4[_ngcontent-%COMP%] {\n gap: 1.5rem;\n padding: 0 2rem 1rem 2rem;\n }\n\n .scrollable-content[_ngcontent-%COMP%] {\n padding: 2rem;\n }\n}\n\n\n\n\n\n@media (max-width: 639px) {\n .mj-grid-4[_ngcontent-%COMP%] {\n grid-template-columns: repeat(2, 1fr);\n gap: 0.5rem;\n padding: 0 0.75rem 0.5rem 0.75rem;\n }\n\n .mj-card[_ngcontent-%COMP%] {\n padding: 0.75rem;\n gap: 0.75rem;\n }\n\n .stat-icon[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n font-size: 1.125rem;\n }\n\n .stat-content[_ngcontent-%COMP%] .stat-value[_ngcontent-%COMP%] {\n font-size: 1.5rem;\n }\n\n .stat-content[_ngcontent-%COMP%] .stat-label[_ngcontent-%COMP%] {\n font-size: 0.6875rem;\n }\n\n .scrollable-content[_ngcontent-%COMP%] {\n padding: 0.75rem;\n }\n\n .list-header[_ngcontent-%COMP%] {\n padding: 0.625rem 0.75rem;\n }\n\n .empty-state[_ngcontent-%COMP%] {\n padding: 2rem 1rem;\n }\n\n .empty-state[_ngcontent-%COMP%] .empty-icon[_ngcontent-%COMP%] {\n font-size: 3rem;\n }\n\n .empty-state[_ngcontent-%COMP%] .empty-text[_ngcontent-%COMP%] {\n font-size: 1.0625rem;\n }\n\n .empty-state[_ngcontent-%COMP%] .empty-subtext[_ngcontent-%COMP%] {\n font-size: 0.875rem;\n }\n}"] });
|
|
1332
1225
|
};
|
|
1333
1226
|
UserManagementComponent = __decorate([
|
|
1334
1227
|
RegisterClass(BaseDashboard, 'UserManagement')
|
|
@@ -1336,7 +1229,7 @@ UserManagementComponent = __decorate([
|
|
|
1336
1229
|
export { UserManagementComponent };
|
|
1337
1230
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(UserManagementComponent, [{
|
|
1338
1231
|
type: Component,
|
|
1339
|
-
args: [{ standalone: false, selector: 'mj-user-management', template: "<div class=\"user-management-container\">\n <!-- Sticky Header Section -->\n <div class=\"sticky-header\">\n <!-- Action Buttons -->\n <div class=\"action-buttons\" role=\"toolbar\" aria-label=\"User management actions\">\n <button\n mjButton variant=\"secondary\" class=\"mj-btn-icon-mobile\"\n (click)=\"refreshData()\"\n [disabled]=\"isLoading\"\n aria-label=\"Refresh user list\"\n >\n <i class=\"fa-solid fa-refresh\" [class.fa-spin]=\"isLoading\" aria-hidden=\"true\"></i>\n <span class=\"btn-text\">Refresh</span>\n </button>\n <button\n mjButton variant=\"secondary\" class=\"mj-btn-icon-mobile\"\n (click)=\"exportUsers()\"\n aria-label=\"Export users to file\"\n >\n <i class=\"fa-solid fa-download\" aria-hidden=\"true\"></i>\n <span class=\"btn-text\">Export</span>\n </button>\n <button\n mjButton variant=\"primary\" class=\"mj-btn-icon-mobile\"\n (click)=\"createNewUser()\"\n aria-label=\"Add new user\"\n >\n <i class=\"fa-solid fa-plus\" aria-hidden=\"true\"></i>\n <span class=\"btn-text\">Add User</span>\n </button>\n </div>\n\n <!-- Bulk Action Toolbar -->\n @if (hasSelection) {\n <div class=\"bulk-action-toolbar\" role=\"toolbar\" aria-label=\"Bulk actions\">\n <div class=\"bulk-selection-info\">\n <i class=\"fa-solid fa-check-square\" aria-hidden=\"true\"></i>\n <span>{{ selectedCount }} user{{ selectedCount > 1 ? 's' : '' }} selected</span>\n <button\n mjButton variant=\"flat\" size=\"sm\"\n (click)=\"clearSelection()\"\n aria-label=\"Clear selection\"\n >\n <i class=\"fa-solid fa-times\" aria-hidden=\"true\"></i>\n Clear\n </button>\n </div>\n <div class=\"bulk-action-buttons\">\n <button\n mjButton variant=\"secondary\" size=\"sm\"\n (click)=\"confirmBulkAction('enable')\"\n aria-label=\"Enable selected users\"\n >\n <i class=\"fa-solid fa-toggle-on\" aria-hidden=\"true\"></i>\n <span class=\"btn-text\">Enable</span>\n </button>\n <button\n mjButton variant=\"secondary\" size=\"sm\"\n (click)=\"confirmBulkAction('disable')\"\n aria-label=\"Disable selected users\"\n >\n <i class=\"fa-solid fa-toggle-off\" aria-hidden=\"true\"></i>\n <span class=\"btn-text\">Disable</span>\n </button>\n <button\n mjButton variant=\"secondary\" size=\"sm\"\n (click)=\"openBulkRoleAssign()\"\n aria-label=\"Assign role to selected users\"\n >\n <i class=\"fa-solid fa-user-tag\" aria-hidden=\"true\"></i>\n <span class=\"btn-text\">Assign Role</span>\n </button>\n <button\n mjButton variant=\"danger\" size=\"sm\"\n (click)=\"confirmBulkAction('delete')\"\n aria-label=\"Delete selected users\"\n >\n <i class=\"fa-solid fa-trash\" aria-hidden=\"true\"></i>\n <span class=\"btn-text\">Delete</span>\n </button>\n </div>\n </div>\n }\n\n <!-- Stats Cards -->\n <div class=\"mj-grid-4\" role=\"region\" aria-label=\"User statistics\">\n <div class=\"mj-card\">\n <div class=\"stat-icon stat-icon-total\" aria-hidden=\"true\">\n <i class=\"fa-solid fa-users\"></i>\n </div>\n <div class=\"stat-content\">\n <div class=\"stat-value\" aria-label=\"Total users count\">{{ stats.totalUsers }}</div>\n <div class=\"stat-label\">Total Users</div>\n </div>\n </div>\n\n <div class=\"mj-card\">\n <div class=\"stat-icon stat-icon-active\" aria-hidden=\"true\">\n <i class=\"fa-solid fa-user-check\"></i>\n </div>\n <div class=\"stat-content\">\n <div class=\"stat-value\" aria-label=\"Active users count\">{{ stats.activeUsers }}</div>\n <div class=\"stat-label\">Active Users</div>\n </div>\n </div>\n\n <div class=\"mj-card\">\n <div class=\"stat-icon stat-icon-inactive\" aria-hidden=\"true\">\n <i class=\"fa-solid fa-user-xmark\"></i>\n </div>\n <div class=\"stat-content\">\n <div class=\"stat-value\" aria-label=\"Inactive users count\">{{ stats.inactiveUsers }}</div>\n <div class=\"stat-label\">Inactive Users</div>\n </div>\n </div>\n\n <div class=\"mj-card\">\n <div class=\"stat-icon stat-icon-admin\" aria-hidden=\"true\">\n <i class=\"fa-solid fa-shield-halved\"></i>\n </div>\n <div class=\"stat-content\">\n <div class=\"stat-value\" aria-label=\"Owner users count\">{{ stats.adminUsers }}</div>\n <div class=\"stat-label\">Owners</div>\n </div>\n </div>\n </div>\n\n <!-- Filters Section -->\n <div class=\"filters-section\" role=\"search\" aria-label=\"Filter users\">\n <div class=\"filters-row\">\n <!-- Search -->\n <div class=\"mj-search\">\n <i class=\"fa-solid fa-search mj-search-icon\" aria-hidden=\"true\"></i>\n <input\n type=\"text\"\n class=\"mj-search-input\"\n placeholder=\"Search users by name or email...\"\n (input)=\"onSearchChange($event)\"\n [value]=\"filters$.value.search\"\n aria-label=\"Search users by name or email\"\n />\n </div>\n\n <!-- Mobile: Filter Toggle Button -->\n <button\n class=\"mobile-filter-toggle\"\n (click)=\"showMobileFilters = !showMobileFilters\"\n [class.active]=\"showMobileFilters\"\n [attr.aria-expanded]=\"showMobileFilters\"\n aria-label=\"Toggle filters\"\n >\n <i class=\"fa-solid fa-filter\" aria-hidden=\"true\"></i>\n @if (hasActiveFilters) {\n <span class=\"filter-badge\">{{ activeFilterCount }}</span>\n }\n </button>\n\n <!-- Desktop: Status Filter - Button group -->\n <div class=\"mj-filter-group desktop-filter-group\">\n <label class=\"mj-filter-label\" id=\"status-filter-label\">Status</label>\n <div class=\"mj-filter-buttons\" role=\"group\" aria-labelledby=\"status-filter-label\">\n <button mjButton\n [variant]=\"filters$.value.status === 'all' ? 'primary' : 'flat'\"\n (click)=\"onStatusFilterChange('all')\"\n [attr.aria-pressed]=\"filters$.value.status === 'all'\"\n >\n All\n </button>\n <button mjButton\n [variant]=\"filters$.value.status === 'active' ? 'primary' : 'flat'\"\n (click)=\"onStatusFilterChange('active')\"\n [attr.aria-pressed]=\"filters$.value.status === 'active'\"\n >\n Active\n </button>\n <button mjButton\n [variant]=\"filters$.value.status === 'inactive' ? 'primary' : 'flat'\"\n (click)=\"onStatusFilterChange('inactive')\"\n [attr.aria-pressed]=\"filters$.value.status === 'inactive'\"\n >\n Inactive\n </button>\n </div>\n </div>\n\n <!-- Desktop: Role Filter -->\n <div class=\"mj-filter-group desktop-filter-group\">\n <label class=\"mj-filter-label\" for=\"role-filter\">Role</label>\n <select\n id=\"role-filter\"\n class=\"mj-filter-select\"\n (change)=\"onRoleFilterChange($any($event.target).value)\"\n aria-label=\"Filter by role\"\n >\n <option value=\"\">All Roles</option>\n @for (role of roles; track role.ID) {\n <option [value]=\"role.ID\">{{ role.Name }}</option>\n }\n </select>\n </div>\n </div>\n\n <!-- Mobile: Filter Dropdown Panel -->\n @if (showMobileFilters) {\n <div class=\"mobile-filter-dropdown\">\n <div class=\"mobile-filter-content\">\n <!-- Status Filter -->\n <div class=\"mj-filter-group\">\n <label class=\"mj-filter-label\" id=\"status-filter-label-mobile\">Status</label>\n <select\n class=\"mj-filter-select\"\n [value]=\"filters$.value.status\"\n (change)=\"onStatusFilterChange($any($event.target).value)\"\n aria-labelledby=\"status-filter-label-mobile\"\n >\n <option value=\"all\">All Status</option>\n <option value=\"active\">Active</option>\n <option value=\"inactive\">Inactive</option>\n </select>\n </div>\n\n <!-- Role Filter -->\n <div class=\"mj-filter-group\">\n <label class=\"mj-filter-label\" for=\"role-filter-mobile\">Role</label>\n <select\n id=\"role-filter-mobile\"\n class=\"mj-filter-select\"\n (change)=\"onRoleFilterChange($any($event.target).value)\"\n aria-label=\"Filter by role\"\n >\n <option value=\"\">All Roles</option>\n @for (role of roles; track role.ID) {\n <option [value]=\"role.ID\">{{ role.Name }}</option>\n }\n </select>\n </div>\n\n <!-- Clear Filters Button -->\n @if (hasActiveFilters) {\n <button mjButton variant=\"flat\" size=\"sm\" class=\"clear-filters-btn\" (click)=\"clearFilters()\">\n <i class=\"fa-solid fa-times\" aria-hidden=\"true\"></i>\n Clear Filters\n </button>\n }\n </div>\n </div>\n }\n </div>\n </div><!-- End Sticky Header -->\n\n <!-- Scrollable Content Section -->\n <div class=\"scrollable-content\">\n <!-- Loading State -->\n @if (isLoading) {\n <div class=\"loading-container\" role=\"status\" aria-live=\"polite\" aria-busy=\"true\">\n <mj-loading text=\"Loading users...\" size=\"medium\"></mj-loading>\n </div>\n }\n\n <!-- Error State -->\n @if (error && !isLoading) {\n <div class=\"error-container\" role=\"alert\" aria-live=\"assertive\">\n <div class=\"error-content\">\n <i class=\"fa-solid fa-exclamation-triangle error-icon\" aria-hidden=\"true\"></i>\n <p class=\"error-message\">{{ error }}</p>\n <button class=\"retry-button\" (click)=\"loadInitialData()\" aria-label=\"Retry loading users\">\n <i class=\"fa-solid fa-refresh\" aria-hidden=\"true\"></i>\n Try Again\n </button>\n </div>\n </div>\n }\n\n <!-- Content Area -->\n @if (!isLoading && !error) {\n <div class=\"content-area\">\n <!-- Users List -->\n <div class=\"users-list\" role=\"list\" aria-label=\"Users list\">\n <!-- List Header with Select All -->\n <div class=\"list-header\">\n <label class=\"select-all-label\">\n <input\n type=\"checkbox\"\n class=\"checkbox\"\n [checked]=\"isAllSelected\"\n [indeterminate]=\"isIndeterminate\"\n (change)=\"toggleSelectAll()\"\n aria-label=\"Select all users\"\n />\n <span class=\"select-all-text\">Select All ({{ filteredUsers.length }})</span>\n </label>\n @if (hasSelection) {\n <span class=\"selection-count\">{{ selectedCount }} selected</span>\n }\n </div>\n\n @for (user of filteredUsers; track user.ID) {\n <div\n class=\"user-card\"\n [class.expanded]=\"isUserExpanded(user.ID)\"\n [class.selected]=\"isUserSelected(user.ID)\"\n role=\"listitem\"\n >\n <!-- User Card Header - Always Visible -->\n <div\n class=\"user-header\"\n (click)=\"toggleUserExpansion(user.ID)\"\n role=\"button\"\n [attr.aria-expanded]=\"isUserExpanded(user.ID)\"\n tabindex=\"0\"\n (keydown.enter)=\"toggleUserExpansion(user.ID)\"\n >\n <!-- Selection Checkbox -->\n <div class=\"user-selection\" (click)=\"$event.stopPropagation()\">\n <input\n type=\"checkbox\"\n class=\"checkbox\"\n [checked]=\"isUserSelected(user.ID)\"\n (change)=\"toggleUserSelection(user.ID, $event)\"\n [attr.aria-label]=\"'Select ' + user.Name\"\n />\n </div>\n\n <!-- User Info -->\n <div class=\"user-info\">\n <div class=\"user-avatar\" aria-hidden=\"true\">\n {{ getUserInitials(user) }}\n </div>\n <div class=\"user-details\">\n <h3 class=\"user-name\">{{ user.Name }}</h3>\n <p class=\"user-email\">{{ user.Email }}</p>\n </div>\n </div>\n\n <!-- User Meta -->\n <div class=\"user-meta\">\n <span class=\"status-badge\" [class]=\"getStatusClass(user)\">\n <i [class]=\"'fa-solid ' + getStatusIcon(user)\" aria-hidden=\"true\"></i>\n {{ user.IsActive ? 'Active' : 'Inactive' }}\n </span>\n <div class=\"user-actions desktop-only\" (click)=\"$event.stopPropagation()\">\n <button\n mjButton variant=\"flat\" size=\"sm\"\n (click)=\"editUser(user)\"\n [attr.aria-label]=\"'Edit ' + user.Name\"\n title=\"Edit\"\n >\n <i class=\"fa-solid fa-edit\" aria-hidden=\"true\"></i>\n </button>\n <button\n mjButton variant=\"flat\" size=\"sm\"\n (click)=\"toggleUserStatus(user)\"\n [attr.aria-label]=\"(user.IsActive ? 'Deactivate ' : 'Activate ') + user.Name\"\n [title]=\"user.IsActive ? 'Deactivate' : 'Activate'\"\n >\n <i [class]=\"user.IsActive ? 'fa-solid fa-toggle-on' : 'fa-solid fa-toggle-off'\" aria-hidden=\"true\"></i>\n </button>\n <button\n mjButton variant=\"danger\" size=\"sm\"\n (click)=\"confirmDeleteUser(user)\"\n [attr.aria-label]=\"'Delete ' + user.Name\"\n title=\"Delete\"\n >\n <i class=\"fa-solid fa-trash\" aria-hidden=\"true\"></i>\n </button>\n </div>\n <button class=\"expand-btn\" aria-label=\"Toggle user details\">\n <i class=\"fa-solid fa-chevron-down\" aria-hidden=\"true\"></i>\n </button>\n </div>\n </div>\n\n <!-- User Card Content - Expanded -->\n @if (isUserExpanded(user.ID)) {\n <div class=\"user-content\">\n <!-- Mobile Actions Bar -->\n <div class=\"mobile-actions-bar\" (click)=\"$event.stopPropagation()\">\n <span class=\"status-badge\" [class]=\"getStatusClass(user)\">\n <i [class]=\"'fa-solid ' + getStatusIcon(user)\" aria-hidden=\"true\"></i>\n {{ user.IsActive ? 'Active' : 'Inactive' }}\n </span>\n <div class=\"mobile-action-buttons\">\n <button\n mjButton variant=\"flat\" size=\"sm\"\n (click)=\"editUser(user)\"\n [attr.aria-label]=\"'Edit ' + user.Name\"\n >\n <i class=\"fa-solid fa-edit\" aria-hidden=\"true\"></i>\n <span class=\"btn-label\">Edit</span>\n </button>\n <button\n mjButton variant=\"flat\" size=\"sm\"\n (click)=\"toggleUserStatus(user)\"\n [attr.aria-label]=\"(user.IsActive ? 'Deactivate ' : 'Activate ') + user.Name\"\n >\n <i [class]=\"user.IsActive ? 'fa-solid fa-toggle-on' : 'fa-solid fa-toggle-off'\" aria-hidden=\"true\"></i>\n <span class=\"btn-label\">{{ user.IsActive ? 'Disable' : 'Enable' }}</span>\n </button>\n <button\n mjButton variant=\"danger\" size=\"sm\"\n (click)=\"confirmDeleteUser(user)\"\n [attr.aria-label]=\"'Delete ' + user.Name\"\n >\n <i class=\"fa-solid fa-trash\" aria-hidden=\"true\"></i>\n <span class=\"btn-label\">Delete</span>\n </button>\n </div>\n </div>\n\n <!-- User Stats -->\n <div class=\"user-stats\">\n <div class=\"stat-item\">\n <i class=\"fa-solid fa-user-tag\" aria-hidden=\"true\"></i>\n <span class=\"stat-label\">Type:</span>\n <span class=\"stat-value\">\n <i [class]=\"'fa-solid ' + getUserTypeIcon(user)\" aria-hidden=\"true\"></i>\n {{ user.Type }}\n </span>\n </div>\n <div class=\"stat-item\">\n <i class=\"fa-solid fa-id-card\" aria-hidden=\"true\"></i>\n <span class=\"stat-label\">Full Name:</span>\n <span class=\"stat-value\">{{ user.FirstName }} {{ user.LastName }}</span>\n </div>\n <div class=\"stat-item\">\n <i class=\"fa-solid fa-calendar\" aria-hidden=\"true\"></i>\n <span class=\"stat-label\">Created:</span>\n <span class=\"stat-value\">{{ user.__mj_CreatedAt | date:'short' }}</span>\n </div>\n <div class=\"stat-item\">\n <i class=\"fa-solid fa-clock\" aria-hidden=\"true\"></i>\n <span class=\"stat-label\">Updated:</span>\n <span class=\"stat-value\">{{ user.__mj_UpdatedAt | date:'short' }}</span>\n </div>\n </div>\n\n <!-- User Roles Section -->\n <div class=\"roles-section\">\n <h4 class=\"section-title\">\n <i class=\"fa-solid fa-user-shield\" aria-hidden=\"true\"></i>\n Assigned Roles\n </h4>\n @if (getUserRoles(user.ID).length > 0) {\n <div class=\"roles-grid\">\n @for (role of getUserRoles(user.ID); track role.ID) {\n <div class=\"role-item\">\n <i class=\"fa-solid fa-shield\" aria-hidden=\"true\"></i>\n {{ role.Name }}\n </div>\n }\n </div>\n } @else {\n <p class=\"no-roles\">No roles assigned to this user</p>\n }\n </div>\n </div>\n }\n </div>\n }\n\n @if (filteredUsers.length === 0) {\n <div class=\"empty-state\" role=\"status\">\n <i class=\"fa-solid fa-users-slash empty-icon\" aria-hidden=\"true\"></i>\n <p class=\"empty-text\">No users found</p>\n <p class=\"empty-subtext\">Try adjusting your filters or add a new user</p>\n </div>\n }\n </div>\n </div>\n }\n </div><!-- End Scrollable Content -->\n\n <!-- User Create/Edit Dialog -->\n <mj-user-dialog\n [data]=\"userDialogData\"\n [visible]=\"showUserDialog\"\n (result)=\"onUserDialogResult($event)\">\n </mj-user-dialog>\n\n <!-- Delete Confirmation Dialog -->\n @if (showDeleteConfirm && selectedUser) {\n <div\n class=\"modal-backdrop\"\n (click)=\"showDeleteConfirm = false\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"delete-dialog-title\"\n aria-describedby=\"delete-dialog-desc\"\n >\n <div class=\"modal-dialog\" (click)=\"$event.stopPropagation()\">\n <div class=\"modal-header\">\n <h3 class=\"modal-title\" id=\"delete-dialog-title\">\n <i class=\"fa-solid fa-exclamation-triangle text-danger\" aria-hidden=\"true\"></i>\n Confirm Delete\n </h3>\n <button\n class=\"modal-close\"\n (click)=\"showDeleteConfirm = false\"\n aria-label=\"Close dialog\"\n >\n <i class=\"fa-solid fa-times\" aria-hidden=\"true\"></i>\n </button>\n </div>\n <div class=\"modal-body\" id=\"delete-dialog-desc\">\n <p>Are you sure you want to delete user <strong>{{ selectedUser.Name }}</strong>?</p>\n <p class=\"text-muted\">This action cannot be undone.</p>\n </div>\n <div class=\"modal-footer\">\n <button mjButton variant=\"danger\" (click)=\"deleteUser()\">\n <i class=\"fa-solid fa-trash\" aria-hidden=\"true\"></i>\n Delete User\n </button>\n <button mjButton (click)=\"showDeleteConfirm = false\">\n Cancel\n </button>\n </div>\n </div>\n </div>\n }\n\n <!-- Bulk Action Confirmation Dialog -->\n @if (showBulkActionConfirm) {\n <div\n class=\"modal-backdrop\"\n (click)=\"cancelBulkAction()\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"bulk-action-dialog-title\"\n aria-describedby=\"bulk-action-dialog-desc\"\n >\n <div class=\"modal-dialog\" (click)=\"$event.stopPropagation()\">\n <div class=\"modal-header\">\n <h3 class=\"modal-title\" id=\"bulk-action-dialog-title\">\n @if (bulkActionType === 'delete') {\n <i class=\"fa-solid fa-exclamation-triangle text-danger\" aria-hidden=\"true\"></i>\n } @else if (bulkActionType === 'enable') {\n <i class=\"fa-solid fa-toggle-on text-success\" aria-hidden=\"true\"></i>\n } @else {\n <i class=\"fa-solid fa-toggle-off text-warning\" aria-hidden=\"true\"></i>\n }\n {{ getBulkActionTitle() }}\n </h3>\n <button\n class=\"modal-close\"\n (click)=\"cancelBulkAction()\"\n aria-label=\"Close dialog\"\n >\n <i class=\"fa-solid fa-times\" aria-hidden=\"true\"></i>\n </button>\n </div>\n <div class=\"modal-body\" id=\"bulk-action-dialog-desc\">\n <p>{{ getBulkActionMessage() }}</p>\n @if (bulkActionType === 'delete') {\n <p class=\"text-muted\">This action cannot be undone.</p>\n }\n </div>\n <div class=\"modal-footer\">\n <button mjButton\n [variant]=\"bulkActionType === 'delete' ? 'danger' : 'primary'\"\n (click)=\"executeBulkAction()\"\n [disabled]=\"isLoading\"\n >\n @if (isLoading) {\n <i class=\"fa-solid fa-spinner fa-spin\" aria-hidden=\"true\"></i>\n Processing...\n } @else {\n @if (bulkActionType === 'delete') {\n <i class=\"fa-solid fa-trash\" aria-hidden=\"true\"></i>\n } @else if (bulkActionType === 'enable') {\n <i class=\"fa-solid fa-toggle-on\" aria-hidden=\"true\"></i>\n } @else {\n <i class=\"fa-solid fa-toggle-off\" aria-hidden=\"true\"></i>\n }\n {{ getBulkActionButtonText() }}\n }\n </button>\n <button mjButton (click)=\"cancelBulkAction()\" [disabled]=\"isLoading\">\n Cancel\n </button>\n </div>\n </div>\n </div>\n }\n\n <!-- Bulk Role Assignment Dialog -->\n @if (showBulkRoleAssign) {\n <div\n class=\"modal-backdrop\"\n (click)=\"cancelBulkRoleAssign()\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"bulk-role-dialog-title\"\n aria-describedby=\"bulk-role-dialog-desc\"\n >\n <div class=\"modal-dialog\" (click)=\"$event.stopPropagation()\">\n <div class=\"modal-header\">\n <h3 class=\"modal-title\" id=\"bulk-role-dialog-title\">\n <i class=\"fa-solid fa-user-tag\" aria-hidden=\"true\"></i>\n Assign Role to {{ selectedCount }} User{{ selectedCount > 1 ? 's' : '' }}\n </h3>\n <button\n class=\"modal-close\"\n (click)=\"cancelBulkRoleAssign()\"\n aria-label=\"Close dialog\"\n >\n <i class=\"fa-solid fa-times\" aria-hidden=\"true\"></i>\n </button>\n </div>\n <div class=\"modal-body\" id=\"bulk-role-dialog-desc\">\n <p>Select a role to assign to the selected users:</p>\n <div class=\"form-field\">\n <label class=\"field-label\" for=\"bulk-role-select\">Role</label>\n <select\n id=\"bulk-role-select\"\n class=\"field-select\"\n [(ngModel)]=\"bulkRoleId\"\n aria-label=\"Select role to assign\"\n >\n <option value=\"\">Select a role...</option>\n @for (role of roles; track role.ID) {\n <option [value]=\"role.ID\">{{ role.Name }}</option>\n }\n </select>\n </div>\n </div>\n <div class=\"modal-footer\">\n <button\n mjButton variant=\"primary\"\n (click)=\"executeBulkRoleAssign()\"\n [disabled]=\"!bulkRoleId || isLoading\"\n >\n @if (isLoading) {\n <i class=\"fa-solid fa-spinner fa-spin\" aria-hidden=\"true\"></i>\n Assigning...\n } @else {\n <i class=\"fa-solid fa-user-tag\" aria-hidden=\"true\"></i>\n Assign Role\n }\n </button>\n <button mjButton (click)=\"cancelBulkRoleAssign()\" [disabled]=\"isLoading\">\n Cancel\n </button>\n </div>\n </div>\n </div>\n }\n</div>\n", styles: ["/* =============================================================================\n Shared Admin Patterns - MJ Design System\n Common styles shared across all admin settings components.\n Component-specific CSS files override these values where needed.\n ============================================================================= */\n\n/* -----------------------------------------------------------------------------\n Host & Container\n ----------------------------------------------------------------------------- */\n:host {\n display: flex;\n flex-direction: column;\n height: 100%;\n width: 100%;\n overflow: hidden;\n}\n\n/* -----------------------------------------------------------------------------\n Sticky Header\n ----------------------------------------------------------------------------- */\n.sticky-header {\n flex-shrink: 0;\n background: var(--mj-bg-page);\n border-bottom: 1px solid var(--mj-border-default);\n box-shadow: var(--mj-shadow-sm);\n z-index: 10;\n}\n\n/* -----------------------------------------------------------------------------\n Scrollable Content\n ----------------------------------------------------------------------------- */\n.scrollable-content {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n -webkit-overflow-scrolling: touch;\n padding: 1rem;\n background: var(--mj-bg-surface-sunken);\n}\n\n@media (min-width: 768px) {\n .scrollable-content {\n padding: 1.5rem 2rem;\n }\n}\n\n@media (min-width: 1024px) {\n .scrollable-content {\n padding: 2rem;\n }\n}\n\n@media (min-width: 1440px) {\n .scrollable-content {\n padding: 2rem 2.5rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Action Buttons (In Sticky Header)\n ----------------------------------------------------------------------------- */\n.action-buttons {\n flex-shrink: 0;\n display: flex;\n gap: 0.75rem;\n justify-content: flex-end;\n padding: 0.75rem 1rem;\n background: var(--mj-bg-page);\n}\n\n@media (min-width: 768px) {\n .action-buttons {\n padding: 1rem 1.5rem;\n }\n}\n\n@media (max-width: 639px) {\n .action-buttons {\n justify-content: center;\n flex-wrap: wrap;\n }\n\n .mj-btn-icon-mobile .btn-text {\n display: none;\n }\n\n .mj-btn-icon-mobile {\n padding: 0.5rem 0.75rem;\n min-height: 40px;\n gap: 0;\n border-radius: var(--mj-radius-full);\n }\n\n .mj-btn-icon-mobile i {\n font-size: 1.125rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Statistics Cards Grid - Static Display (Non-interactive)\n ----------------------------------------------------------------------------- */\n.mj-grid-4 {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 0.5rem;\n padding: 0 1rem 0.75rem 1rem;\n background: var(--mj-bg-page);\n}\n\n@media (min-width: 768px) {\n .mj-grid-4 {\n grid-template-columns: repeat(4, 1fr);\n padding: 0 1.5rem 1rem 1.5rem;\n gap: 0.75rem;\n }\n}\n\n@media (min-width: 1024px) {\n .mj-grid-4 {\n gap: 1rem;\n }\n}\n\n/* Static Card - No hover effects */\n.mj-card {\n background: var(--mj-bg-surface-card);\n border-radius: var(--mj-radius-lg);\n padding: 1rem;\n box-shadow: var(--mj-shadow-sm);\n display: flex;\n align-items: center;\n gap: 1rem;\n border: 1px solid var(--mj-border-default);\n cursor: default;\n pointer-events: none;\n}\n\n@media (min-width: 768px) {\n .mj-card {\n padding: 1rem 1.25rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Stat Icon Containers\n ----------------------------------------------------------------------------- */\n.stat-icon {\n width: 48px;\n height: 48px;\n border-radius: var(--mj-radius-lg);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 1.25rem;\n flex-shrink: 0;\n}\n\n@media (min-width: 768px) {\n .stat-icon {\n width: 52px;\n height: 52px;\n font-size: 1.375rem;\n }\n}\n\n.stat-icon-total {\n background: var(--mj-color-accent-300);\n color: var(--mj-brand-primary);\n}\n\n.stat-icon-active {\n background: var(--mj-color-success-100);\n color: var(--mj-status-success);\n}\n\n/* -----------------------------------------------------------------------------\n Stat Content Typography\n ----------------------------------------------------------------------------- */\n.stat-content {\n flex: 1;\n min-width: 0;\n}\n\n.stat-content .stat-value {\n font-size: 1.75rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n line-height: 1;\n letter-spacing: -0.02em;\n}\n\n@media (min-width: 768px) {\n .stat-content .stat-value {\n font-size: 2rem;\n }\n}\n\n.stat-content .stat-label {\n font-size: 0.75rem;\n font-weight: 500;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin-top: 0.25rem;\n}\n\n@media (min-width: 768px) {\n .stat-content .stat-label {\n font-size: 0.8125rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Filters Section\n ----------------------------------------------------------------------------- */\n.filters-section {\n flex-shrink: 0;\n background: var(--mj-bg-surface-card);\n margin: 0 1rem 0.75rem 1rem;\n padding: 0.75rem;\n border-radius: var(--mj-radius-lg);\n border: 1px solid var(--mj-border-default);\n}\n\n@media (min-width: 768px) {\n .filters-section {\n margin: 0 1.5rem 1rem 1.5rem;\n padding: 1rem 1.25rem;\n }\n}\n\n.filters-row {\n display: flex;\n gap: 1rem;\n align-items: flex-end;\n flex-wrap: wrap;\n}\n\n@media (min-width: 768px) {\n .filters-row {\n gap: 1.5rem;\n }\n}\n\n.mj-filter-group {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.mj-filter-label {\n font-size: 0.75rem;\n font-weight: 500;\n color: var(--mj-text-primary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n.mj-filter-buttons {\n display: flex;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-full);\n padding: 4px;\n gap: 2px;\n}\n\n.mj-filter-buttons .mj-btn {\n border-radius: var(--mj-radius-full);\n}\n\n.mj-filter-buttons .mj-btn-primary {\n background-color: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n box-shadow: var(--mj-shadow-sm);\n}\n\n/* -----------------------------------------------------------------------------\n Search Input\n ----------------------------------------------------------------------------- */\n.mj-search {\n position: relative;\n flex: 1;\n min-width: 200px;\n}\n\n@media (min-width: 640px) {\n .mj-search {\n min-width: 280px;\n }\n}\n\n@media (min-width: 1024px) {\n .mj-search {\n min-width: 400px;\n max-width: 600px;\n }\n}\n\n@media (min-width: 1440px) {\n .mj-search {\n min-width: 500px;\n max-width: 800px;\n }\n}\n\n.mj-search .mj-search-icon {\n position: absolute;\n left: 1rem;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-secondary);\n font-size: 1rem;\n pointer-events: none;\n transition: color 0.2s ease;\n}\n\n@media (min-width: 1024px) {\n .mj-search .mj-search-icon {\n left: 1.25rem;\n font-size: 1.125rem;\n }\n}\n\n.mj-search .mj-search-input {\n width: 100%;\n padding: 0.875rem 1rem 0.875rem 2.75rem;\n border: 2px solid var(--mj-border-default);\n border-radius: var(--mj-radius-full);\n font-size: 1rem;\n background: var(--mj-bg-page);\n color: var(--mj-text-primary);\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 44px;\n}\n\n@media (min-width: 1024px) {\n .mj-search .mj-search-input {\n padding: 1rem 1.25rem 1rem 3.25rem;\n font-size: 1.0625rem;\n }\n}\n\n@media (min-width: 1440px) {\n .mj-search .mj-search-input {\n padding: 1.125rem 1.5rem 1.125rem 3.5rem;\n }\n}\n\n.mj-search .mj-search-input::placeholder {\n color: var(--mj-text-secondary);\n}\n\n.mj-search .mj-search-input:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n}\n\n.mj-search .mj-search-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px rgba(0, 118, 182, 0.2);\n background: var(--mj-bg-page);\n}\n\n.mj-search:focus-within .mj-search-icon {\n color: var(--mj-brand-primary);\n}\n\n/* -----------------------------------------------------------------------------\n Content Area\n ----------------------------------------------------------------------------- */\n.content-area {\n flex: 1 1 auto;\n overflow: visible;\n position: relative;\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-xl);\n box-shadow: var(--mj-shadow-sm);\n padding: 1rem;\n border: 1px solid var(--mj-border-default);\n}\n\n@media (min-width: 768px) {\n .content-area {\n padding: 1.5rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Expand Button\n ----------------------------------------------------------------------------- */\n.expand-btn {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 1rem;\n cursor: pointer;\n transition: all 0.2s ease;\n border-radius: var(--mj-radius-full);\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.expand-btn:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.expand-btn i {\n transition: transform 0.3s cubic-bezier(0, 0, 0.2, 1);\n}\n\n/* -----------------------------------------------------------------------------\n Status Badge\n ----------------------------------------------------------------------------- */\n.status-badge {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.375rem 0.875rem;\n border-radius: var(--mj-radius-full);\n font-size: 0.75rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.03em;\n}\n\n.status-badge.status-active {\n background: var(--mj-color-success-100);\n color: var(--mj-color-success-800);\n border: 1px solid var(--mj-status-success);\n}\n\n.status-badge.status-inactive {\n background: var(--mj-color-error-100);\n color: var(--mj-status-error);\n border: 1px solid var(--mj-status-error);\n}\n\n.status-badge i {\n font-size: 0.625rem;\n}\n\n/* -----------------------------------------------------------------------------\n Mobile Actions Bar\n ----------------------------------------------------------------------------- */\n.mobile-actions-bar {\n display: none;\n}\n\n.mobile-action-buttons {\n display: flex;\n gap: 0.5rem;\n}\n\n/* -----------------------------------------------------------------------------\n Empty State\n ----------------------------------------------------------------------------- */\n.empty-state {\n text-align: center;\n padding: 4rem 2rem;\n}\n\n.empty-state .empty-icon {\n font-size: 4rem;\n color: var(--mj-border-default);\n margin-bottom: 1.5rem;\n}\n\n.empty-state .empty-text {\n font-size: 1.25rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0 0 0.5rem 0;\n}\n\n.empty-state .empty-subtext {\n font-size: 1rem;\n color: var(--mj-text-secondary);\n margin: 0;\n}\n\n/* -----------------------------------------------------------------------------\n Loading State\n ----------------------------------------------------------------------------- */\n.loading-container {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 4rem 2rem;\n}\n\n/* -----------------------------------------------------------------------------\n Error State\n ----------------------------------------------------------------------------- */\n.error-container {\n text-align: center;\n padding: 4rem 2rem;\n}\n\n.error-container .error-content {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 1rem;\n}\n\n.error-container .error-icon {\n font-size: 3.5rem;\n color: var(--mj-status-error);\n margin-bottom: 1rem;\n}\n\n.error-container .error-message {\n font-size: 1.0625rem;\n color: var(--mj-text-primary);\n margin: 0 0 1.5rem 0;\n}\n\n/* -----------------------------------------------------------------------------\n Modal Dialog\n ----------------------------------------------------------------------------- */\n.modal-backdrop {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.4);\n backdrop-filter: blur(4px);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n padding: 1rem;\n animation: fadeIn 0.2s cubic-bezier(0, 0, 0.2, 1);\n}\n\n.modal-dialog {\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-2xl);\n box-shadow: var(--mj-shadow-2xl);\n max-width: 500px;\n width: 100%;\n max-height: 90vh;\n overflow: hidden;\n animation: slideUp 0.3s cubic-bezier(0, 0, 0.2, 1);\n}\n\n.modal-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 1.5rem;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.modal-header .modal-title {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n font-size: 1.375rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0;\n}\n\n.modal-header .modal-close {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 1.25rem;\n cursor: pointer;\n border-radius: var(--mj-radius-full);\n transition: all 0.2s ease;\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.modal-header .modal-close:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.modal-body {\n padding: 1.5rem;\n}\n\n.modal-body p {\n font-size: 1rem;\n color: var(--mj-text-primary);\n margin: 0 0 1rem 0;\n line-height: 1.5;\n}\n\n.modal-body p:last-child {\n margin-bottom: 0;\n}\n\n.modal-footer {\n display: flex;\n justify-content: flex-start;\n gap: 0.75rem;\n padding: 1.5rem;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n}\n\n@media (max-width: 639px) {\n .modal-dialog {\n width: 95%;\n max-height: 85vh;\n }\n\n .modal-header {\n padding: 1rem;\n }\n\n .modal-header .modal-title {\n font-size: 1.125rem;\n }\n\n .modal-body {\n padding: 1rem;\n }\n\n .modal-footer {\n padding: 1rem;\n flex-direction: column;\n }\n\n .modal-footer .mj-btn {\n width: 100%;\n justify-content: center;\n }\n}\n\n/* -----------------------------------------------------------------------------\n MJ Button System\n ----------------------------------------------------------------------------- */\n.mj-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n padding: 0.75rem 1.5rem;\n font-size: 0.875rem;\n font-weight: 600;\n border: none;\n border-radius: var(--mj-radius-full);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n white-space: nowrap;\n min-height: 44px;\n}\n\n.mj-btn:disabled {\n opacity: 0.38;\n cursor: not-allowed;\n}\n\n/* Primary Button */\n.mj-btn-primary {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n box-shadow: var(--mj-shadow-sm);\n}\n\n.mj-btn-primary:hover:not(:disabled) {\n background: var(--mj-brand-primary-light);\n box-shadow: var(--mj-shadow-md);\n}\n\n.mj-btn-primary:active:not(:disabled) {\n background: var(--mj-color-brand-400);\n transform: scale(0.98);\n}\n\n/* Secondary Button */\n.mj-btn-secondary {\n background: var(--mj-bg-page);\n color: var(--mj-brand-primary);\n border: 1px solid var(--mj-color-neutral-400);\n}\n\n.mj-btn-secondary:hover:not(:disabled) {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.mj-btn-secondary:active:not(:disabled) {\n background: var(--mj-color-brand-700);\n border-color: var(--mj-color-brand-700);\n}\n\n/* Ghost Button */\n.mj-btn-ghost {\n background: transparent;\n color: var(--mj-text-secondary);\n}\n\n.mj-btn-ghost:hover:not(:disabled) {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.mj-btn-ghost:active:not(:disabled) {\n background: var(--mj-color-brand-700);\n}\n\n/* Danger Button */\n.mj-btn-danger {\n background: var(--mj-status-error);\n color: var(--mj-text-inverse);\n box-shadow: var(--mj-shadow-sm);\n}\n\n.mj-btn-danger:hover:not(:disabled) {\n background: var(--mj-color-error-300);\n box-shadow: var(--mj-shadow-md);\n}\n\n.mj-btn-danger:active:not(:disabled) {\n background: var(--mj-color-error-200);\n transform: scale(0.98);\n}\n\n/* Small Button */\n.mj-btn-sm {\n padding: 0.5rem 0.875rem;\n font-size: 0.8125rem;\n min-height: 36px;\n}\n\n/* Icon-only Button */\n.mj-btn-icon-only {\n padding: 0.625rem;\n min-width: 44px;\n min-height: 44px;\n}\n\n/* Icon-mobile Button (text hidden on small screens) */\n.mj-btn-icon-mobile {\n gap: 0.5rem;\n}\n\n.mj-btn-icon-mobile .btn-text {\n display: inline;\n}\n\n/* Ghost Danger Button */\n.mj-btn-ghost.mj-btn-danger {\n background: transparent;\n color: var(--mj-status-error);\n box-shadow: none;\n}\n\n.mj-btn-ghost.mj-btn-danger:hover:not(:disabled) {\n background: var(--mj-color-error-100);\n color: var(--mj-status-error);\n}\n\n/* -----------------------------------------------------------------------------\n Filter Button (Mobile Only)\n ----------------------------------------------------------------------------- */\n.filter-button {\n display: none;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n padding: 0.75rem 1.25rem;\n border: 2px solid var(--mj-border-default);\n background: var(--mj-bg-page);\n color: var(--mj-text-primary);\n border-radius: var(--mj-radius-full);\n font-size: 0.875rem;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 44px;\n min-width: 44px;\n}\n\n.filter-button:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n}\n\n.filter-button:active {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.filter-button i {\n font-size: 1rem;\n}\n\n/* -----------------------------------------------------------------------------\n Filter Modal (Mobile Bottom Sheet)\n ----------------------------------------------------------------------------- */\n.filter-modal-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.4);\n backdrop-filter: blur(4px);\n display: flex;\n align-items: flex-end;\n justify-content: center;\n z-index: 1000;\n animation: fadeIn 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n padding: 0;\n}\n\n.filter-modal {\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-2xl) var(--mj-radius-2xl) 0 0;\n box-shadow: var(--mj-shadow-2xl);\n width: 100%;\n max-height: 80vh;\n overflow: hidden;\n animation: slideUpFromBottom 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n display: flex;\n flex-direction: column;\n}\n\n.filter-modal-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 1.25rem 1.5rem;\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.filter-modal-title {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n font-size: 1.25rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0;\n}\n\n.filter-modal-title i {\n color: var(--mj-brand-primary);\n font-size: 1.375rem;\n}\n\n.filter-modal-close {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 1.25rem;\n cursor: pointer;\n border-radius: var(--mj-radius-full);\n transition: all 0.2s ease;\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.filter-modal-close:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.filter-modal-body {\n padding: 1.5rem;\n overflow-y: auto;\n -webkit-overflow-scrolling: touch;\n flex: 1;\n}\n\n.filter-modal-footer {\n display: flex;\n gap: 0.75rem;\n padding: 1.25rem 1.5rem;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n flex-shrink: 0;\n}\n\n.filter-modal-footer button {\n flex: 1;\n margin: 0;\n}\n\n/* Filter Options Container (Inside Modal) */\n.filter-options-container {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n.filter-group {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n}\n\n.filter-group-label {\n font-size: 0.875rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin: 0;\n}\n\n.filter-group-options {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.filter-option {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 0.875rem 1rem;\n background: var(--mj-bg-surface-sunken);\n border: 2px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 56px;\n}\n\n.filter-option:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface-sunken);\n}\n\n.filter-option.selected {\n background: var(--mj-color-accent-300);\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.filter-option input[type=\"checkbox\"],\n.filter-option input[type=\"radio\"] {\n width: 20px;\n height: 20px;\n cursor: pointer;\n accent-color: var(--mj-brand-primary);\n flex-shrink: 0;\n}\n\n.filter-option-label {\n flex: 1;\n font-size: 1rem;\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.filter-option.selected .filter-option-label {\n color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n/* -----------------------------------------------------------------------------\n Utility Classes\n ----------------------------------------------------------------------------- */\n.text-danger {\n color: var(--mj-status-error);\n}\n\n.text-warning {\n color: var(--mj-color-warning-500);\n}\n\n.text-success {\n color: var(--mj-status-success);\n}\n\n/* -----------------------------------------------------------------------------\n Animations\n ----------------------------------------------------------------------------- */\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n@keyframes slideUp {\n from {\n transform: translateY(20px);\n opacity: 0;\n }\n to {\n transform: translateY(0);\n opacity: 1;\n }\n}\n\n@keyframes slideDown {\n from {\n opacity: 0;\n transform: translateY(-10px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes slideUpFromBottom {\n from {\n transform: translateY(100%);\n opacity: 0;\n }\n to {\n transform: translateY(0);\n opacity: 1;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Accessibility: Focus Indicators\n ----------------------------------------------------------------------------- */\n.mj-search-input:focus-visible,\nbutton:focus-visible,\n.mj-btn:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n/* -----------------------------------------------------------------------------\n Accessibility: Reduced Motion\n ----------------------------------------------------------------------------- */\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 User Management Component - Component-Specific Styles\n Shared patterns are in ../shared/styles/_admin-patterns.css\n ============================================================================= */\n\n/* -----------------------------------------------------------------------------\n Container\n ----------------------------------------------------------------------------- */\n.user-management-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n position: relative;\n width: 100%;\n background: var(--mj-bg-page);\n}\n\n/* -----------------------------------------------------------------------------\n Stats Grid Override - Hidden until 768px (unlike other admin components)\n ----------------------------------------------------------------------------- */\n.mj-grid-4 {\n display: none;\n}\n\n@media (min-width: 768px) {\n .mj-grid-4 {\n display: grid;\n }\n}\n\n/* Stat Icon Override - Stays 48px at 768px (others go to 52px) */\n@media (min-width: 768px) {\n .stat-icon {\n width: 48px;\n height: 48px;\n font-size: 1.25rem;\n }\n}\n\n/* Stat Icon Override - color-mix background instead of accent-300 */\n.stat-icon-total {\n background: color-mix(in srgb, var(--mj-brand-accent) 25%, transparent);\n color: var(--mj-brand-primary);\n}\n\n.stat-icon-inactive {\n background: var(--mj-color-error-100);\n color: var(--mj-status-error);\n}\n\n.stat-icon-admin {\n background: var(--mj-color-warning-50);\n color: var(--mj-color-warning-700);\n}\n\n/* -----------------------------------------------------------------------------\n User-specific Filters: Search + Mobile Filter Toggle/Dropdown\n ----------------------------------------------------------------------------- */\n@media (max-width: 767px) {\n .filters-section {\n padding: 0.75rem;\n }\n\n .filters-row {\n display: flex;\n flex-direction: row;\n gap: 0.75rem;\n align-items: center;\n }\n\n .filters-row .mj-search {\n flex: 1;\n min-width: 0;\n }\n}\n\n@media (max-width: 767px) {\n .mj-search {\n width: 100%;\n max-width: none;\n min-width: 0;\n }\n}\n\n/* Search input overrides for user-mgmt at 768px */\n@media (min-width: 768px) {\n .mj-search {\n min-width: 320px;\n max-width: 600px;\n }\n\n .mj-search .mj-search-input {\n padding: 1rem 1.25rem 1rem 3rem;\n min-height: 52px;\n font-size: 1.0625rem;\n }\n\n .mj-search .mj-search-icon {\n left: 1.125rem;\n font-size: 1.125rem;\n }\n}\n\n/* Mobile Filter Toggle Button */\n.mobile-filter-toggle {\n display: none;\n align-items: center;\n justify-content: center;\n position: relative;\n width: 48px;\n height: 48px;\n min-width: 48px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n font-size: 1.125rem;\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n box-shadow: var(--mj-shadow-sm);\n flex-shrink: 0;\n}\n\n.mobile-filter-toggle:hover {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.mobile-filter-toggle.active {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.filter-badge {\n position: absolute;\n top: -4px;\n right: -4px;\n min-width: 18px;\n height: 18px;\n padding: 0 5px;\n border-radius: var(--mj-radius-full);\n background: var(--mj-status-error);\n color: var(--mj-text-inverse);\n font-size: 0.6875rem;\n font-weight: 700;\n display: flex;\n align-items: center;\n justify-content: center;\n line-height: 1;\n}\n\n/* Mobile Filter Dropdown Panel */\n.mobile-filter-dropdown {\n display: none;\n margin-top: 0.75rem;\n padding-top: 0.75rem;\n border-top: 1px solid var(--mj-border-default);\n animation: slideDown 0.2s ease;\n}\n\n@media (max-width: 767px) {\n .mobile-filter-toggle {\n display: flex !important;\n }\n\n .mobile-filter-dropdown {\n display: block;\n }\n\n .desktop-filter-group {\n display: none !important;\n }\n}\n\n.mobile-filter-content {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n}\n\n.mobile-filter-content .mj-filter-group {\n width: 100%;\n}\n\n.mobile-filter-content .mj-filter-select {\n width: 100%;\n}\n\n.clear-filters-btn {\n align-self: flex-start;\n margin-top: 0.25rem;\n}\n\n/* Desktop filter groups visibility */\n.desktop-filter-group {\n display: none !important;\n}\n\n@media screen and (min-width: 768px) {\n .desktop-filter-group {\n display: flex !important;\n flex-direction: column;\n gap: 0.375rem;\n }\n\n .mobile-filter-toggle {\n display: none !important;\n }\n\n .mobile-filter-dropdown {\n display: none !important;\n }\n}\n\n@media (max-width: 767px) {\n .mj-filter-group {\n flex: 1;\n min-width: 100px;\n }\n}\n\n.mj-filter-select {\n padding: 0.625rem 1rem;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n background: var(--mj-bg-surface-sunken);\n font-size: 0.875rem;\n font-weight: 500;\n color: var(--mj-text-primary);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-width: 120px;\n box-shadow: var(--mj-shadow-sm);\n}\n\n.mj-filter-select:hover {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-brand-primary);\n}\n\n@media (max-width: 767px) {\n .mj-filter-select {\n width: 100%;\n padding: 0.5rem 0.75rem;\n font-size: 0.8125rem;\n }\n}\n\n.mj-filter-select:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px rgba(0, 118, 182, 0.2);\n}\n\n/* -----------------------------------------------------------------------------\n Bulk Action Toolbar (Unique to user-management)\n ----------------------------------------------------------------------------- */\n.bulk-action-toolbar {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n padding: 0.75rem 1rem;\n background: var(--mj-brand-accent-subtle);\n border-bottom: 1px solid var(--mj-border-default);\n animation: slideDown 0.2s ease;\n}\n\n@media (min-width: 768px) {\n .bulk-action-toolbar {\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n padding: 1rem 1.5rem;\n }\n}\n\n.bulk-selection-info {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n font-size: 0.875rem;\n font-weight: 600;\n color: var(--mj-brand-primary);\n}\n\n.bulk-selection-info i {\n font-size: 1.25rem;\n}\n\n.bulk-action-buttons {\n display: flex;\n gap: 0.5rem;\n flex-wrap: wrap;\n}\n\n@media (max-width: 639px) {\n .bulk-action-buttons .btn-text {\n display: none;\n }\n\n .bulk-action-buttons .mj-btn-sm {\n padding: 0.5rem;\n min-width: 36px;\n }\n}\n\n/* -----------------------------------------------------------------------------\n User Card - Interactive\n ----------------------------------------------------------------------------- */\n.users-list {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n}\n\n.list-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.75rem 1rem;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-md);\n border: 1px solid var(--mj-border-default);\n margin-bottom: 0.5rem;\n}\n\n.select-all-label {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n cursor: pointer;\n font-size: 0.875rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.select-all-text {\n font-weight: 500;\n}\n\n.selection-count {\n font-size: 0.75rem;\n font-weight: 600;\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-accent) 25%, transparent);\n padding: 0.25rem 0.75rem;\n border-radius: var(--mj-radius-full);\n}\n\n.user-card {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-xl);\n overflow: hidden;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.user-card:hover {\n box-shadow: var(--mj-shadow-md);\n border-color: var(--mj-brand-primary);\n}\n\n.user-card.expanded {\n box-shadow: var(--mj-shadow-lg);\n border-color: var(--mj-brand-primary);\n}\n\n.user-card.selected {\n background: var(--mj-brand-accent-subtle);\n border-color: var(--mj-brand-primary);\n}\n\n.user-card.selected .user-header {\n background: transparent;\n}\n\n.user-card.selected:hover .user-header {\n background: rgba(0, 118, 182, 0.08);\n}\n\n.user-header {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 1.25rem 1.5rem;\n cursor: pointer;\n background: var(--mj-bg-surface);\n transition: background-color 0.2s ease;\n}\n\n.user-header:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n@media (max-width: 639px) {\n .user-header {\n padding: 0.875rem 1rem;\n gap: 0.625rem;\n }\n}\n\n.user-selection {\n flex-shrink: 0;\n}\n\n.checkbox {\n width: 20px;\n height: 20px;\n cursor: pointer;\n accent-color: var(--mj-brand-primary);\n}\n\n.user-info {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n flex: 1;\n min-width: 0;\n}\n\n.user-avatar {\n width: 48px;\n height: 48px;\n border-radius: var(--mj-radius-full);\n background: linear-gradient(135deg, var(--mj-brand-primary) 0%, var(--mj-brand-primary-light) 100%);\n color: var(--mj-brand-on-primary);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 0.875rem;\n font-weight: 600;\n flex-shrink: 0;\n}\n\n@media (max-width: 639px) {\n .user-avatar {\n width: 40px;\n height: 40px;\n font-size: 0.8125rem;\n }\n\n .user-details {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n }\n\n .user-name {\n font-size: 0.9375rem;\n font-weight: 600;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .user-email {\n font-size: 0.8125rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n}\n\n.user-details {\n flex: 1;\n min-width: 0;\n}\n\n.user-name {\n font-size: 1rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.user-email {\n font-size: 0.875rem;\n color: var(--mj-text-secondary);\n margin: 0.125rem 0 0 0;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.user-meta {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n flex-shrink: 0;\n}\n\n@media (max-width: 767px) {\n .user-meta .status-badge,\n .user-meta .user-actions {\n display: none !important;\n }\n\n .user-meta {\n gap: 0;\n }\n}\n\n.desktop-only {\n display: none;\n}\n\n@media (min-width: 768px) {\n .desktop-only {\n display: flex;\n gap: 0.25rem;\n }\n}\n\n.user-actions {\n display: flex;\n gap: 0.25rem;\n}\n\n.user-card.expanded .expand-btn i {\n transform: rotate(180deg);\n}\n\n/* User Card Content - Expanded */\n.user-content {\n padding: 1.25rem 1.5rem;\n background: var(--mj-bg-page);\n border-top: 1px solid var(--mj-border-default);\n animation: slideDown 0.3s cubic-bezier(0, 0, 0.2, 1);\n}\n\n/* Mobile Actions Bar - visible on mobile */\n.mobile-actions-bar {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding-bottom: 1rem;\n margin-bottom: 1rem;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n@media (min-width: 768px) {\n .mobile-actions-bar {\n display: none;\n }\n}\n\n.mobile-action-buttons .btn-label {\n margin-left: 0.375rem;\n}\n\n/* User Stats in Expanded Content */\n.user-stats {\n display: flex;\n flex-wrap: wrap;\n gap: 1rem;\n margin-bottom: 1rem;\n}\n\n.user-stats .stat-item {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n font-size: 0.875rem;\n color: var(--mj-text-secondary);\n}\n\n.user-stats .stat-item i {\n color: var(--mj-brand-primary);\n font-size: 0.875rem;\n}\n\n.user-stats .stat-label {\n color: var(--mj-text-secondary);\n}\n\n.user-stats .stat-value {\n color: var(--mj-text-primary);\n font-weight: 500;\n display: flex;\n align-items: center;\n gap: 0.25rem;\n}\n\n.user-stats .stat-value i {\n font-size: 0.75rem;\n}\n\n/* Roles Section */\n.roles-section {\n padding-top: 1rem;\n border-top: 1px solid var(--mj-border-default);\n}\n\n.section-title {\n display: flex;\n align-items: center;\n gap: 0.625rem;\n font-size: 1rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0 0 0.75rem 0;\n}\n\n.section-title i {\n color: var(--mj-brand-primary);\n font-size: 1.125rem;\n}\n\n.roles-grid {\n display: flex;\n flex-wrap: wrap;\n gap: 0.5rem;\n}\n\n.role-item {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.375rem 0.875rem;\n background: var(--mj-color-warning-50);\n color: var(--mj-color-warning-800);\n border: 1px solid var(--mj-color-warning-500);\n border-radius: var(--mj-radius-full);\n font-size: 0.75rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.03em;\n}\n\n.role-item i {\n font-size: 0.625rem;\n}\n\n.no-roles {\n font-size: 0.875rem;\n color: var(--mj-text-secondary);\n margin: 0;\n}\n\n/* -----------------------------------------------------------------------------\n Error State Override - includes retry button\n ----------------------------------------------------------------------------- */\n.error-container .retry-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n padding: 0.75rem 1.5rem;\n font-size: 0.875rem;\n font-weight: 600;\n border: none;\n border-radius: var(--mj-radius-full);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n box-shadow: var(--mj-shadow-sm);\n min-height: 44px;\n}\n\n.error-container .retry-button:hover {\n background: var(--mj-brand-primary-light);\n box-shadow: var(--mj-shadow-md);\n}\n\n.error-container .retry-button:active {\n background: var(--mj-color-brand-400);\n transform: scale(0.98);\n}\n\n/* -----------------------------------------------------------------------------\n Form Field in Modal\n ----------------------------------------------------------------------------- */\n.form-field {\n margin-bottom: 1rem;\n}\n\n.form-field .field-label {\n display: block;\n font-size: 0.75rem;\n font-weight: 500;\n color: var(--mj-text-primary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin-bottom: 0.5rem;\n}\n\n.form-field .field-select {\n width: 100%;\n padding: 0.75rem 1rem;\n border: 1px solid var(--mj-color-neutral-400);\n border-radius: var(--mj-radius-md);\n background: var(--mj-bg-page);\n font-size: 1rem;\n color: var(--mj-text-primary);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.form-field .field-select:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px rgba(0, 118, 182, 0.2);\n}\n\n/* User-mgmt specific mobile action-buttons with FAB style */\n@media (max-width: 639px) {\n .mj-btn-primary.mj-btn-icon-mobile {\n box-shadow: var(--mj-shadow-md);\n }\n\n .mj-btn-primary.mj-btn-icon-mobile:hover {\n box-shadow: var(--mj-shadow-lg);\n transform: scale(1.05);\n }\n\n .mj-btn-secondary.mj-btn-icon-mobile {\n background: var(--mj-bg-page);\n border: 1px solid var(--mj-color-neutral-400);\n }\n\n .mj-btn-secondary.mj-btn-icon-mobile:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n border-color: var(--mj-brand-primary);\n }\n\n .mj-btn-icon-mobile {\n width: 48px;\n height: 48px;\n padding: 0;\n border-radius: var(--mj-radius-full);\n min-width: 48px;\n min-height: 48px;\n }\n\n .mj-btn-icon-mobile i {\n font-size: 1.25rem;\n }\n}\n\n/* Accessibility override for user-specific elements */\n.checkbox:focus-visible,\n.user-header:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n/* .mj-filter-select focus indicator */\n.mj-filter-select:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n/* -----------------------------------------------------------------------------\n Large Desktop (1440px+)\n ----------------------------------------------------------------------------- */\n@media (min-width: 1440px) {\n .user-management-container {\n margin: 0 auto;\n }\n\n .action-buttons {\n padding: 1.25rem 2rem;\n }\n\n .bulk-action-toolbar {\n padding: 1.25rem 2rem;\n }\n\n .mj-grid-4 {\n gap: 1.5rem;\n padding: 0 2rem 1rem 2rem;\n }\n\n .filters-section {\n margin: 0 2rem 1rem 2rem;\n padding: 1rem 1.5rem;\n }\n\n .scrollable-content {\n padding: 2rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Mobile (< 640px) - Compact adjustments\n ----------------------------------------------------------------------------- */\n@media (max-width: 639px) {\n .sticky-header {\n padding-bottom: 0;\n }\n\n .mj-grid-4 {\n grid-template-columns: repeat(2, 1fr);\n gap: 0.5rem;\n padding: 0 0.75rem 0.5rem 0.75rem;\n }\n\n .mj-card {\n padding: 0.75rem;\n gap: 0.75rem;\n }\n\n .stat-icon {\n width: 40px;\n height: 40px;\n font-size: 1.125rem;\n }\n\n .stat-content .stat-value {\n font-size: 1.5rem;\n }\n\n .stat-content .stat-label {\n font-size: 0.6875rem;\n }\n\n .filters-section {\n margin: 0 0.75rem 0.5rem 0.75rem;\n padding: 0.75rem;\n }\n\n .scrollable-content {\n padding: 0.75rem;\n }\n\n .content-area {\n padding: 0.875rem;\n border-radius: var(--mj-radius-lg);\n }\n\n .list-header {\n padding: 0.625rem 0.75rem;\n }\n\n .empty-state {\n padding: 2rem 1rem;\n }\n\n .empty-state .empty-icon {\n font-size: 3rem;\n }\n\n .empty-state .empty-text {\n font-size: 1.0625rem;\n }\n\n .empty-state .empty-subtext {\n font-size: 0.875rem;\n }\n}\n"] }]
|
|
1232
|
+
args: [{ standalone: false, selector: 'mj-user-management', template: "<!--\n Interior chrome \u2014 <mj-page-header-interior> is the body-level sibling of\n <mj-page-header>. Same slot conventions ([toolbar] / [meta] / [actions]);\n different visual shape (single-row card). See Section 10 of\n explorer-chrome-conventions.\n-->\n<mj-page-header-interior\n AriaLabel=\"Filter users\"\n Title=\"Users\"\n Subtitle=\"Manage user accounts, roles, and access\">\n <!-- X-of-Y filtered count earns its meta spot per chrome conventions \u00A72 \u2014\n tells the user how the search/filter is narrowing the data, signal at\n any scale. Partition badges (active/inactive/owners) stay dropped \u2014\n they 1:1 mirror the filter chips in [toolbar] below. -->\n <div meta>\n <mj-stat-badge\n [Count]=\"filteredUsers.length\"\n [Total]=\"users.length\"\n Label=\"users\">\n </mj-stat-badge>\n </div>\n <div toolbar>\n <mj-page-search\n Placeholder=\"Search users by name or email...\"\n [Value]=\"filters$.value.search\"\n (ValueChange)=\"updateFilter({ search: $event })\">\n </mj-page-search>\n <div class=\"status-chips\" role=\"group\" aria-label=\"Filter by status\">\n <mj-filter-chip\n Label=\"All\"\n [Active]=\"filters$.value.status === 'all'\"\n (Clicked)=\"onStatusFilterChange('all')\">\n </mj-filter-chip>\n <mj-filter-chip\n Label=\"Active\"\n [Active]=\"filters$.value.status === 'active'\"\n (Clicked)=\"onStatusFilterChange('active')\">\n </mj-filter-chip>\n <mj-filter-chip\n Label=\"Inactive\"\n [Active]=\"filters$.value.status === 'inactive'\"\n (Clicked)=\"onStatusFilterChange('inactive')\">\n </mj-filter-chip>\n </div>\n </div>\n <div actions>\n <mj-filter-popover\n [ActiveCount]=\"popoverActiveFilterCount\"\n [ShowClearAll]=\"popoverActiveFilterCount > 0\"\n (ClearAllRequested)=\"onFilterPanelChange({ role: '' })\">\n <mj-filter-panel\n [Fields]=\"filterFields\"\n [Values]=\"filterValues\"\n (ValuesChange)=\"onFilterPanelChange($event)\"\n (Reset)=\"onFilterPanelChange({ role: '' })\">\n </mj-filter-panel>\n </mj-filter-popover>\n <mj-refresh-button [Loading]=\"isLoading\" (Clicked)=\"refreshData()\"></mj-refresh-button>\n <button mjButton variant=\"secondary\" size=\"sm\" (click)=\"exportUsers()\" aria-label=\"Export users to file\">\n <i class=\"fa-solid fa-download\"></i> Export\n </button>\n <button mjButton variant=\"primary\" size=\"sm\" (click)=\"createNewUser()\" aria-label=\"Add new user\">\n <i class=\"fa-solid fa-plus\"></i> Add User\n </button>\n </div>\n</mj-page-header-interior>\n\n <!-- Bulk Action Toolbar \u2014 contextual band shown above the list when users are selected. -->\n @if (hasSelection) {\n <div class=\"bulk-action-toolbar\" role=\"toolbar\" aria-label=\"Bulk actions\">\n <div class=\"bulk-selection-info\">\n <i class=\"fa-solid fa-check-square\" aria-hidden=\"true\"></i>\n <span>{{ selectedCount }} user{{ selectedCount > 1 ? 's' : '' }} selected</span>\n <button mjButton variant=\"flat\" size=\"sm\" (click)=\"clearSelection()\" aria-label=\"Clear selection\">\n <i class=\"fa-solid fa-times\" aria-hidden=\"true\"></i>\n Clear\n </button>\n </div>\n <div class=\"bulk-action-buttons\">\n <button mjButton variant=\"secondary\" size=\"sm\" (click)=\"confirmBulkAction('enable')\" aria-label=\"Enable selected users\">\n <i class=\"fa-solid fa-toggle-on\" aria-hidden=\"true\"></i>\n <span class=\"btn-text\">Enable</span>\n </button>\n <button mjButton variant=\"secondary\" size=\"sm\" (click)=\"confirmBulkAction('disable')\" aria-label=\"Disable selected users\">\n <i class=\"fa-solid fa-toggle-off\" aria-hidden=\"true\"></i>\n <span class=\"btn-text\">Disable</span>\n </button>\n <button mjButton variant=\"secondary\" size=\"sm\" (click)=\"openBulkRoleAssign()\" aria-label=\"Assign role to selected users\">\n <i class=\"fa-solid fa-user-tag\" aria-hidden=\"true\"></i>\n <span class=\"btn-text\">Assign Role</span>\n </button>\n <button mjButton variant=\"danger\" size=\"sm\" (click)=\"confirmBulkAction('delete')\" aria-label=\"Delete selected users\">\n <i class=\"fa-solid fa-trash\" aria-hidden=\"true\"></i>\n <span class=\"btn-text\">Delete</span>\n </button>\n </div>\n </div>\n }\n\n <!-- Scrollable Content Section \u2014 owned by <mj-page-body-interior>. -->\n <mj-page-body-interior>\n <!-- Loading State -->\n @if (isLoading) {\n <div class=\"loading-container\" role=\"status\" aria-live=\"polite\" aria-busy=\"true\">\n <mj-loading text=\"Loading users...\" size=\"medium\"></mj-loading>\n </div>\n }\n\n <!-- Error State -->\n @if (error && !isLoading) {\n <div class=\"error-container\" role=\"alert\" aria-live=\"assertive\">\n <div class=\"error-content\">\n <i class=\"fa-solid fa-exclamation-triangle error-icon\" aria-hidden=\"true\"></i>\n <p class=\"error-message\">{{ error }}</p>\n <button class=\"retry-button\" (click)=\"loadInitialData()\" aria-label=\"Retry loading users\">\n <i class=\"fa-solid fa-refresh\" aria-hidden=\"true\"></i>\n Try Again\n </button>\n </div>\n </div>\n }\n\n <!-- Users List -->\n @if (!isLoading && !error) {\n <div class=\"users-list\" role=\"list\" aria-label=\"Users list\">\n <!-- List Header with Select All -->\n <div class=\"list-header\">\n <label class=\"select-all-label\">\n <input\n type=\"checkbox\"\n class=\"checkbox\"\n [checked]=\"isAllSelected\"\n [indeterminate]=\"isIndeterminate\"\n (change)=\"toggleSelectAll()\"\n aria-label=\"Select all users\"\n />\n <span class=\"select-all-text\">Select All ({{ filteredUsers.length }})</span>\n </label>\n @if (hasSelection) {\n <span class=\"selection-count\">{{ selectedCount }} selected</span>\n }\n </div>\n\n @for (user of filteredUsers; track user.ID) {\n <div\n class=\"user-card\"\n [class.expanded]=\"isUserExpanded(user.ID)\"\n [class.selected]=\"isUserSelected(user.ID)\"\n role=\"listitem\"\n >\n <!-- User Card Header - Always Visible -->\n <div\n class=\"user-header\"\n (click)=\"toggleUserExpansion(user.ID)\"\n role=\"button\"\n [attr.aria-expanded]=\"isUserExpanded(user.ID)\"\n tabindex=\"0\"\n (keydown.enter)=\"toggleUserExpansion(user.ID)\"\n >\n <!-- Selection Checkbox -->\n <div class=\"user-selection\" (click)=\"$event.stopPropagation()\">\n <input\n type=\"checkbox\"\n class=\"checkbox\"\n [checked]=\"isUserSelected(user.ID)\"\n (change)=\"toggleUserSelection(user.ID, $event)\"\n [attr.aria-label]=\"'Select ' + user.Name\"\n />\n </div>\n\n <!-- User Info -->\n <div class=\"user-info\">\n <div class=\"user-avatar\" aria-hidden=\"true\">\n {{ getUserInitials(user) }}\n </div>\n <div class=\"user-details\">\n <h3 class=\"user-name\">{{ user.Name }}</h3>\n <p class=\"user-email\">{{ user.Email }}</p>\n </div>\n </div>\n\n <!-- User Meta -->\n <div class=\"user-meta\">\n <span class=\"status-badge\" [class]=\"getStatusClass(user)\">\n <i [class]=\"'fa-solid ' + getStatusIcon(user)\" aria-hidden=\"true\"></i>\n {{ user.IsActive ? 'Active' : 'Inactive' }}\n </span>\n <div class=\"user-actions desktop-only\" (click)=\"$event.stopPropagation()\">\n <button\n mjButton variant=\"flat\" size=\"sm\"\n (click)=\"editUser(user)\"\n [attr.aria-label]=\"'Edit ' + user.Name\"\n title=\"Edit\"\n >\n <i class=\"fa-solid fa-edit\" aria-hidden=\"true\"></i>\n </button>\n <button\n mjButton variant=\"flat\" size=\"sm\"\n (click)=\"toggleUserStatus(user)\"\n [attr.aria-label]=\"(user.IsActive ? 'Deactivate ' : 'Activate ') + user.Name\"\n [title]=\"user.IsActive ? 'Deactivate' : 'Activate'\"\n >\n <i [class]=\"user.IsActive ? 'fa-solid fa-toggle-on' : 'fa-solid fa-toggle-off'\" aria-hidden=\"true\"></i>\n </button>\n <button\n mjButton variant=\"danger\" size=\"sm\"\n (click)=\"confirmDeleteUser(user)\"\n [attr.aria-label]=\"'Delete ' + user.Name\"\n title=\"Delete\"\n >\n <i class=\"fa-solid fa-trash\" aria-hidden=\"true\"></i>\n </button>\n </div>\n <button class=\"expand-btn\" aria-label=\"Toggle user details\">\n <i class=\"fa-solid fa-chevron-down\" aria-hidden=\"true\"></i>\n </button>\n </div>\n </div>\n\n <!-- User Card Content - Expanded -->\n @if (isUserExpanded(user.ID)) {\n <div class=\"user-content\">\n <!-- Mobile Actions Bar -->\n <div class=\"mobile-actions-bar\" (click)=\"$event.stopPropagation()\">\n <span class=\"status-badge\" [class]=\"getStatusClass(user)\">\n <i [class]=\"'fa-solid ' + getStatusIcon(user)\" aria-hidden=\"true\"></i>\n {{ user.IsActive ? 'Active' : 'Inactive' }}\n </span>\n <div class=\"mobile-action-buttons\">\n <button\n mjButton variant=\"flat\" size=\"sm\"\n (click)=\"editUser(user)\"\n [attr.aria-label]=\"'Edit ' + user.Name\"\n >\n <i class=\"fa-solid fa-edit\" aria-hidden=\"true\"></i>\n <span class=\"btn-label\">Edit</span>\n </button>\n <button\n mjButton variant=\"flat\" size=\"sm\"\n (click)=\"toggleUserStatus(user)\"\n [attr.aria-label]=\"(user.IsActive ? 'Deactivate ' : 'Activate ') + user.Name\"\n >\n <i [class]=\"user.IsActive ? 'fa-solid fa-toggle-on' : 'fa-solid fa-toggle-off'\" aria-hidden=\"true\"></i>\n <span class=\"btn-label\">{{ user.IsActive ? 'Disable' : 'Enable' }}</span>\n </button>\n <button\n mjButton variant=\"danger\" size=\"sm\"\n (click)=\"confirmDeleteUser(user)\"\n [attr.aria-label]=\"'Delete ' + user.Name\"\n >\n <i class=\"fa-solid fa-trash\" aria-hidden=\"true\"></i>\n <span class=\"btn-label\">Delete</span>\n </button>\n </div>\n </div>\n\n <!-- User Stats -->\n <div class=\"user-stats\">\n <div class=\"stat-item\">\n <i class=\"fa-solid fa-user-tag\" aria-hidden=\"true\"></i>\n <span class=\"stat-label\">Type:</span>\n <span class=\"stat-value\">\n <i [class]=\"'fa-solid ' + getUserTypeIcon(user)\" aria-hidden=\"true\"></i>\n {{ user.Type }}\n </span>\n </div>\n <div class=\"stat-item\">\n <i class=\"fa-solid fa-id-card\" aria-hidden=\"true\"></i>\n <span class=\"stat-label\">Full Name:</span>\n <span class=\"stat-value\">{{ user.FirstName }} {{ user.LastName }}</span>\n </div>\n <div class=\"stat-item\">\n <i class=\"fa-solid fa-calendar\" aria-hidden=\"true\"></i>\n <span class=\"stat-label\">Created:</span>\n <span class=\"stat-value\">{{ user.__mj_CreatedAt | date:'short' }}</span>\n </div>\n <div class=\"stat-item\">\n <i class=\"fa-solid fa-clock\" aria-hidden=\"true\"></i>\n <span class=\"stat-label\">Updated:</span>\n <span class=\"stat-value\">{{ user.__mj_UpdatedAt | date:'short' }}</span>\n </div>\n </div>\n\n <!-- User Roles Section -->\n <div class=\"roles-section\">\n <h4 class=\"section-title\">\n <i class=\"fa-solid fa-user-shield\" aria-hidden=\"true\"></i>\n Assigned Roles\n </h4>\n @if (getUserRoles(user.ID).length > 0) {\n <div class=\"roles-grid\">\n @for (role of getUserRoles(user.ID); track role.ID) {\n <div class=\"role-item\">\n <i class=\"fa-solid fa-shield\" aria-hidden=\"true\"></i>\n {{ role.Name }}\n </div>\n }\n </div>\n } @else {\n <p class=\"no-roles\">No roles assigned to this user</p>\n }\n </div>\n </div>\n }\n </div>\n }\n\n @if (filteredUsers.length === 0) {\n <div class=\"empty-state\" role=\"status\">\n <i class=\"fa-solid fa-users-slash empty-icon\" aria-hidden=\"true\"></i>\n <p class=\"empty-text\">No users found</p>\n <p class=\"empty-subtext\">Try adjusting your filters or add a new user</p>\n </div>\n }\n </div>\n }\n </mj-page-body-interior>\n\n <!-- User Create/Edit Dialog -->\n <mj-user-dialog\n [data]=\"userDialogData\"\n [visible]=\"showUserDialog\"\n (result)=\"onUserDialogResult($event)\">\n </mj-user-dialog>\n\n <!-- Delete Confirmation Dialog -->\n @if (showDeleteConfirm && selectedUser) {\n <div\n class=\"modal-backdrop\"\n (click)=\"showDeleteConfirm = false\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"delete-dialog-title\"\n aria-describedby=\"delete-dialog-desc\"\n >\n <div class=\"modal-dialog\" (click)=\"$event.stopPropagation()\">\n <div class=\"modal-header\">\n <h3 class=\"modal-title\" id=\"delete-dialog-title\">\n <i class=\"fa-solid fa-exclamation-triangle text-danger\" aria-hidden=\"true\"></i>\n Confirm Delete\n </h3>\n <button\n class=\"modal-close\"\n (click)=\"showDeleteConfirm = false\"\n aria-label=\"Close dialog\"\n >\n <i class=\"fa-solid fa-times\" aria-hidden=\"true\"></i>\n </button>\n </div>\n <div class=\"modal-body\" id=\"delete-dialog-desc\">\n <p>Are you sure you want to delete user <strong>{{ selectedUser.Name }}</strong>?</p>\n <p class=\"text-muted\">This action cannot be undone.</p>\n </div>\n <div class=\"modal-footer\">\n <button mjButton variant=\"danger\" (click)=\"deleteUser()\">\n <i class=\"fa-solid fa-trash\" aria-hidden=\"true\"></i>\n Delete User\n </button>\n <button mjButton (click)=\"showDeleteConfirm = false\">\n Cancel\n </button>\n </div>\n </div>\n </div>\n }\n\n <!-- Bulk Action Confirmation Dialog -->\n @if (showBulkActionConfirm) {\n <div\n class=\"modal-backdrop\"\n (click)=\"cancelBulkAction()\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"bulk-action-dialog-title\"\n aria-describedby=\"bulk-action-dialog-desc\"\n >\n <div class=\"modal-dialog\" (click)=\"$event.stopPropagation()\">\n <div class=\"modal-header\">\n <h3 class=\"modal-title\" id=\"bulk-action-dialog-title\">\n @if (bulkActionType === 'delete') {\n <i class=\"fa-solid fa-exclamation-triangle text-danger\" aria-hidden=\"true\"></i>\n } @else if (bulkActionType === 'enable') {\n <i class=\"fa-solid fa-toggle-on text-success\" aria-hidden=\"true\"></i>\n } @else {\n <i class=\"fa-solid fa-toggle-off text-warning\" aria-hidden=\"true\"></i>\n }\n {{ getBulkActionTitle() }}\n </h3>\n <button\n class=\"modal-close\"\n (click)=\"cancelBulkAction()\"\n aria-label=\"Close dialog\"\n >\n <i class=\"fa-solid fa-times\" aria-hidden=\"true\"></i>\n </button>\n </div>\n <div class=\"modal-body\" id=\"bulk-action-dialog-desc\">\n <p>{{ getBulkActionMessage() }}</p>\n @if (bulkActionType === 'delete') {\n <p class=\"text-muted\">This action cannot be undone.</p>\n }\n </div>\n <div class=\"modal-footer\">\n <button mjButton\n [variant]=\"bulkActionType === 'delete' ? 'danger' : 'primary'\"\n (click)=\"executeBulkAction()\"\n [disabled]=\"isLoading\"\n >\n @if (isLoading) {\n <i class=\"fa-solid fa-spinner fa-spin\" aria-hidden=\"true\"></i>\n Processing...\n } @else {\n @if (bulkActionType === 'delete') {\n <i class=\"fa-solid fa-trash\" aria-hidden=\"true\"></i>\n } @else if (bulkActionType === 'enable') {\n <i class=\"fa-solid fa-toggle-on\" aria-hidden=\"true\"></i>\n } @else {\n <i class=\"fa-solid fa-toggle-off\" aria-hidden=\"true\"></i>\n }\n {{ getBulkActionButtonText() }}\n }\n </button>\n <button mjButton (click)=\"cancelBulkAction()\" [disabled]=\"isLoading\">\n Cancel\n </button>\n </div>\n </div>\n </div>\n }\n\n <!-- Bulk Role Assignment Dialog -->\n @if (showBulkRoleAssign) {\n <div\n class=\"modal-backdrop\"\n (click)=\"cancelBulkRoleAssign()\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"bulk-role-dialog-title\"\n aria-describedby=\"bulk-role-dialog-desc\"\n >\n <div class=\"modal-dialog\" (click)=\"$event.stopPropagation()\">\n <div class=\"modal-header\">\n <h3 class=\"modal-title\" id=\"bulk-role-dialog-title\">\n <i class=\"fa-solid fa-user-tag\" aria-hidden=\"true\"></i>\n Assign Role to {{ selectedCount }} User{{ selectedCount > 1 ? 's' : '' }}\n </h3>\n <button\n class=\"modal-close\"\n (click)=\"cancelBulkRoleAssign()\"\n aria-label=\"Close dialog\"\n >\n <i class=\"fa-solid fa-times\" aria-hidden=\"true\"></i>\n </button>\n </div>\n <div class=\"modal-body\" id=\"bulk-role-dialog-desc\">\n <p>Select a role to assign to the selected users:</p>\n <div class=\"form-field\">\n <label class=\"field-label\" for=\"bulk-role-select\">Role</label>\n <select\n id=\"bulk-role-select\"\n class=\"field-select\"\n [(ngModel)]=\"bulkRoleId\"\n aria-label=\"Select role to assign\"\n >\n <option value=\"\">Select a role...</option>\n @for (role of roles; track role.ID) {\n <option [value]=\"role.ID\">{{ role.Name }}</option>\n }\n </select>\n </div>\n </div>\n <div class=\"modal-footer\">\n <button\n mjButton variant=\"primary\"\n (click)=\"executeBulkRoleAssign()\"\n [disabled]=\"!bulkRoleId || isLoading\"\n >\n @if (isLoading) {\n <i class=\"fa-solid fa-spinner fa-spin\" aria-hidden=\"true\"></i>\n Assigning...\n } @else {\n <i class=\"fa-solid fa-user-tag\" aria-hidden=\"true\"></i>\n Assign Role\n }\n </button>\n <button mjButton (click)=\"cancelBulkRoleAssign()\" [disabled]=\"isLoading\">\n Cancel\n </button>\n </div>\n </div>\n </div>\n }\n", styles: ["/* =============================================================================\n Shared Admin Patterns - MJ Design System\n Common styles shared across all admin settings components.\n Component-specific CSS files override these values where needed.\n ============================================================================= */\n\n/* -----------------------------------------------------------------------------\n Host & Container\n ----------------------------------------------------------------------------- */\n:host {\n display: flex;\n flex-direction: column;\n height: 100%;\n width: 100%;\n overflow: hidden;\n}\n\n/* -----------------------------------------------------------------------------\n Sticky Header\n ----------------------------------------------------------------------------- */\n.sticky-header {\n flex-shrink: 0;\n background: var(--mj-bg-page);\n border-bottom: 1px solid var(--mj-border-default);\n box-shadow: var(--mj-shadow-sm);\n z-index: 10;\n}\n\n/* -----------------------------------------------------------------------------\n Scrollable Content\n ----------------------------------------------------------------------------- */\n.scrollable-content {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n -webkit-overflow-scrolling: touch;\n padding: 1rem;\n background: var(--mj-bg-surface-sunken);\n}\n\n@media (min-width: 768px) {\n .scrollable-content {\n padding: 1.5rem 2rem;\n }\n}\n\n@media (min-width: 1024px) {\n .scrollable-content {\n padding: 2rem;\n }\n}\n\n@media (min-width: 1440px) {\n .scrollable-content {\n padding: 2rem 2.5rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Action Buttons (In Sticky Header)\n ----------------------------------------------------------------------------- */\n.action-buttons {\n flex-shrink: 0;\n display: flex;\n gap: 0.75rem;\n justify-content: flex-end;\n padding: 0.75rem 1rem;\n background: var(--mj-bg-page);\n}\n\n@media (min-width: 768px) {\n .action-buttons {\n padding: 1rem 1.5rem;\n }\n}\n\n@media (max-width: 639px) {\n .action-buttons {\n justify-content: center;\n flex-wrap: wrap;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Statistics Cards Grid - Static Display (Non-interactive)\n ----------------------------------------------------------------------------- */\n.mj-grid-4 {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 0.5rem;\n padding: 0 1rem 0.75rem 1rem;\n background: var(--mj-bg-page);\n}\n\n@media (min-width: 768px) {\n .mj-grid-4 {\n grid-template-columns: repeat(4, 1fr);\n padding: 0 1.5rem 1rem 1.5rem;\n gap: 0.75rem;\n }\n}\n\n@media (min-width: 1024px) {\n .mj-grid-4 {\n gap: 1rem;\n }\n}\n\n/* Static Card - No hover effects */\n.mj-card {\n background: var(--mj-bg-surface-card);\n border-radius: var(--mj-radius-lg);\n padding: 1rem;\n box-shadow: var(--mj-shadow-sm);\n display: flex;\n align-items: center;\n gap: 1rem;\n border: 1px solid var(--mj-border-default);\n cursor: default;\n pointer-events: none;\n}\n\n@media (min-width: 768px) {\n .mj-card {\n padding: 1rem 1.25rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Stat Icon Containers\n ----------------------------------------------------------------------------- */\n.stat-icon {\n width: 48px;\n height: 48px;\n border-radius: var(--mj-radius-lg);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 1.25rem;\n flex-shrink: 0;\n}\n\n@media (min-width: 768px) {\n .stat-icon {\n width: 52px;\n height: 52px;\n font-size: 1.375rem;\n }\n}\n\n.stat-icon-total {\n background: var(--mj-color-accent-300);\n color: var(--mj-brand-primary);\n}\n\n.stat-icon-active {\n background: var(--mj-color-success-100);\n color: var(--mj-status-success);\n}\n\n/* -----------------------------------------------------------------------------\n Stat Content Typography\n ----------------------------------------------------------------------------- */\n.stat-content {\n flex: 1;\n min-width: 0;\n}\n\n.stat-content .stat-value {\n font-size: 1.75rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n line-height: 1;\n letter-spacing: -0.02em;\n}\n\n@media (min-width: 768px) {\n .stat-content .stat-value {\n font-size: 2rem;\n }\n}\n\n.stat-content .stat-label {\n font-size: 0.75rem;\n font-weight: 500;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin-top: 0.25rem;\n}\n\n@media (min-width: 768px) {\n .stat-content .stat-label {\n font-size: 0.8125rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Filters Section\n ----------------------------------------------------------------------------- */\n.filters-section {\n flex-shrink: 0;\n background: var(--mj-bg-surface-card);\n margin: 0 1rem 0.75rem 1rem;\n padding: 0.75rem;\n border-radius: var(--mj-radius-lg);\n border: 1px solid var(--mj-border-default);\n}\n\n@media (min-width: 768px) {\n .filters-section {\n margin: 0 1.5rem 1rem 1.5rem;\n padding: 1rem 1.25rem;\n }\n}\n\n.filters-row {\n display: flex;\n gap: 1rem;\n align-items: flex-end;\n flex-wrap: wrap;\n}\n\n@media (min-width: 768px) {\n .filters-row {\n gap: 1.5rem;\n }\n}\n\n.mj-filter-group {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.mj-filter-label {\n font-size: 0.75rem;\n font-weight: 500;\n color: var(--mj-text-primary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n.mj-filter-buttons {\n display: flex;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-full);\n padding: 4px;\n gap: 2px;\n}\n\n/* -----------------------------------------------------------------------------\n Search Input\n ----------------------------------------------------------------------------- */\n.mj-search {\n position: relative;\n flex: 1;\n min-width: 200px;\n}\n\n@media (min-width: 640px) {\n .mj-search {\n min-width: 280px;\n }\n}\n\n@media (min-width: 1024px) {\n .mj-search {\n min-width: 400px;\n max-width: 600px;\n }\n}\n\n@media (min-width: 1440px) {\n .mj-search {\n min-width: 500px;\n max-width: 800px;\n }\n}\n\n.mj-search .mj-search-icon {\n position: absolute;\n left: 1rem;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-secondary);\n font-size: 1rem;\n pointer-events: none;\n transition: color 0.2s ease;\n}\n\n@media (min-width: 1024px) {\n .mj-search .mj-search-icon {\n left: 1.25rem;\n font-size: 1.125rem;\n }\n}\n\n.mj-search .mj-search-input {\n width: 100%;\n padding: 0.875rem 1rem 0.875rem 2.75rem;\n border: 2px solid var(--mj-border-default);\n border-radius: var(--mj-radius-full);\n font-size: 1rem;\n background: var(--mj-bg-page);\n color: var(--mj-text-primary);\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 44px;\n}\n\n@media (min-width: 1024px) {\n .mj-search .mj-search-input {\n padding: 1rem 1.25rem 1rem 3.25rem;\n font-size: 1.0625rem;\n }\n}\n\n@media (min-width: 1440px) {\n .mj-search .mj-search-input {\n padding: 1.125rem 1.5rem 1.125rem 3.5rem;\n }\n}\n\n.mj-search .mj-search-input::placeholder {\n color: var(--mj-text-secondary);\n}\n\n.mj-search .mj-search-input:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n}\n\n.mj-search .mj-search-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px rgba(0, 118, 182, 0.2);\n background: var(--mj-bg-page);\n}\n\n.mj-search:focus-within .mj-search-icon {\n color: var(--mj-brand-primary);\n}\n\n/* -----------------------------------------------------------------------------\n Content Area\n ----------------------------------------------------------------------------- */\n.content-area {\n flex: 1 1 auto;\n overflow: visible;\n position: relative;\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-xl);\n box-shadow: var(--mj-shadow-sm);\n padding: 1rem;\n border: 1px solid var(--mj-border-default);\n}\n\n@media (min-width: 768px) {\n .content-area {\n padding: 1.5rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Expand Button\n ----------------------------------------------------------------------------- */\n.expand-btn {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 1rem;\n cursor: pointer;\n transition: all 0.2s ease;\n border-radius: var(--mj-radius-full);\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.expand-btn:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.expand-btn i {\n transition: transform 0.3s cubic-bezier(0, 0, 0.2, 1);\n}\n\n/* -----------------------------------------------------------------------------\n Status Badge\n ----------------------------------------------------------------------------- */\n.status-badge {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.375rem 0.875rem;\n border-radius: var(--mj-radius-full);\n font-size: 0.75rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.03em;\n}\n\n.status-badge.status-active {\n background: var(--mj-color-success-100);\n color: var(--mj-color-success-800);\n border: 1px solid var(--mj-status-success);\n}\n\n.status-badge.status-inactive {\n background: var(--mj-color-error-100);\n color: var(--mj-status-error);\n border: 1px solid var(--mj-status-error);\n}\n\n.status-badge i {\n font-size: 0.625rem;\n}\n\n/* -----------------------------------------------------------------------------\n Mobile Actions Bar\n ----------------------------------------------------------------------------- */\n.mobile-actions-bar {\n display: none;\n}\n\n.mobile-action-buttons {\n display: flex;\n gap: 0.5rem;\n}\n\n/* -----------------------------------------------------------------------------\n Empty State\n ----------------------------------------------------------------------------- */\n.empty-state {\n text-align: center;\n padding: 4rem 2rem;\n}\n\n.empty-state .empty-icon {\n font-size: 4rem;\n color: var(--mj-border-default);\n margin-bottom: 1.5rem;\n}\n\n.empty-state .empty-text {\n font-size: 1.25rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0 0 0.5rem 0;\n}\n\n.empty-state .empty-subtext {\n font-size: 1rem;\n color: var(--mj-text-secondary);\n margin: 0;\n}\n\n/* -----------------------------------------------------------------------------\n Loading State\n ----------------------------------------------------------------------------- */\n.loading-container {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 4rem 2rem;\n}\n\n/* -----------------------------------------------------------------------------\n Error State\n ----------------------------------------------------------------------------- */\n.error-container {\n text-align: center;\n padding: 4rem 2rem;\n}\n\n.error-container .error-content {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 1rem;\n}\n\n.error-container .error-icon {\n font-size: 3.5rem;\n color: var(--mj-status-error);\n margin-bottom: 1rem;\n}\n\n.error-container .error-message {\n font-size: 1.0625rem;\n color: var(--mj-text-primary);\n margin: 0 0 1.5rem 0;\n}\n\n/* -----------------------------------------------------------------------------\n Modal Dialog\n ----------------------------------------------------------------------------- */\n.modal-backdrop {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.4);\n backdrop-filter: blur(4px);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n padding: 1rem;\n animation: fadeIn 0.2s cubic-bezier(0, 0, 0.2, 1);\n}\n\n.modal-dialog {\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-2xl);\n box-shadow: var(--mj-shadow-2xl);\n max-width: 500px;\n width: 100%;\n max-height: 90vh;\n overflow: hidden;\n animation: slideUp 0.3s cubic-bezier(0, 0, 0.2, 1);\n}\n\n.modal-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 1.5rem;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.modal-header .modal-title {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n font-size: 1.375rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0;\n}\n\n.modal-header .modal-close {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 1.25rem;\n cursor: pointer;\n border-radius: var(--mj-radius-full);\n transition: all 0.2s ease;\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.modal-header .modal-close:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.modal-body {\n padding: 1.5rem;\n}\n\n.modal-body p {\n font-size: 1rem;\n color: var(--mj-text-primary);\n margin: 0 0 1rem 0;\n line-height: 1.5;\n}\n\n.modal-body p:last-child {\n margin-bottom: 0;\n}\n\n.modal-footer {\n display: flex;\n justify-content: flex-start;\n gap: 0.75rem;\n padding: 1.5rem;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n}\n\n@media (max-width: 639px) {\n .modal-dialog {\n width: 95%;\n max-height: 85vh;\n }\n\n .modal-header {\n padding: 1rem;\n }\n\n .modal-header .modal-title {\n font-size: 1.125rem;\n }\n\n .modal-body {\n padding: 1rem;\n }\n\n .modal-footer {\n padding: 1rem;\n flex-direction: column;\n }\n\n}\n\n/* The legacy \"MJ Button System\" rule block (.mj-btn / .mj-btn-primary /\n .mj-btn-secondary / .mj-btn-ghost / .mj-btn-danger / .mj-btn-sm /\n .mj-btn-icon-only / .mj-btn-icon-mobile) was removed 2026-05-19. These\n rules pre-dated the mjButton directive standardization (the directive\n uses BEM modifiers like .mj-btn--primary, single-dash names like\n .mj-btn-primary don't match it anyway). The base .mj-btn rule WAS active\n though \u2014 its component-scoped specificity outranked button.scss's global\n directive styles, so admin sub-page buttons rendered pill-shaped + 44px\n regardless of the variant/size requested via mjButton inputs. Removing the\n rule lets every sub-page fall back to the directive's intended look. */\n\n/* -----------------------------------------------------------------------------\n Filter Button (Mobile Only)\n ----------------------------------------------------------------------------- */\n.filter-button {\n display: none;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n padding: 0.75rem 1.25rem;\n border: 2px solid var(--mj-border-default);\n background: var(--mj-bg-page);\n color: var(--mj-text-primary);\n border-radius: var(--mj-radius-full);\n font-size: 0.875rem;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 44px;\n min-width: 44px;\n}\n\n.filter-button:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n}\n\n.filter-button:active {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.filter-button i {\n font-size: 1rem;\n}\n\n/* -----------------------------------------------------------------------------\n Filter Modal (Mobile Bottom Sheet)\n ----------------------------------------------------------------------------- */\n.filter-modal-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.4);\n backdrop-filter: blur(4px);\n display: flex;\n align-items: flex-end;\n justify-content: center;\n z-index: 1000;\n animation: fadeIn 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n padding: 0;\n}\n\n.filter-modal {\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-2xl) var(--mj-radius-2xl) 0 0;\n box-shadow: var(--mj-shadow-2xl);\n width: 100%;\n max-height: 80vh;\n overflow: hidden;\n animation: slideUpFromBottom 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n display: flex;\n flex-direction: column;\n}\n\n.filter-modal-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 1.25rem 1.5rem;\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.filter-modal-title {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n font-size: 1.25rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0;\n}\n\n.filter-modal-title i {\n color: var(--mj-brand-primary);\n font-size: 1.375rem;\n}\n\n.filter-modal-close {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 1.25rem;\n cursor: pointer;\n border-radius: var(--mj-radius-full);\n transition: all 0.2s ease;\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.filter-modal-close:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.filter-modal-body {\n padding: 1.5rem;\n overflow-y: auto;\n -webkit-overflow-scrolling: touch;\n flex: 1;\n}\n\n.filter-modal-footer {\n display: flex;\n gap: 0.75rem;\n padding: 1.25rem 1.5rem;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n flex-shrink: 0;\n}\n\n.filter-modal-footer button {\n flex: 1;\n margin: 0;\n}\n\n/* Filter Options Container (Inside Modal) */\n.filter-options-container {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n.filter-group {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n}\n\n.filter-group-label {\n font-size: 0.875rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin: 0;\n}\n\n.filter-group-options {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.filter-option {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 0.875rem 1rem;\n background: var(--mj-bg-surface-sunken);\n border: 2px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 56px;\n}\n\n.filter-option:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface-sunken);\n}\n\n.filter-option.selected {\n background: var(--mj-color-accent-300);\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.filter-option input[type=\"checkbox\"],\n.filter-option input[type=\"radio\"] {\n width: 20px;\n height: 20px;\n cursor: pointer;\n accent-color: var(--mj-brand-primary);\n flex-shrink: 0;\n}\n\n.filter-option-label {\n flex: 1;\n font-size: 1rem;\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.filter-option.selected .filter-option-label {\n color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n/* -----------------------------------------------------------------------------\n Utility Classes\n ----------------------------------------------------------------------------- */\n.text-danger {\n color: var(--mj-status-error);\n}\n\n.text-warning {\n color: var(--mj-color-warning-500);\n}\n\n.text-success {\n color: var(--mj-status-success);\n}\n\n/* -----------------------------------------------------------------------------\n Animations\n ----------------------------------------------------------------------------- */\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n@keyframes slideUp {\n from {\n transform: translateY(20px);\n opacity: 0;\n }\n to {\n transform: translateY(0);\n opacity: 1;\n }\n}\n\n@keyframes slideDown {\n from {\n opacity: 0;\n transform: translateY(-10px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes slideUpFromBottom {\n from {\n transform: translateY(100%);\n opacity: 0;\n }\n to {\n transform: translateY(0);\n opacity: 1;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Accessibility: Focus Indicators\n ----------------------------------------------------------------------------- */\n.mj-search-input:focus-visible,\nbutton:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n/* -----------------------------------------------------------------------------\n Accessibility: Reduced Motion\n ----------------------------------------------------------------------------- */\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 User Management Component - Component-Specific Styles\n Shared patterns are in ../shared/styles/_admin-patterns.css\n ============================================================================= */\n\n/* -----------------------------------------------------------------------------\n Status chip group inside <mj-page-header-interior>'s [toolbar] slot. Sits\n alongside the search input. Tight spacing distinguishes the chips visually\n from the [actions] cluster on the right.\n ----------------------------------------------------------------------------- */\n.status-chips {\n display: inline-flex;\n align-items: center;\n gap: var(--mj-space-2);\n flex-shrink: 0;\n}\n\n/* No bespoke .mj-btn rules here. Buttons inherit the mjButton directive's\n global styles from button.scss \u2014 see \"Button Styling\" in packages/Angular/CLAUDE.md. */\n\n/* :host already provides flex column / 100% height / overflow hidden via\n _admin-patterns.css. No bespoke container wrapper here \u2014 see Section 10 of\n explorer-chrome-conventions for the standardized sub-page layout contract. */\n\n/* -----------------------------------------------------------------------------\n Stats Grid Override - Hidden until 768px (unlike other admin components)\n ----------------------------------------------------------------------------- */\n.mj-grid-4 {\n display: none;\n}\n\n@media (min-width: 768px) {\n .mj-grid-4 {\n display: grid;\n }\n}\n\n/* Stat Icon Override - Stays 48px at 768px (others go to 52px) */\n@media (min-width: 768px) {\n .stat-icon {\n width: 48px;\n height: 48px;\n font-size: 1.25rem;\n }\n}\n\n/* Stat Icon Override - color-mix background instead of accent-300 */\n.stat-icon-total {\n background: color-mix(in srgb, var(--mj-brand-accent) 25%, transparent);\n color: var(--mj-brand-primary);\n}\n\n.stat-icon-inactive {\n background: var(--mj-color-error-100);\n color: var(--mj-status-error);\n}\n\n.stat-icon-admin {\n background: var(--mj-color-warning-50);\n color: var(--mj-color-warning-700);\n}\n\n/* -----------------------------------------------------------------------------\n Bulk Action Toolbar (Unique to user-management)\n ----------------------------------------------------------------------------- */\n.bulk-action-toolbar {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n padding: 0.75rem 1rem;\n background: var(--mj-brand-accent-subtle);\n border-bottom: 1px solid var(--mj-border-default);\n animation: slideDown 0.2s ease;\n}\n\n@media (min-width: 768px) {\n .bulk-action-toolbar {\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n padding: 1rem 1.5rem;\n }\n}\n\n.bulk-selection-info {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n font-size: 0.875rem;\n font-weight: 600;\n color: var(--mj-brand-primary);\n}\n\n.bulk-selection-info i {\n font-size: 1.25rem;\n}\n\n.bulk-action-buttons {\n display: flex;\n gap: 0.5rem;\n flex-wrap: wrap;\n}\n\n@media (max-width: 639px) {\n .bulk-action-buttons .btn-text {\n display: none;\n }\n\n .bulk-action-buttons .mj-btn-sm {\n padding: 0.5rem;\n min-width: 36px;\n }\n}\n\n/* -----------------------------------------------------------------------------\n User Card - Interactive\n ----------------------------------------------------------------------------- */\n.users-list {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n}\n\n.list-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.75rem 1rem;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-md);\n border: 1px solid var(--mj-border-default);\n margin-bottom: 0.5rem;\n}\n\n.select-all-label {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n cursor: pointer;\n font-size: 0.875rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.select-all-text {\n font-weight: 500;\n}\n\n.selection-count {\n font-size: 0.75rem;\n font-weight: 600;\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-accent) 25%, transparent);\n padding: 0.25rem 0.75rem;\n border-radius: var(--mj-radius-full);\n}\n\n.user-card {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-xl);\n overflow: hidden;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.user-card:hover {\n box-shadow: var(--mj-shadow-md);\n border-color: var(--mj-brand-primary);\n}\n\n.user-card.expanded {\n box-shadow: var(--mj-shadow-lg);\n border-color: var(--mj-brand-primary);\n}\n\n.user-card.selected {\n background: var(--mj-brand-accent-subtle);\n border-color: var(--mj-brand-primary);\n}\n\n.user-card.selected .user-header {\n background: transparent;\n}\n\n.user-card.selected:hover .user-header {\n background: rgba(0, 118, 182, 0.08);\n}\n\n.user-header {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 1.25rem 1.5rem;\n cursor: pointer;\n background: var(--mj-bg-surface);\n transition: background-color 0.2s ease;\n}\n\n.user-header:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n@media (max-width: 639px) {\n .user-header {\n padding: 0.875rem 1rem;\n gap: 0.625rem;\n }\n}\n\n.user-selection {\n flex-shrink: 0;\n}\n\n.checkbox {\n width: 20px;\n height: 20px;\n cursor: pointer;\n accent-color: var(--mj-brand-primary);\n}\n\n.user-info {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n flex: 1;\n min-width: 0;\n}\n\n.user-avatar {\n width: 48px;\n height: 48px;\n border-radius: var(--mj-radius-full);\n background: linear-gradient(135deg, var(--mj-brand-primary) 0%, var(--mj-brand-primary-light) 100%);\n color: var(--mj-brand-on-primary);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 0.875rem;\n font-weight: 600;\n flex-shrink: 0;\n}\n\n@media (max-width: 639px) {\n .user-avatar {\n width: 40px;\n height: 40px;\n font-size: 0.8125rem;\n }\n\n .user-details {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n }\n\n .user-name {\n font-size: 0.9375rem;\n font-weight: 600;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .user-email {\n font-size: 0.8125rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n}\n\n.user-details {\n flex: 1;\n min-width: 0;\n}\n\n.user-name {\n font-size: 1rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.user-email {\n font-size: 0.875rem;\n color: var(--mj-text-secondary);\n margin: 0.125rem 0 0 0;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.user-meta {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n flex-shrink: 0;\n}\n\n@media (max-width: 767px) {\n .user-meta .status-badge,\n .user-meta .user-actions {\n display: none !important;\n }\n\n .user-meta {\n gap: 0;\n }\n}\n\n.desktop-only {\n display: none;\n}\n\n@media (min-width: 768px) {\n .desktop-only {\n display: flex;\n gap: 0.25rem;\n }\n}\n\n.user-actions {\n display: flex;\n gap: 0.25rem;\n}\n\n.user-card.expanded .expand-btn i {\n transform: rotate(180deg);\n}\n\n/* User Card Content - Expanded */\n.user-content {\n padding: 1.25rem 1.5rem;\n background: var(--mj-bg-page);\n border-top: 1px solid var(--mj-border-default);\n animation: slideDown 0.3s cubic-bezier(0, 0, 0.2, 1);\n}\n\n/* Mobile Actions Bar - visible on mobile */\n.mobile-actions-bar {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding-bottom: 1rem;\n margin-bottom: 1rem;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n@media (min-width: 768px) {\n .mobile-actions-bar {\n display: none;\n }\n}\n\n.mobile-action-buttons .btn-label {\n margin-left: 0.375rem;\n}\n\n/* User Stats in Expanded Content */\n.user-stats {\n display: flex;\n flex-wrap: wrap;\n gap: 1rem;\n margin-bottom: 1rem;\n}\n\n.user-stats .stat-item {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n font-size: 0.875rem;\n color: var(--mj-text-secondary);\n}\n\n.user-stats .stat-item i {\n color: var(--mj-brand-primary);\n font-size: 0.875rem;\n}\n\n.user-stats .stat-label {\n color: var(--mj-text-secondary);\n}\n\n.user-stats .stat-value {\n color: var(--mj-text-primary);\n font-weight: 500;\n display: flex;\n align-items: center;\n gap: 0.25rem;\n}\n\n.user-stats .stat-value i {\n font-size: 0.75rem;\n}\n\n/* Roles Section */\n.roles-section {\n padding-top: 1rem;\n border-top: 1px solid var(--mj-border-default);\n}\n\n.section-title {\n display: flex;\n align-items: center;\n gap: 0.625rem;\n font-size: 1rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0 0 0.75rem 0;\n}\n\n.section-title i {\n color: var(--mj-brand-primary);\n font-size: 1.125rem;\n}\n\n.roles-grid {\n display: flex;\n flex-wrap: wrap;\n gap: 0.5rem;\n}\n\n.role-item {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.375rem 0.875rem;\n background: var(--mj-color-warning-50);\n color: var(--mj-color-warning-800);\n border: 1px solid var(--mj-color-warning-500);\n border-radius: var(--mj-radius-full);\n font-size: 0.75rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.03em;\n}\n\n.role-item i {\n font-size: 0.625rem;\n}\n\n.no-roles {\n font-size: 0.875rem;\n color: var(--mj-text-secondary);\n margin: 0;\n}\n\n/* -----------------------------------------------------------------------------\n Error State Override - includes retry button\n ----------------------------------------------------------------------------- */\n.error-container .retry-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n padding: 0.75rem 1.5rem;\n font-size: 0.875rem;\n font-weight: 600;\n border: none;\n border-radius: var(--mj-radius-full);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n box-shadow: var(--mj-shadow-sm);\n min-height: 44px;\n}\n\n.error-container .retry-button:hover {\n background: var(--mj-brand-primary-light);\n box-shadow: var(--mj-shadow-md);\n}\n\n.error-container .retry-button:active {\n background: var(--mj-color-brand-400);\n transform: scale(0.98);\n}\n\n/* -----------------------------------------------------------------------------\n Form Field in Modal\n ----------------------------------------------------------------------------- */\n.form-field {\n margin-bottom: 1rem;\n}\n\n.form-field .field-label {\n display: block;\n font-size: 0.75rem;\n font-weight: 500;\n color: var(--mj-text-primary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin-bottom: 0.5rem;\n}\n\n.form-field .field-select {\n width: 100%;\n padding: 0.75rem 1rem;\n border: 1px solid var(--mj-color-neutral-400);\n border-radius: var(--mj-radius-md);\n background: var(--mj-bg-page);\n font-size: 1rem;\n color: var(--mj-text-primary);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.form-field .field-select:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px rgba(0, 118, 182, 0.2);\n}\n\n/* Accessibility override for user-specific elements */\n.checkbox:focus-visible,\n.user-header:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n/* -----------------------------------------------------------------------------\n Large Desktop (1440px+)\n ----------------------------------------------------------------------------- */\n@media (min-width: 1440px) {\n .bulk-action-toolbar {\n padding: 1.25rem 2rem;\n }\n\n .mj-grid-4 {\n gap: 1.5rem;\n padding: 0 2rem 1rem 2rem;\n }\n\n .scrollable-content {\n padding: 2rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Mobile (< 640px) - Compact adjustments\n ----------------------------------------------------------------------------- */\n@media (max-width: 639px) {\n .mj-grid-4 {\n grid-template-columns: repeat(2, 1fr);\n gap: 0.5rem;\n padding: 0 0.75rem 0.5rem 0.75rem;\n }\n\n .mj-card {\n padding: 0.75rem;\n gap: 0.75rem;\n }\n\n .stat-icon {\n width: 40px;\n height: 40px;\n font-size: 1.125rem;\n }\n\n .stat-content .stat-value {\n font-size: 1.5rem;\n }\n\n .stat-content .stat-label {\n font-size: 0.6875rem;\n }\n\n .scrollable-content {\n padding: 0.75rem;\n }\n\n .list-header {\n padding: 0.625rem 0.75rem;\n }\n\n .empty-state {\n padding: 2rem 1rem;\n }\n\n .empty-state .empty-icon {\n font-size: 3rem;\n }\n\n .empty-state .empty-text {\n font-size: 1.0625rem;\n }\n\n .empty-state .empty-subtext {\n font-size: 0.875rem;\n }\n}\n"] }]
|
|
1340
1233
|
}], () => [{ type: i0.ChangeDetectorRef }, { type: i0.NgZone }], null); })();
|
|
1341
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(UserManagementComponent, { className: "UserManagementComponent", filePath: "src/lib/user-management/user-management.component.ts", lineNumber:
|
|
1234
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(UserManagementComponent, { className: "UserManagementComponent", filePath: "src/lib/user-management/user-management.component.ts", lineNumber: 31 }); })();
|
|
1342
1235
|
//# sourceMappingURL=user-management.component.js.map
|