@memberjunction/ng-explorer-settings 2.70.0 → 2.72.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.
Files changed (38) hide show
  1. package/dist/lib/application-management/application-dialog/application-dialog.component.d.ts +60 -0
  2. package/dist/lib/application-management/application-dialog/application-dialog.component.d.ts.map +1 -0
  3. package/dist/lib/application-management/application-dialog/application-dialog.component.js +584 -0
  4. package/dist/lib/application-management/application-dialog/application-dialog.component.js.map +1 -0
  5. package/dist/lib/application-management/application-management.component.d.ts +4 -2
  6. package/dist/lib/application-management/application-management.component.d.ts.map +1 -1
  7. package/dist/lib/application-management/application-management.component.js +79 -35
  8. package/dist/lib/application-management/application-management.component.js.map +1 -1
  9. package/dist/lib/entity-permissions/entity-permissions.component.d.ts +3 -1
  10. package/dist/lib/entity-permissions/entity-permissions.component.d.ts.map +1 -1
  11. package/dist/lib/entity-permissions/entity-permissions.component.js +43 -66
  12. package/dist/lib/entity-permissions/entity-permissions.component.js.map +1 -1
  13. package/dist/lib/entity-permissions/permission-dialog/permission-dialog.component.d.ts +50 -0
  14. package/dist/lib/entity-permissions/permission-dialog/permission-dialog.component.d.ts.map +1 -0
  15. package/dist/lib/entity-permissions/permission-dialog/permission-dialog.component.js +464 -0
  16. package/dist/lib/entity-permissions/permission-dialog/permission-dialog.component.js.map +1 -0
  17. package/dist/lib/role-management/role-dialog/role-dialog.component.d.ts +38 -0
  18. package/dist/lib/role-management/role-dialog/role-dialog.component.d.ts.map +1 -0
  19. package/dist/lib/role-management/role-dialog/role-dialog.component.js +329 -0
  20. package/dist/lib/role-management/role-dialog/role-dialog.component.js.map +1 -0
  21. package/dist/lib/role-management/role-management.component.d.ts +4 -0
  22. package/dist/lib/role-management/role-management.component.d.ts.map +1 -1
  23. package/dist/lib/role-management/role-management.component.js +114 -72
  24. package/dist/lib/role-management/role-management.component.js.map +1 -1
  25. package/dist/lib/settings/settings.component.js +8 -8
  26. package/dist/lib/settings/settings.component.js.map +1 -1
  27. package/dist/lib/shared/components/settings-card/settings-card.component.d.ts.map +1 -1
  28. package/dist/lib/shared/components/settings-card/settings-card.component.js +11 -8
  29. package/dist/lib/shared/components/settings-card/settings-card.component.js.map +1 -1
  30. package/dist/lib/user-management/user-dialog/user-dialog.component.d.ts +44 -0
  31. package/dist/lib/user-management/user-dialog/user-dialog.component.d.ts.map +1 -0
  32. package/dist/lib/user-management/user-dialog/user-dialog.component.js +470 -0
  33. package/dist/lib/user-management/user-dialog/user-dialog.component.js.map +1 -0
  34. package/dist/lib/user-management/user-management.component.d.ts +9 -0
  35. package/dist/lib/user-management/user-management.component.d.ts.map +1 -1
  36. package/dist/lib/user-management/user-management.component.js +213 -98
  37. package/dist/lib/user-management/user-management.component.js.map +1 -1
  38. package/package.json +13 -13
@@ -3,8 +3,10 @@ import { CommonModule } from '@angular/common';
3
3
  import { FormsModule } from '@angular/forms';
4
4
  import { Subject, BehaviorSubject } from 'rxjs';
5
5
  import { takeUntil, debounceTime, distinctUntilChanged } from 'rxjs/operators';
6
- import { RunView } from '@memberjunction/core';
6
+ import { RunView, Metadata } from '@memberjunction/core';
7
7
  import { SharedSettingsModule } from '../shared/shared-settings.module';
8
+ import { UserDialogComponent } from './user-dialog/user-dialog.component';
9
+ import { WindowModule } from '@progress/kendo-angular-dialog';
8
10
  import * as i0 from "@angular/core";
9
11
  import * as i1 from "@angular/common";
10
12
  import * as i2 from "@angular/forms";
@@ -20,21 +22,21 @@ function UserManagementComponent_For_66_Template(rf, ctx) { if (rf & 1) {
20
22
  i0.ɵɵtextInterpolate(role_r1.Name);
21
23
  } }
22
24
  function UserManagementComponent_Conditional_72_Template(rf, ctx) { if (rf & 1) {
23
- i0.ɵɵelementStart(0, "div", 38)(1, "div", 42);
24
- i0.ɵɵelement(2, "div", 43)(3, "div", 43)(4, "div", 43);
25
+ i0.ɵɵelementStart(0, "div", 38)(1, "div", 43);
26
+ i0.ɵɵelement(2, "div", 44)(3, "div", 44)(4, "div", 44);
25
27
  i0.ɵɵelementEnd();
26
- i0.ɵɵelementStart(5, "div", 44);
28
+ i0.ɵɵelementStart(5, "div", 45);
27
29
  i0.ɵɵtext(6, "Loading users...");
28
30
  i0.ɵɵelementEnd()();
29
31
  } }
30
32
  function UserManagementComponent_Conditional_73_Template(rf, ctx) { if (rf & 1) {
31
33
  const _r2 = i0.ɵɵgetCurrentView();
32
- i0.ɵɵelementStart(0, "div", 39)(1, "div", 45);
33
- i0.ɵɵelement(2, "i", 46);
34
- i0.ɵɵelementStart(3, "p", 47);
34
+ i0.ɵɵelementStart(0, "div", 39)(1, "div", 46);
35
+ i0.ɵɵelement(2, "i", 47);
36
+ i0.ɵɵelementStart(3, "p", 48);
35
37
  i0.ɵɵtext(4);
36
38
  i0.ɵɵelementEnd();
37
- i0.ɵɵelementStart(5, "button", 48);
39
+ i0.ɵɵelementStart(5, "button", 49);
38
40
  i0.ɵɵlistener("click", function UserManagementComponent_Conditional_73_Template_button_click_5_listener() { i0.ɵɵrestoreView(_r2); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.loadInitialData()); });
39
41
  i0.ɵɵelement(6, "i", 3);
40
42
  i0.ɵɵtext(7, " Try Again ");
@@ -46,49 +48,49 @@ function UserManagementComponent_Conditional_73_Template(rf, ctx) { if (rf & 1)
46
48
  } }
47
49
  function UserManagementComponent_Conditional_74_Conditional_1_For_20_Template(rf, ctx) { if (rf & 1) {
48
50
  const _r4 = i0.ɵɵgetCurrentView();
49
- i0.ɵɵelementStart(0, "tr", 57);
51
+ i0.ɵɵelementStart(0, "tr", 58);
50
52
  i0.ɵɵlistener("click", function UserManagementComponent_Conditional_74_Conditional_1_For_20_Template_tr_click_0_listener() { const user_r5 = i0.ɵɵrestoreView(_r4).$implicit; const ctx_r2 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r2.selectUser(user_r5)); });
51
- i0.ɵɵelementStart(1, "td", 58);
53
+ i0.ɵɵelementStart(1, "td", 59);
52
54
  i0.ɵɵlistener("click", function UserManagementComponent_Conditional_74_Conditional_1_For_20_Template_td_click_1_listener($event) { i0.ɵɵrestoreView(_r4); return i0.ɵɵresetView($event.stopPropagation()); });
53
- i0.ɵɵelement(2, "input", 53);
55
+ i0.ɵɵelement(2, "input", 54);
54
56
  i0.ɵɵelementEnd();
55
- i0.ɵɵelementStart(3, "td")(4, "div", 59)(5, "div", 60);
57
+ i0.ɵɵelementStart(3, "td")(4, "div", 60)(5, "div", 61);
56
58
  i0.ɵɵtext(6);
57
59
  i0.ɵɵelementEnd();
58
- i0.ɵɵelementStart(7, "div", 61)(8, "div", 62);
60
+ i0.ɵɵelementStart(7, "div", 62)(8, "div", 63);
59
61
  i0.ɵɵtext(9);
60
62
  i0.ɵɵelementEnd();
61
- i0.ɵɵelementStart(10, "div", 63);
63
+ i0.ɵɵelementStart(10, "div", 64);
62
64
  i0.ɵɵtext(11);
63
65
  i0.ɵɵelementEnd()()()();
64
66
  i0.ɵɵelementStart(12, "td");
65
67
  i0.ɵɵtext(13);
66
68
  i0.ɵɵelementEnd();
67
- i0.ɵɵelementStart(14, "td")(15, "div", 64);
69
+ i0.ɵɵelementStart(14, "td")(15, "div", 65);
68
70
  i0.ɵɵelement(16, "i");
69
71
  i0.ɵɵtext(17);
70
72
  i0.ɵɵelementEnd()();
71
- i0.ɵɵelementStart(18, "td")(19, "span", 65);
73
+ i0.ɵɵelementStart(18, "td")(19, "span", 66);
72
74
  i0.ɵɵelement(20, "i");
73
75
  i0.ɵɵtext(21);
74
76
  i0.ɵɵelementEnd()();
75
- i0.ɵɵelementStart(22, "td")(23, "span", 66);
77
+ i0.ɵɵelementStart(22, "td")(23, "span", 67);
76
78
  i0.ɵɵtext(24);
77
79
  i0.ɵɵpipe(25, "date");
78
80
  i0.ɵɵelementEnd()();
79
- i0.ɵɵelementStart(26, "td", 67);
81
+ i0.ɵɵelementStart(26, "td", 68);
80
82
  i0.ɵɵlistener("click", function UserManagementComponent_Conditional_74_Conditional_1_For_20_Template_td_click_26_listener($event) { i0.ɵɵrestoreView(_r4); return i0.ɵɵresetView($event.stopPropagation()); });
81
- i0.ɵɵelementStart(27, "button", 68);
83
+ i0.ɵɵelementStart(27, "button", 69);
82
84
  i0.ɵɵlistener("click", function UserManagementComponent_Conditional_74_Conditional_1_For_20_Template_button_click_27_listener() { const user_r5 = i0.ɵɵrestoreView(_r4).$implicit; const ctx_r2 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r2.editUser(user_r5)); });
83
- i0.ɵɵelement(28, "i", 69);
85
+ i0.ɵɵelement(28, "i", 70);
84
86
  i0.ɵɵelementEnd();
85
- i0.ɵɵelementStart(29, "button", 70);
87
+ i0.ɵɵelementStart(29, "button", 71);
86
88
  i0.ɵɵlistener("click", function UserManagementComponent_Conditional_74_Conditional_1_For_20_Template_button_click_29_listener() { const user_r5 = i0.ɵɵrestoreView(_r4).$implicit; const ctx_r2 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r2.toggleUserStatus(user_r5)); });
87
89
  i0.ɵɵelement(30, "i");
88
90
  i0.ɵɵelementEnd();
89
- i0.ɵɵelementStart(31, "button", 71);
91
+ i0.ɵɵelementStart(31, "button", 72);
90
92
  i0.ɵɵlistener("click", function UserManagementComponent_Conditional_74_Conditional_1_For_20_Template_button_click_31_listener() { const user_r5 = i0.ɵɵrestoreView(_r4).$implicit; const ctx_r2 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r2.confirmDeleteUser(user_r5)); });
91
- i0.ɵɵelement(32, "i", 72);
93
+ i0.ɵɵelement(32, "i", 73);
92
94
  i0.ɵɵelementEnd()()();
93
95
  } if (rf & 2) {
94
96
  const user_r5 = ctx.$implicit;
@@ -119,18 +121,18 @@ function UserManagementComponent_Conditional_74_Conditional_1_For_20_Template(rf
119
121
  i0.ɵɵclassMap(user_r5.IsActive ? "fa-solid fa-toggle-on" : "fa-solid fa-toggle-off");
120
122
  } }
121
123
  function UserManagementComponent_Conditional_74_Conditional_1_Conditional_21_Template(rf, ctx) { if (rf & 1) {
122
- i0.ɵɵelementStart(0, "div", 56);
123
- i0.ɵɵelement(1, "i", 73);
124
- i0.ɵɵelementStart(2, "p", 74);
124
+ i0.ɵɵelementStart(0, "div", 57);
125
+ i0.ɵɵelement(1, "i", 74);
126
+ i0.ɵɵelementStart(2, "p", 75);
125
127
  i0.ɵɵtext(3, "No users found");
126
128
  i0.ɵɵelementEnd();
127
- i0.ɵɵelementStart(4, "p", 75);
129
+ i0.ɵɵelementStart(4, "p", 76);
128
130
  i0.ɵɵtext(5, "Try adjusting your filters or add a new user");
129
131
  i0.ɵɵelementEnd()();
130
132
  } }
131
133
  function UserManagementComponent_Conditional_74_Conditional_1_Template(rf, ctx) { if (rf & 1) {
132
- i0.ɵɵelementStart(0, "div", 49)(1, "table", 51)(2, "thead")(3, "tr")(4, "th", 52);
133
- i0.ɵɵelement(5, "input", 53);
134
+ i0.ɵɵelementStart(0, "div", 50)(1, "table", 52)(2, "thead")(3, "tr")(4, "th", 53);
135
+ i0.ɵɵelement(5, "input", 54);
134
136
  i0.ɵɵelementEnd();
135
137
  i0.ɵɵelementStart(6, "th");
136
138
  i0.ɵɵtext(7, "User");
@@ -147,13 +149,13 @@ function UserManagementComponent_Conditional_74_Conditional_1_Template(rf, ctx)
147
149
  i0.ɵɵelementStart(14, "th");
148
150
  i0.ɵɵtext(15, "Last Updated");
149
151
  i0.ɵɵelementEnd();
150
- i0.ɵɵelementStart(16, "th", 54);
152
+ i0.ɵɵelementStart(16, "th", 55);
151
153
  i0.ɵɵtext(17, "Actions");
152
154
  i0.ɵɵelementEnd()()();
153
155
  i0.ɵɵelementStart(18, "tbody");
154
- i0.ɵɵrepeaterCreate(19, UserManagementComponent_Conditional_74_Conditional_1_For_20_Template, 33, 20, "tr", 55, _forTrack0);
156
+ i0.ɵɵrepeaterCreate(19, UserManagementComponent_Conditional_74_Conditional_1_For_20_Template, 33, 20, "tr", 56, _forTrack0);
155
157
  i0.ɵɵelementEnd()();
156
- i0.ɵɵtemplate(21, UserManagementComponent_Conditional_74_Conditional_1_Conditional_21_Template, 6, 0, "div", 56);
158
+ i0.ɵɵtemplate(21, UserManagementComponent_Conditional_74_Conditional_1_Conditional_21_Template, 6, 0, "div", 57);
157
159
  i0.ɵɵelementEnd();
158
160
  } if (rf & 2) {
159
161
  const ctx_r2 = i0.ɵɵnextContext(2);
@@ -164,39 +166,39 @@ function UserManagementComponent_Conditional_74_Conditional_1_Template(rf, ctx)
164
166
  } }
165
167
  function UserManagementComponent_Conditional_74_Conditional_2_For_2_Template(rf, ctx) { if (rf & 1) {
166
168
  const _r6 = i0.ɵɵgetCurrentView();
167
- i0.ɵɵelementStart(0, "div", 77);
169
+ i0.ɵɵelementStart(0, "div", 78);
168
170
  i0.ɵɵlistener("click", function UserManagementComponent_Conditional_74_Conditional_2_For_2_Template_div_click_0_listener() { const user_r7 = i0.ɵɵrestoreView(_r6).$implicit; const ctx_r2 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r2.selectUser(user_r7)); });
169
- i0.ɵɵelementStart(1, "div", 78)(2, "div", 79);
171
+ i0.ɵɵelementStart(1, "div", 79)(2, "div", 80);
170
172
  i0.ɵɵtext(3);
171
173
  i0.ɵɵelementEnd();
172
- i0.ɵɵelementStart(4, "div", 80)(5, "button", 68);
174
+ i0.ɵɵelementStart(4, "div", 81)(5, "button", 69);
173
175
  i0.ɵɵlistener("click", function UserManagementComponent_Conditional_74_Conditional_2_For_2_Template_button_click_5_listener($event) { const user_r7 = i0.ɵɵrestoreView(_r6).$implicit; const ctx_r2 = i0.ɵɵnextContext(3); ctx_r2.editUser(user_r7); return i0.ɵɵresetView($event.stopPropagation()); });
174
- i0.ɵɵelement(6, "i", 69);
176
+ i0.ɵɵelement(6, "i", 70);
175
177
  i0.ɵɵelementEnd();
176
- i0.ɵɵelementStart(7, "button", 71);
178
+ i0.ɵɵelementStart(7, "button", 72);
177
179
  i0.ɵɵlistener("click", function UserManagementComponent_Conditional_74_Conditional_2_For_2_Template_button_click_7_listener($event) { const user_r7 = i0.ɵɵrestoreView(_r6).$implicit; const ctx_r2 = i0.ɵɵnextContext(3); ctx_r2.confirmDeleteUser(user_r7); return i0.ɵɵresetView($event.stopPropagation()); });
178
- i0.ɵɵelement(8, "i", 72);
180
+ i0.ɵɵelement(8, "i", 73);
179
181
  i0.ɵɵelementEnd()()();
180
- i0.ɵɵelementStart(9, "div", 81)(10, "h3", 62);
182
+ i0.ɵɵelementStart(9, "div", 82)(10, "h3", 63);
181
183
  i0.ɵɵtext(11);
182
184
  i0.ɵɵelementEnd();
183
- i0.ɵɵelementStart(12, "p", 63);
185
+ i0.ɵɵelementStart(12, "p", 64);
184
186
  i0.ɵɵtext(13);
185
187
  i0.ɵɵelementEnd();
186
- i0.ɵɵelementStart(14, "p", 82);
187
- i0.ɵɵelement(15, "i", 83);
188
+ i0.ɵɵelementStart(14, "p", 83);
189
+ i0.ɵɵelement(15, "i", 84);
188
190
  i0.ɵɵtext(16);
189
191
  i0.ɵɵelementEnd();
190
- i0.ɵɵelementStart(17, "div", 84)(18, "div", 85);
192
+ i0.ɵɵelementStart(17, "div", 85)(18, "div", 86);
191
193
  i0.ɵɵelement(19, "i");
192
194
  i0.ɵɵtext(20);
193
195
  i0.ɵɵelementEnd();
194
- i0.ɵɵelementStart(21, "span", 65);
196
+ i0.ɵɵelementStart(21, "span", 66);
195
197
  i0.ɵɵelement(22, "i");
196
198
  i0.ɵɵtext(23);
197
199
  i0.ɵɵelementEnd()();
198
- i0.ɵɵelementStart(24, "div", 86)(25, "div", 66);
199
- i0.ɵɵelement(26, "i", 87);
200
+ i0.ɵɵelementStart(24, "div", 87)(25, "div", 67);
201
+ i0.ɵɵelement(26, "i", 88);
200
202
  i0.ɵɵtext(27);
201
203
  i0.ɵɵpipe(28, "date");
202
204
  i0.ɵɵelementEnd()()()();
@@ -225,19 +227,19 @@ function UserManagementComponent_Conditional_74_Conditional_2_For_2_Template(rf,
225
227
  i0.ɵɵtextInterpolate1(" Last updated: ", user_r7.__mj_UpdatedAt ? i0.ɵɵpipeBind2(28, 14, user_r7.__mj_UpdatedAt, "short") : "Never", " ");
226
228
  } }
227
229
  function UserManagementComponent_Conditional_74_Conditional_2_Conditional_3_Template(rf, ctx) { if (rf & 1) {
228
- i0.ɵɵelementStart(0, "div", 56);
229
- i0.ɵɵelement(1, "i", 73);
230
- i0.ɵɵelementStart(2, "p", 74);
230
+ i0.ɵɵelementStart(0, "div", 57);
231
+ i0.ɵɵelement(1, "i", 74);
232
+ i0.ɵɵelementStart(2, "p", 75);
231
233
  i0.ɵɵtext(3, "No users found");
232
234
  i0.ɵɵelementEnd();
233
- i0.ɵɵelementStart(4, "p", 75);
235
+ i0.ɵɵelementStart(4, "p", 76);
234
236
  i0.ɵɵtext(5, "Try adjusting your filters or add a new user");
235
237
  i0.ɵɵelementEnd()();
236
238
  } }
237
239
  function UserManagementComponent_Conditional_74_Conditional_2_Template(rf, ctx) { if (rf & 1) {
238
- i0.ɵɵelementStart(0, "div", 50);
239
- i0.ɵɵrepeaterCreate(1, UserManagementComponent_Conditional_74_Conditional_2_For_2_Template, 29, 17, "div", 76, _forTrack0);
240
- i0.ɵɵtemplate(3, UserManagementComponent_Conditional_74_Conditional_2_Conditional_3_Template, 6, 0, "div", 56);
240
+ i0.ɵɵelementStart(0, "div", 51);
241
+ i0.ɵɵrepeaterCreate(1, UserManagementComponent_Conditional_74_Conditional_2_For_2_Template, 29, 17, "div", 77, _forTrack0);
242
+ i0.ɵɵtemplate(3, UserManagementComponent_Conditional_74_Conditional_2_Conditional_3_Template, 6, 0, "div", 57);
241
243
  i0.ɵɵelementEnd();
242
244
  } if (rf & 2) {
243
245
  const ctx_r2 = i0.ɵɵnextContext(2);
@@ -248,7 +250,7 @@ function UserManagementComponent_Conditional_74_Conditional_2_Template(rf, ctx)
248
250
  } }
249
251
  function UserManagementComponent_Conditional_74_Template(rf, ctx) { if (rf & 1) {
250
252
  i0.ɵɵelementStart(0, "div", 40);
251
- i0.ɵɵtemplate(1, UserManagementComponent_Conditional_74_Conditional_1_Template, 22, 1, "div", 49)(2, UserManagementComponent_Conditional_74_Conditional_2_Template, 4, 1, "div", 50);
253
+ i0.ɵɵtemplate(1, UserManagementComponent_Conditional_74_Conditional_1_Template, 22, 1, "div", 50)(2, UserManagementComponent_Conditional_74_Conditional_2_Template, 4, 1, "div", 51);
252
254
  i0.ɵɵelementEnd();
253
255
  } if (rf & 2) {
254
256
  const ctx_r2 = i0.ɵɵnextContext();
@@ -257,37 +259,37 @@ function UserManagementComponent_Conditional_74_Template(rf, ctx) { if (rf & 1)
257
259
  i0.ɵɵadvance();
258
260
  i0.ɵɵconditional(ctx_r2.viewMode === "cards" ? 2 : -1);
259
261
  } }
260
- function UserManagementComponent_Conditional_75_Template(rf, ctx) { if (rf & 1) {
262
+ function UserManagementComponent_Conditional_76_Template(rf, ctx) { if (rf & 1) {
261
263
  const _r8 = i0.ɵɵgetCurrentView();
262
- i0.ɵɵelementStart(0, "div", 88);
263
- i0.ɵɵlistener("click", function UserManagementComponent_Conditional_75_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r8); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.showDeleteConfirm = false); });
264
- i0.ɵɵelementStart(1, "div", 89);
265
- i0.ɵɵlistener("click", function UserManagementComponent_Conditional_75_Template_div_click_1_listener($event) { i0.ɵɵrestoreView(_r8); return i0.ɵɵresetView($event.stopPropagation()); });
266
- i0.ɵɵelementStart(2, "div", 90)(3, "h3", 91);
267
- i0.ɵɵelement(4, "i", 92);
264
+ i0.ɵɵelementStart(0, "div", 89);
265
+ i0.ɵɵlistener("click", function UserManagementComponent_Conditional_76_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r8); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.showDeleteConfirm = false); });
266
+ i0.ɵɵelementStart(1, "div", 90);
267
+ i0.ɵɵlistener("click", function UserManagementComponent_Conditional_76_Template_div_click_1_listener($event) { i0.ɵɵrestoreView(_r8); return i0.ɵɵresetView($event.stopPropagation()); });
268
+ i0.ɵɵelementStart(2, "div", 91)(3, "h3", 92);
269
+ i0.ɵɵelement(4, "i", 93);
268
270
  i0.ɵɵtext(5, " Confirm Delete ");
269
271
  i0.ɵɵelementEnd();
270
- i0.ɵɵelementStart(6, "button", 93);
271
- i0.ɵɵlistener("click", function UserManagementComponent_Conditional_75_Template_button_click_6_listener() { i0.ɵɵrestoreView(_r8); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.showDeleteConfirm = false); });
272
- i0.ɵɵelement(7, "i", 94);
272
+ i0.ɵɵelementStart(6, "button", 94);
273
+ i0.ɵɵlistener("click", function UserManagementComponent_Conditional_76_Template_button_click_6_listener() { i0.ɵɵrestoreView(_r8); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.showDeleteConfirm = false); });
274
+ i0.ɵɵelement(7, "i", 95);
273
275
  i0.ɵɵelementEnd()();
274
- i0.ɵɵelementStart(8, "div", 95)(9, "p");
276
+ i0.ɵɵelementStart(8, "div", 96)(9, "p");
275
277
  i0.ɵɵtext(10, "Are you sure you want to delete user ");
276
278
  i0.ɵɵelementStart(11, "strong");
277
279
  i0.ɵɵtext(12);
278
280
  i0.ɵɵelementEnd();
279
281
  i0.ɵɵtext(13, "?");
280
282
  i0.ɵɵelementEnd();
281
- i0.ɵɵelementStart(14, "p", 96);
283
+ i0.ɵɵelementStart(14, "p", 97);
282
284
  i0.ɵɵtext(15, "This action cannot be undone.");
283
285
  i0.ɵɵelementEnd()();
284
- i0.ɵɵelementStart(16, "div", 97)(17, "button", 4);
285
- i0.ɵɵlistener("click", function UserManagementComponent_Conditional_75_Template_button_click_17_listener() { i0.ɵɵrestoreView(_r8); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.showDeleteConfirm = false); });
286
+ i0.ɵɵelementStart(16, "div", 98)(17, "button", 4);
287
+ i0.ɵɵlistener("click", function UserManagementComponent_Conditional_76_Template_button_click_17_listener() { i0.ɵɵrestoreView(_r8); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.showDeleteConfirm = false); });
286
288
  i0.ɵɵtext(18, "Cancel");
287
289
  i0.ɵɵelementEnd();
288
- i0.ɵɵelementStart(19, "button", 98);
289
- i0.ɵɵlistener("click", function UserManagementComponent_Conditional_75_Template_button_click_19_listener() { i0.ɵɵrestoreView(_r8); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.deleteUser()); });
290
- i0.ɵɵelement(20, "i", 72);
290
+ i0.ɵɵelementStart(19, "button", 99);
291
+ i0.ɵɵlistener("click", function UserManagementComponent_Conditional_76_Template_button_click_19_listener() { i0.ɵɵrestoreView(_r8); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.deleteUser()); });
292
+ i0.ɵɵelement(20, "i", 73);
291
293
  i0.ɵɵtext(21, " Delete User ");
292
294
  i0.ɵɵelementEnd()()()();
293
295
  } if (rf & 2) {
@@ -303,6 +305,9 @@ export class UserManagementComponent {
303
305
  selectedUser = null;
304
306
  isLoading = false;
305
307
  error = null;
308
+ // Dialog state
309
+ showUserDialog = false;
310
+ userDialogData = null;
306
311
  // Stats
307
312
  stats = {
308
313
  totalUsers: 0,
@@ -321,6 +326,8 @@ export class UserManagementComponent {
321
326
  showEditDialog = false;
322
327
  showDeleteConfirm = false;
323
328
  viewMode = 'grid';
329
+ // User-Role mapping
330
+ userRoleMap = new Map(); // userId -> roleIds[]
324
331
  // Grid configuration
325
332
  gridConfig = {
326
333
  pageSize: 20,
@@ -328,6 +335,7 @@ export class UserManagementComponent {
328
335
  sortDirection: 'asc'
329
336
  };
330
337
  destroy$ = new Subject();
338
+ metadata = new Metadata();
331
339
  constructor() { }
332
340
  ngOnInit() {
333
341
  this.loadInitialData();
@@ -341,13 +349,16 @@ export class UserManagementComponent {
341
349
  try {
342
350
  this.isLoading = true;
343
351
  this.error = null;
344
- // Load users and roles in parallel
345
- const [users, roles] = await Promise.all([
352
+ // Load users, roles, and user-role relationships in parallel
353
+ const [users, roles, userRoles] = await Promise.all([
346
354
  this.loadUsers(),
347
- this.loadRoles()
355
+ this.loadRoles(),
356
+ this.loadUserRoles()
348
357
  ]);
349
358
  this.users = users;
350
359
  this.roles = roles;
360
+ // Build user-role mapping
361
+ this.buildUserRoleMapping(userRoles);
351
362
  this.calculateStats();
352
363
  this.applyFilters();
353
364
  }
@@ -376,6 +387,25 @@ export class UserManagementComponent {
376
387
  });
377
388
  return result.Success ? result.Results : [];
378
389
  }
390
+ async loadUserRoles() {
391
+ const rv = new RunView();
392
+ const result = await rv.RunView({
393
+ EntityName: 'User Roles',
394
+ ResultType: 'entity_object'
395
+ });
396
+ return result.Success ? result.Results : [];
397
+ }
398
+ buildUserRoleMapping(userRoles) {
399
+ this.userRoleMap.clear();
400
+ userRoles.forEach(userRole => {
401
+ const userId = userRole.UserID;
402
+ const roleId = userRole.RoleID;
403
+ if (!this.userRoleMap.has(userId)) {
404
+ this.userRoleMap.set(userId, []);
405
+ }
406
+ this.userRoleMap.get(userId).push(roleId);
407
+ });
408
+ }
379
409
  setupFilterSubscription() {
380
410
  this.filters$
381
411
  .pipe(debounceTime(300), distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b)), takeUntil(this.destroy$))
@@ -392,8 +422,10 @@ export class UserManagementComponent {
392
422
  }
393
423
  // Apply role filter
394
424
  if (filters.role) {
395
- // This would need to be implemented based on your user-role relationship
396
- // For now, we'll skip this filter
425
+ filtered = filtered.filter(user => {
426
+ const userRoles = this.userRoleMap.get(user.ID) || [];
427
+ return userRoles.includes(filters.role);
428
+ });
397
429
  }
398
430
  // Apply search filter
399
431
  if (filters.search) {
@@ -435,12 +467,19 @@ export class UserManagementComponent {
435
467
  this.showEditDialog = true;
436
468
  }
437
469
  createNewUser() {
438
- this.selectedUser = null;
439
- this.showCreateDialog = true;
470
+ this.userDialogData = {
471
+ mode: 'create',
472
+ availableRoles: this.roles
473
+ };
474
+ this.showUserDialog = true;
440
475
  }
441
476
  editUser(user) {
442
- this.selectedUser = user;
443
- this.showEditDialog = true;
477
+ this.userDialogData = {
478
+ user: user,
479
+ mode: 'edit',
480
+ availableRoles: this.roles
481
+ };
482
+ this.showUserDialog = true;
444
483
  }
445
484
  confirmDeleteUser(user) {
446
485
  this.selectedUser = user;
@@ -450,13 +489,27 @@ export class UserManagementComponent {
450
489
  if (!this.selectedUser)
451
490
  return;
452
491
  try {
453
- // Implement user deletion logic
454
- this.showDeleteConfirm = false;
455
- await this.loadInitialData();
492
+ // Load user entity to delete
493
+ const user = await this.metadata.GetEntityObject('Users');
494
+ const loadResult = await user.Load(this.selectedUser.ID);
495
+ if (loadResult) {
496
+ const deleteResult = await user.Delete();
497
+ if (deleteResult) {
498
+ this.showDeleteConfirm = false;
499
+ this.selectedUser = null;
500
+ await this.loadInitialData();
501
+ }
502
+ else {
503
+ throw new Error(user.LatestResult?.Message || 'Failed to delete user');
504
+ }
505
+ }
506
+ else {
507
+ throw new Error('User not found or permission denied');
508
+ }
456
509
  }
457
510
  catch (error) {
458
511
  console.error('Error deleting user:', error);
459
- this.error = 'Failed to delete user';
512
+ this.error = error.message || 'Failed to delete user';
460
513
  }
461
514
  }
462
515
  async toggleUserStatus(user) {
@@ -474,8 +527,52 @@ export class UserManagementComponent {
474
527
  this.viewMode = this.viewMode === 'grid' ? 'cards' : 'grid';
475
528
  }
476
529
  exportUsers() {
477
- // Implement export functionality
478
- console.log('Export users');
530
+ if (this.filteredUsers.length === 0) {
531
+ this.error = 'No users to export';
532
+ return;
533
+ }
534
+ try {
535
+ // Create CSV content
536
+ const headers = ['Name', 'First Name', 'Last Name', 'Email', 'Type', 'Status', 'Created', 'Updated'];
537
+ const csvRows = [headers.join(',')];
538
+ // Add user data
539
+ this.filteredUsers.forEach(user => {
540
+ const row = [
541
+ this.escapeCSV(user.Name || ''),
542
+ this.escapeCSV(user.FirstName || ''),
543
+ this.escapeCSV(user.LastName || ''),
544
+ this.escapeCSV(user.Email || ''),
545
+ this.escapeCSV(user.Type || ''),
546
+ user.IsActive ? 'Active' : 'Inactive',
547
+ user.__mj_CreatedAt ? new Date(user.__mj_CreatedAt).toLocaleDateString() : '',
548
+ user.__mj_UpdatedAt ? new Date(user.__mj_UpdatedAt).toLocaleDateString() : ''
549
+ ];
550
+ csvRows.push(row.join(','));
551
+ });
552
+ // Create and download file
553
+ const csvContent = csvRows.join('\n');
554
+ const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
555
+ const link = document.createElement('a');
556
+ if (link.download !== undefined) {
557
+ const url = URL.createObjectURL(blob);
558
+ link.setAttribute('href', url);
559
+ link.setAttribute('download', `users_export_${new Date().toISOString().split('T')[0]}.csv`);
560
+ link.style.visibility = 'hidden';
561
+ document.body.appendChild(link);
562
+ link.click();
563
+ document.body.removeChild(link);
564
+ }
565
+ }
566
+ catch (error) {
567
+ console.error('Error exporting users:', error);
568
+ this.error = 'Failed to export users';
569
+ }
570
+ }
571
+ escapeCSV(value) {
572
+ if (value.includes(',') || value.includes('"') || value.includes('\n')) {
573
+ return `"${value.replace(/"/g, '""')}"`;
574
+ }
575
+ return value;
479
576
  }
480
577
  refreshData() {
481
578
  this.loadInitialData();
@@ -501,8 +598,16 @@ export class UserManagementComponent {
501
598
  const last = user.LastName?.charAt(0) || '';
502
599
  return (first + last).toUpperCase() || user.Name?.charAt(0).toUpperCase() || 'U';
503
600
  }
601
+ onUserDialogResult(result) {
602
+ this.showUserDialog = false;
603
+ this.userDialogData = null;
604
+ if (result.action === 'save') {
605
+ // Refresh the user list to show changes
606
+ this.loadInitialData();
607
+ }
608
+ }
504
609
  static ɵfac = function UserManagementComponent_Factory(t) { return new (t || UserManagementComponent)(); };
505
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: UserManagementComponent, selectors: [["mj-user-management"]], standalone: true, features: [i0.ɵɵStandaloneFeature], decls: 76, vars: 22, consts: [[1, "user-management-container"], [1, "action-buttons"], [1, "btn-secondary", 3, "click", "disabled"], [1, "fa-solid", "fa-refresh"], [1, "btn-secondary", 3, "click"], [1, "fa-solid", "fa-download"], [1, "btn-primary", 3, "click"], [1, "fa-solid", "fa-plus"], [1, "stats-grid", 2, "display", "flex"], [1, "stat-card"], [1, "stat-icon", "stat-icon-total"], [1, "fa-solid", "fa-users"], [1, "stat-content"], [1, "stat-value"], [1, "stat-label"], [1, "stat-icon", "stat-icon-active"], [1, "fa-solid", "fa-user-check"], [1, "stat-icon", "stat-icon-inactive"], [1, "fa-solid", "fa-user-xmark"], [1, "stat-icon", "stat-icon-admin"], [1, "fa-solid", "fa-shield-halved"], [1, "filters-section"], [1, "filters-row"], [1, "search-container"], [1, "fa-solid", "fa-search", "search-icon"], ["type", "text", "placeholder", "Search users by name or email...", 1, "search-input", 3, "input", "value"], [1, "filter-group"], [1, "filter-label"], [1, "filter-buttons"], [1, "filter-btn", 3, "click"], [1, "filter-select", 3, "change"], ["value", ""], [3, "value"], [1, "view-toggle"], ["title", "Grid View", 1, "view-btn", 3, "click"], [1, "fa-solid", "fa-table"], ["title", "Card View", 1, "view-btn", 3, "click"], [1, "fa-solid", "fa-th-large"], [1, "loading-container"], [1, "error-container"], [1, "content-area"], [1, "modal-backdrop"], [1, "loading-spinner"], [1, "spinner-ring"], [1, "loading-text"], [1, "error-content"], [1, "fa-solid", "fa-exclamation-triangle", "error-icon"], [1, "error-message"], [1, "retry-button", 3, "click"], [1, "users-table"], [1, "users-grid"], [1, "modern-table"], [1, "th-checkbox"], ["type", "checkbox", 1, "checkbox"], [1, "th-actions"], [1, "table-row"], [1, "empty-state"], [1, "table-row", 3, "click"], [1, "td-checkbox", 3, "click"], [1, "user-cell"], [1, "user-avatar"], [1, "user-info"], [1, "user-name"], [1, "user-fullname"], [1, "user-type"], [1, "status-badge"], [1, "last-login"], [1, "td-actions", 3, "click"], ["title", "Edit", 1, "action-btn", 3, "click"], [1, "fa-solid", "fa-edit"], [1, "action-btn", 3, "click", "title"], ["title", "Delete", 1, "action-btn", "action-btn-danger", 3, "click"], [1, "fa-solid", "fa-trash"], [1, "fa-solid", "fa-users-slash", "empty-icon"], [1, "empty-text"], [1, "empty-subtext"], [1, "user-card"], [1, "user-card", 3, "click"], [1, "card-header"], [1, "user-avatar-large"], [1, "card-actions"], [1, "card-body"], [1, "user-email"], [1, "fa-solid", "fa-envelope"], [1, "card-meta"], [1, "meta-item"], [1, "card-footer"], [1, "fa-solid", "fa-clock"], [1, "modal-backdrop", 3, "click"], [1, "modal-dialog", 3, "click"], [1, "modal-header"], [1, "modal-title"], [1, "fa-solid", "fa-exclamation-triangle", "text-danger"], [1, "modal-close", 3, "click"], [1, "fa-solid", "fa-times"], [1, "modal-body"], [1, "text-muted"], [1, "modal-footer"], [1, "btn-danger", 3, "click"]], template: function UserManagementComponent_Template(rf, ctx) { if (rf & 1) {
610
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: UserManagementComponent, selectors: [["mj-user-management"]], standalone: true, features: [i0.ɵɵStandaloneFeature], decls: 77, vars: 28, consts: [[1, "user-management-container"], [1, "action-buttons"], [1, "mj-btn", "mj-btn-secondary", 3, "click", "disabled"], [1, "fa-solid", "fa-refresh"], [1, "mj-btn", "mj-btn-secondary", 3, "click"], [1, "fa-solid", "fa-download"], [1, "mj-btn", "mj-btn-primary", 3, "click"], [1, "fa-solid", "fa-plus"], [1, "mj-grid", "mj-grid-4"], [1, "mj-card"], [1, "stat-icon", "stat-icon-total"], [1, "fa-solid", "fa-users"], [1, "stat-content"], [1, "stat-value"], [1, "stat-label"], [1, "stat-icon", "stat-icon-active"], [1, "fa-solid", "fa-user-check"], [1, "stat-icon", "stat-icon-inactive"], [1, "fa-solid", "fa-user-xmark"], [1, "stat-icon", "stat-icon-admin"], [1, "fa-solid", "fa-shield-halved"], [1, "filters-section"], [1, "filters-row"], [1, "search-container"], [1, "fa-solid", "fa-search", "search-icon"], ["type", "text", "placeholder", "Search users by name or email...", 1, "search-input", 3, "input", "value"], [1, "filter-group"], [1, "filter-label"], [1, "filter-buttons"], [1, "mj-btn", "mj-btn-ghost", 3, "click"], [1, "filter-select", 3, "change"], ["value", ""], [3, "value"], [1, "view-toggle"], ["title", "Grid View", 1, "mj-btn", "mj-btn-icon-only", 3, "click"], [1, "fa-solid", "fa-table"], ["title", "Card View", 1, "mj-btn", "mj-btn-icon-only", 3, "click"], [1, "fa-solid", "fa-th-large"], [1, "loading-container"], [1, "error-container"], [1, "content-area"], [3, "result", "data", "visible"], [1, "modal-backdrop"], [1, "loading-spinner"], [1, "spinner-ring"], [1, "loading-text"], [1, "error-content"], [1, "fa-solid", "fa-exclamation-triangle", "error-icon"], [1, "error-message"], [1, "retry-button", 3, "click"], [1, "users-table"], [1, "users-grid"], [1, "modern-table"], [1, "th-checkbox"], ["type", "checkbox", 1, "checkbox"], [1, "th-actions"], [1, "table-row"], [1, "empty-state"], [1, "table-row", 3, "click"], [1, "td-checkbox", 3, "click"], [1, "user-cell"], [1, "user-avatar"], [1, "user-info"], [1, "user-name"], [1, "user-fullname"], [1, "user-type"], [1, "status-badge"], [1, "last-login"], [1, "td-actions", 3, "click"], ["title", "Edit", 1, "mj-btn", "mj-btn-ghost", "mj-btn-sm", 3, "click"], [1, "fa-solid", "fa-edit"], [1, "mj-btn", "mj-btn-ghost", "mj-btn-sm", 3, "click", "title"], ["title", "Delete", 1, "mj-btn", "mj-btn-ghost", "mj-btn-sm", "text-danger", 3, "click"], [1, "fa-solid", "fa-trash"], [1, "fa-solid", "fa-users-slash", "empty-icon"], [1, "empty-text"], [1, "empty-subtext"], [1, "user-card"], [1, "user-card", 3, "click"], [1, "card-header"], [1, "user-avatar-large"], [1, "card-actions"], [1, "card-body"], [1, "user-email"], [1, "fa-solid", "fa-envelope"], [1, "card-meta"], [1, "meta-item"], [1, "card-footer"], [1, "fa-solid", "fa-clock"], [1, "modal-backdrop", 3, "click"], [1, "modal-dialog", 3, "click"], [1, "modal-header"], [1, "modal-title"], [1, "fa-solid", "fa-exclamation-triangle", "text-danger"], [1, "modal-close", 3, "click"], [1, "fa-solid", "fa-times"], [1, "modal-body"], [1, "text-muted"], [1, "modal-footer"], [1, "mj-btn", "mj-btn-primary", "text-danger", 3, "click"]], template: function UserManagementComponent_Template(rf, ctx) { if (rf & 1) {
506
611
  i0.ɵɵelementStart(0, "div", 0)(1, "div", 1)(2, "button", 2);
507
612
  i0.ɵɵlistener("click", function UserManagementComponent_Template_button_click_2_listener() { return ctx.refreshData(); });
508
613
  i0.ɵɵelement(3, "i", 3);
@@ -592,7 +697,11 @@ export class UserManagementComponent {
592
697
  i0.ɵɵlistener("click", function UserManagementComponent_Template_button_click_70_listener() { return ctx.viewMode = "cards"; });
593
698
  i0.ɵɵelement(71, "i", 37);
594
699
  i0.ɵɵelementEnd()()()();
595
- i0.ɵɵtemplate(72, UserManagementComponent_Conditional_72_Template, 7, 0, "div", 38)(73, UserManagementComponent_Conditional_73_Template, 8, 1, "div", 39)(74, UserManagementComponent_Conditional_74_Template, 3, 2, "div", 40)(75, UserManagementComponent_Conditional_75_Template, 22, 1, "div", 41);
700
+ i0.ɵɵtemplate(72, UserManagementComponent_Conditional_72_Template, 7, 0, "div", 38)(73, UserManagementComponent_Conditional_73_Template, 8, 1, "div", 39)(74, UserManagementComponent_Conditional_74_Template, 3, 2, "div", 40);
701
+ i0.ɵɵelementStart(75, "mj-user-dialog", 41);
702
+ i0.ɵɵlistener("result", function UserManagementComponent_Template_mj_user_dialog_result_75_listener($event) { return ctx.onUserDialogResult($event); });
703
+ i0.ɵɵelementEnd();
704
+ i0.ɵɵtemplate(76, UserManagementComponent_Conditional_76_Template, 22, 1, "div", 42);
596
705
  i0.ɵɵelementEnd();
597
706
  } if (rf & 2) {
598
707
  i0.ɵɵadvance(2);
@@ -610,17 +719,17 @@ export class UserManagementComponent {
610
719
  i0.ɵɵadvance(7);
611
720
  i0.ɵɵproperty("value", ctx.filters$.value.search);
612
721
  i0.ɵɵadvance(5);
613
- i0.ɵɵclassProp("active", ctx.filters$.value.status === "all");
722
+ i0.ɵɵclassProp("mj-btn-primary", ctx.filters$.value.status === "all");
614
723
  i0.ɵɵadvance(2);
615
- i0.ɵɵclassProp("active", ctx.filters$.value.status === "active");
724
+ i0.ɵɵclassProp("mj-btn-primary", ctx.filters$.value.status === "active");
616
725
  i0.ɵɵadvance(2);
617
- i0.ɵɵclassProp("active", ctx.filters$.value.status === "inactive");
726
+ i0.ɵɵclassProp("mj-btn-primary", ctx.filters$.value.status === "inactive");
618
727
  i0.ɵɵadvance(8);
619
728
  i0.ɵɵrepeater(ctx.roles);
620
729
  i0.ɵɵadvance(3);
621
- i0.ɵɵclassProp("active", ctx.viewMode === "grid");
730
+ i0.ɵɵclassProp("mj-btn-primary", ctx.viewMode === "grid")("mj-btn-ghost", ctx.viewMode !== "grid");
622
731
  i0.ɵɵadvance(2);
623
- i0.ɵɵclassProp("active", ctx.viewMode === "cards");
732
+ i0.ɵɵclassProp("mj-btn-primary", ctx.viewMode === "cards")("mj-btn-ghost", ctx.viewMode !== "cards");
624
733
  i0.ɵɵadvance(2);
625
734
  i0.ɵɵconditional(ctx.isLoading ? 72 : -1);
626
735
  i0.ɵɵadvance();
@@ -628,16 +737,22 @@ export class UserManagementComponent {
628
737
  i0.ɵɵadvance();
629
738
  i0.ɵɵconditional(!ctx.isLoading && !ctx.error ? 74 : -1);
630
739
  i0.ɵɵadvance();
631
- i0.ɵɵconditional(ctx.showDeleteConfirm && ctx.selectedUser ? 75 : -1);
632
- } }, dependencies: [CommonModule, i1.DatePipe, FormsModule, i2.NgSelectOption, i2.ɵNgSelectMultipleOption, SharedSettingsModule], styles: ["@import '../shared/styles/variables';\n@import '../shared/styles/mixins';\n\n.user-management-container[_ngcontent-%COMP%] {\n @include scrollable-container;\n max-width: 1400px;\n margin: 0 auto;\n padding: 2rem;\n}\n\n//[_ngcontent-%COMP%] Action[_ngcontent-%COMP%] Buttons\n.action-buttons[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.75rem;\n justify-content: flex-end;\n margin-bottom: 1.5rem;\n\n @media (max-width: 768px) {\n justify-content: center;\n flex-wrap: wrap;\n }\n}\n\n//[_ngcontent-%COMP%] Buttons\n.btn-primary[_ngcontent-%COMP%] {\n @include button-base;\n background-color: #2196f3;\n color: white;\n \n &:hover {\n background-color: #1976d2;\n transform: translateY(-1px);\n box-shadow: 0 4px 12px rgba(33, 150, 243, 0.3);\n }\n\n &:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n transform: none;\n }\n}\n\n.btn-secondary[_ngcontent-%COMP%] {\n @include button-base;\n background-color: #ffffff;\n color: #374151;\n border: 1px solid #e5e7eb;\n \n &:hover {\n background-color: #f9fafb;\n border-color: #2196f3;\n color: #2196f3;\n }\n}\n\n.btn-danger[_ngcontent-%COMP%] {\n @include button-base;\n background-color: #f44336;\n color: white;\n \n &:hover {\n background-color: #d32f2f;\n }\n}\n\n//[_ngcontent-%COMP%] Stats[_ngcontent-%COMP%] Grid\n.stats-grid[_ngcontent-%COMP%] {\n display: grid !important;\n grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));\n gap: 1.5rem;\n margin-bottom: 2rem;\n width: 100%;\n\n @media (max-width: 768px) {\n grid-template-columns: repeat(2, 1fr);\n gap: 1rem;\n }\n}\n\n.stat-card[_ngcontent-%COMP%] {\n background: white;\n border-radius: 12px;\n padding: 1.5rem;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n display: flex;\n margin-right: 10px;\n align-items: center;\n gap: 1rem;\n transition: all 0.3s ease;\n min-width: 0; // Prevent grid blowout\n\n &:hover {\n transform: translateY(-2px);\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);\n }\n}\n\n.stat-icon[_ngcontent-%COMP%] {\n width: 60px;\n height: 60px;\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 1.5rem;\n\n &-total {\n background: rgba(33, 150, 243, 0.1);\n color: #2196f3;\n }\n\n &-active {\n background: rgba(76, 175, 80, 0.1);\n color: #4caf50;\n }\n\n &-inactive {\n background: rgba(244, 67, 54, 0.1);\n color: #f44336;\n }\n\n &-admin {\n background: rgba(156, 39, 176, 0.1);\n color: #9c27b0;\n }\n}\n\n.stat-content[_ngcontent-%COMP%] {\n flex: 1;\n\n .stat-value {\n font-size: 2rem;\n font-weight: 700;\n color: #1f2937;\n line-height: 1;\n }\n\n .stat-label {\n color: #6b7280;\n font-size: 0.875rem;\n margin-top: 0.25rem;\n }\n}\n\n//[_ngcontent-%COMP%] Filters[_ngcontent-%COMP%] Section\n.filters-section[_ngcontent-%COMP%] {\n background: white;\n border-radius: 12px;\n padding: 1.5rem;\n margin-bottom: 1.5rem;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n}\n\n.filters-row[_ngcontent-%COMP%] {\n display: flex;\n gap: 1.5rem;\n align-items: flex-end;\n flex-wrap: wrap;\n\n @media (max-width: 768px) {\n gap: 1rem;\n }\n}\n\n.search-container[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 250px;\n position: relative;\n\n .search-icon {\n position: absolute;\n left: 1rem;\n top: 50%;\n transform: translateY(-50%);\n color: #6b7280;\n font-size: 1rem;\n }\n\n .search-input {\n width: 100%;\n padding: 0.75rem 1rem 0.75rem 2.75rem;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n font-size: 0.95rem;\n transition: all 0.2s;\n\n &:focus {\n outline: none;\n border-color: #2196f3;\n box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1);\n }\n }\n}\n\n.filter-group[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n\n .filter-label {\n font-size: 0.875rem;\n font-weight: 500;\n color: #374151;\n }\n\n .filter-buttons {\n display: flex;\n background: #f3f4f6;\n border-radius: 8px;\n padding: 4px;\n }\n\n .filter-btn {\n padding: 0.5rem 1rem;\n border: none;\n background: transparent;\n color: #6b7280;\n font-size: 0.875rem;\n font-weight: 500;\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s;\n\n &:hover {\n color: #374151;\n }\n\n &.active {\n background: white;\n color: #2196f3;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n }\n }\n\n .filter-select {\n padding: 0.625rem 1rem;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n background: white;\n font-size: 0.875rem;\n color: #374151;\n cursor: pointer;\n transition: all 0.2s;\n\n &:focus {\n outline: none;\n border-color: #2196f3;\n box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1);\n }\n }\n}\n\n.view-toggle[_ngcontent-%COMP%] {\n display: flex;\n background: #f3f4f6;\n border-radius: 8px;\n padding: 4px;\n\n .view-btn {\n padding: 0.5rem 0.75rem;\n border: none;\n background: transparent;\n color: #6b7280;\n font-size: 1rem;\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s;\n\n &:hover {\n color: #374151;\n }\n\n &.active {\n background: white;\n color: #2196f3;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n }\n }\n}\n\n//[_ngcontent-%COMP%] Content[_ngcontent-%COMP%] Area\n.content-area[_ngcontent-%COMP%] {\n @include scrollable-content;\n background: white;\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n overflow: hidden;\n}\n\n//[_ngcontent-%COMP%] Table[_ngcontent-%COMP%] View\n.users-table[_ngcontent-%COMP%] {\n overflow-x: auto;\n max-height: calc(100vh - 450px); // Dynamic height\n overflow-y: auto;\n}\n\n.modern-table[_ngcontent-%COMP%] {\n width: 100%;\n border-collapse: collapse;\n\n thead {\n background: #f9fafb;\n border-bottom: 1px solid #e5e7eb;\n\n th {\n padding: 1rem;\n text-align: left;\n font-size: 0.875rem;\n font-weight: 600;\n color: #374151;\n white-space: nowrap;\n\n &.th-checkbox {\n width: 50px;\n }\n\n &.th-actions {\n text-align: center;\n width: 150px;\n }\n }\n }\n\n tbody {\n tr {\n border-bottom: 1px solid #f3f4f6;\n transition: background-color 0.2s;\n cursor: pointer;\n\n &:hover {\n background-color: #f9fafb;\n }\n }\n\n td {\n padding: 1rem;\n font-size: 0.875rem;\n color: #374151;\n\n &.td-checkbox {\n width: 50px;\n }\n\n &.td-actions {\n text-align: center;\n }\n }\n }\n}\n\n.checkbox[_ngcontent-%COMP%] {\n width: 18px;\n height: 18px;\n cursor: pointer;\n}\n\n.user-cell[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n}\n\n.user-avatar[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n border-radius: 50%;\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n display: flex;\n align-items: center;\n justify-content: center;\n font-weight: 600;\n font-size: 0.875rem;\n}\n\n.user-avatar-large[_ngcontent-%COMP%] {\n width: 80px;\n height: 80px;\n border-radius: 50%;\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n display: flex;\n align-items: center;\n justify-content: center;\n font-weight: 600;\n font-size: 1.5rem;\n margin: 0 auto 1rem;\n}\n\n.user-info[_ngcontent-%COMP%] {\n .user-name {\n font-weight: 600;\n color: #1f2937;\n }\n\n .user-fullname {\n font-size: 0.75rem;\n color: #6b7280;\n }\n}\n\n.user-type[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 0.5rem;\n color: #4b5563;\n\n i {\n font-size: 0.875rem;\n }\n}\n\n.status-badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.25rem 0.75rem;\n border-radius: 20px;\n font-size: 0.75rem;\n font-weight: 500;\n\n &.status-active {\n background: rgba(76, 175, 80, 0.1);\n color: #388e3c;\n }\n\n &.status-inactive {\n background: rgba(244, 67, 54, 0.1);\n color: #d32f2f;\n }\n\n i {\n font-size: 0.625rem;\n }\n}\n\n.last-login[_ngcontent-%COMP%] {\n color: #6b7280;\n font-size: 0.875rem;\n}\n\n.action-btn[_ngcontent-%COMP%] {\n padding: 0.5rem;\n border: none;\n background: transparent;\n color: #6b7280;\n font-size: 1rem;\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s;\n\n &:hover {\n background: #f3f4f6;\n color: #2196f3;\n }\n\n &-danger:hover {\n color: #f44336;\n }\n}\n\n//[_ngcontent-%COMP%] Card[_ngcontent-%COMP%] View\n.users-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));\n gap: 1.5rem;\n padding: 1.5rem;\n\n @media (max-width: 768px) {\n grid-template-columns: 1fr;\n gap: 1rem;\n padding: 1rem;\n }\n}\n\n.user-card[_ngcontent-%COMP%] {\n background: white;\n border: 1px solid #e5e7eb;\n border-radius: 12px;\n padding: 1.5rem;\n cursor: pointer;\n transition: all 0.3s ease;\n\n &:hover {\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);\n transform: translateY(-2px);\n border-color: #2196f3;\n }\n}\n\n.card-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 1rem;\n}\n\n.card-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.5rem;\n}\n\n.card-body[_ngcontent-%COMP%] {\n text-align: center;\n\n .user-name {\n font-size: 1.25rem;\n font-weight: 600;\n color: #1f2937;\n margin: 0 0 0.25rem 0;\n }\n\n .user-fullname {\n color: #6b7280;\n margin: 0 0 0.75rem 0;\n }\n\n .user-email {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n color: #4b5563;\n font-size: 0.875rem;\n margin-bottom: 1rem;\n\n i {\n color: #6b7280;\n }\n }\n}\n\n.card-meta[_ngcontent-%COMP%] {\n display: flex;\n justify-content: center;\n align-items: center;\n gap: 1rem;\n padding: 1rem 0;\n border-top: 1px solid #f3f4f6;\n border-bottom: 1px solid #f3f4f6;\n margin-bottom: 1rem;\n\n .meta-item {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n color: #4b5563;\n font-size: 0.875rem;\n }\n}\n\n.card-footer[_ngcontent-%COMP%] {\n .last-login {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0.375rem;\n color: #6b7280;\n font-size: 0.75rem;\n\n i {\n font-size: 0.875rem;\n }\n }\n}\n\n//[_ngcontent-%COMP%] Empty[_ngcontent-%COMP%] State\n.empty-state[_ngcontent-%COMP%] {\n text-align: center;\n padding: 4rem 2rem;\n\n .empty-icon {\n font-size: 4rem;\n color: #e5e7eb;\n margin-bottom: 1rem;\n }\n\n .empty-text {\n font-size: 1.25rem;\n font-weight: 600;\n color: #374151;\n margin: 0 0 0.5rem 0;\n }\n\n .empty-subtext {\n color: #6b7280;\n margin: 0;\n }\n}\n\n//[_ngcontent-%COMP%] Loading[_ngcontent-%COMP%] State\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.loading-spinner[_ngcontent-%COMP%] {\n position: relative;\n width: 60px;\n height: 60px;\n margin-bottom: 1rem;\n\n .spinner-ring {\n position: absolute;\n width: 100%;\n height: 100%;\n border: 3px solid transparent;\n border-radius: 50%;\n animation: _ngcontent-%COMP%_spin 1.5s cubic-bezier(0.5, 0, 0.5, 1) infinite;\n\n &:nth-child(1) {\n border-color: #2196f3 transparent transparent transparent;\n animation-delay: -0.45s;\n }\n\n &:nth-child(2) {\n border-color: transparent #4caf50 transparent transparent;\n animation-delay: -0.3s;\n }\n\n &:nth-child(3) {\n border-color: transparent transparent #ff9800 transparent;\n animation-delay: -0.15s;\n }\n }\n}\n\n@keyframes _ngcontent-%COMP%_spin {\n 0% {\n transform: rotate(0deg);\n }\n 100% {\n transform: rotate(360deg);\n }\n}\n\n.loading-text[_ngcontent-%COMP%] {\n color: #6b7280;\n font-size: 0.95rem;\n}\n\n//[_ngcontent-%COMP%] Error[_ngcontent-%COMP%] State\n.error-container[_ngcontent-%COMP%] {\n text-align: center;\n padding: 4rem 2rem;\n\n .error-icon {\n font-size: 3rem;\n color: #f44336;\n margin-bottom: 1rem;\n }\n\n .error-message {\n color: #374151;\n margin-bottom: 1.5rem;\n }\n\n .retry-button {\n @include button-base;\n background-color: #2196f3;\n color: white;\n }\n}\n\n//[_ngcontent-%COMP%] Modal[_ngcontent-%COMP%] Styles\n.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.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n animation: fadeIn 0.2s ease;\n}\n\n.modal-dialog[_ngcontent-%COMP%] {\n background: white;\n border-radius: 12px;\n box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);\n max-width: 500px;\n width: 90%;\n max-height: 90vh;\n overflow: hidden;\n animation: _ngcontent-%COMP%_slideUp 0.3s ease;\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 #e5e7eb;\n\n .modal-title {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n font-size: 1.25rem;\n font-weight: 600;\n color: #1f2937;\n margin: 0;\n }\n\n .modal-close {\n padding: 0.5rem;\n border: none;\n background: transparent;\n color: #6b7280;\n font-size: 1.25rem;\n cursor: pointer;\n border-radius: 6px;\n transition: all 0.2s;\n\n &:hover {\n background: #f3f4f6;\n color: #374151;\n }\n }\n}\n\n.modal-body[_ngcontent-%COMP%] {\n padding: 1.5rem;\n\n p {\n margin: 0 0 1rem 0;\n color: #374151;\n\n &:last-child {\n margin-bottom: 0;\n }\n }\n\n .text-muted {\n color: #6b7280;\n font-size: 0.875rem;\n }\n}\n\n.modal-footer[_ngcontent-%COMP%] {\n display: flex;\n justify-content: flex-end;\n gap: 0.75rem;\n padding: 1.5rem;\n border-top: 1px solid #e5e7eb;\n background: #f9fafb;\n}\n\n//[_ngcontent-%COMP%] Animations\n@keyframes[_ngcontent-%COMP%] fadeIn[_ngcontent-%COMP%] {\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//[_ngcontent-%COMP%] Utility[_ngcontent-%COMP%] Classes\n.text-danger[_ngcontent-%COMP%] {\n color: #f44336;\n}"] });
740
+ i0.ɵɵproperty("data", ctx.userDialogData)("visible", ctx.showUserDialog);
741
+ i0.ɵɵadvance();
742
+ i0.ɵɵconditional(ctx.showDeleteConfirm && ctx.selectedUser ? 76 : -1);
743
+ } }, dependencies: [CommonModule, i1.DatePipe, FormsModule, i2.NgSelectOption, i2.ɵNgSelectMultipleOption, SharedSettingsModule,
744
+ UserDialogComponent,
745
+ WindowModule], styles: ["@import '../shared/styles/variables';\n@import '../shared/styles/mixins';\n\n.user-management-container[_ngcontent-%COMP%] {\n @include scrollable-container;\n width: 100%;\n height: 100%;\n}\n\n//[_ngcontent-%COMP%] Action[_ngcontent-%COMP%] Buttons\n.action-buttons[_ngcontent-%COMP%] {\n @include fixed-header;\n display: flex;\n gap: 0.75rem;\n justify-content: flex-end;\n padding: 1rem 2rem;\n background: white;\n border-bottom: 1px solid $border-light;\n\n @media (max-width: 768px) {\n justify-content: center;\n flex-wrap: wrap;\n padding: 1rem;\n }\n}\n\n//[_ngcontent-%COMP%] Buttons\n.btn-primary[_ngcontent-%COMP%] {\n @include button-base;\n background-color: #2196f3;\n color: white;\n \n &:hover {\n background-color: #1976d2;\n transform: translateY(-1px);\n box-shadow: 0 4px 12px rgba(33, 150, 243, 0.3);\n }\n\n &:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n transform: none;\n }\n}\n\n.btn-secondary[_ngcontent-%COMP%] {\n @include button-base;\n background-color: #ffffff;\n color: #374151;\n border: 1px solid #e5e7eb;\n \n &:hover {\n background-color: #f9fafb;\n border-color: #2196f3;\n color: #2196f3;\n }\n}\n\n.btn-danger[_ngcontent-%COMP%] {\n @include button-base;\n background-color: #f44336;\n color: white;\n \n &:hover {\n background-color: #d32f2f;\n }\n}\n\n//[_ngcontent-%COMP%] Stats[_ngcontent-%COMP%] Grid\n.stats-grid[_ngcontent-%COMP%] {\n @include fixed-header;\n display: grid !important;\n grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));\n gap: 1.5rem;\n padding: 1rem 2rem;\n background: white;\n border-bottom: 1px solid $border-light;\n width: 100%;\n\n @media (max-width: 768px) {\n grid-template-columns: repeat(2, 1fr);\n gap: 1rem;\n padding: 1rem;\n }\n}\n\n.stat-card[_ngcontent-%COMP%] {\n background: white;\n border-radius: 12px;\n padding: 1.5rem;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n display: flex;\n margin-right: 10px;\n align-items: center;\n gap: 1rem;\n transition: all 0.3s ease;\n min-width: 0; // Prevent grid blowout\n\n &:hover {\n transform: translateY(-2px);\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);\n }\n}\n\n.stat-icon[_ngcontent-%COMP%] {\n width: 60px;\n height: 60px;\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 1.5rem;\n\n &-total {\n background: rgba(33, 150, 243, 0.1);\n color: #2196f3;\n }\n\n &-active {\n background: rgba(76, 175, 80, 0.1);\n color: #4caf50;\n }\n\n &-inactive {\n background: rgba(244, 67, 54, 0.1);\n color: #f44336;\n }\n\n &-admin {\n background: rgba(156, 39, 176, 0.1);\n color: #9c27b0;\n }\n}\n\n.stat-content[_ngcontent-%COMP%] {\n flex: 1;\n\n .stat-value {\n font-size: 2rem;\n font-weight: 700;\n color: #1f2937;\n line-height: 1;\n }\n\n .stat-label {\n color: #6b7280;\n font-size: 0.875rem;\n margin-top: 0.25rem;\n }\n}\n\n//[_ngcontent-%COMP%] Filters[_ngcontent-%COMP%] Section\n.filters-section[_ngcontent-%COMP%] {\n @include fixed-header;\n background: white;\n padding: 1.5rem 2rem;\n border-bottom: 1px solid $border-light;\n\n @media (max-width: 768px) {\n padding: 1rem;\n }\n}\n\n.filters-row[_ngcontent-%COMP%] {\n display: flex;\n gap: 1.5rem;\n align-items: flex-end;\n flex-wrap: wrap;\n\n @media (max-width: 768px) {\n gap: 1rem;\n }\n}\n\n.search-container[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 250px;\n position: relative;\n\n .search-icon {\n position: absolute;\n left: 1rem;\n top: 50%;\n transform: translateY(-50%);\n color: #6b7280;\n font-size: 1rem;\n }\n\n .search-input {\n width: 100%;\n padding: 0.75rem 1rem 0.75rem 2.75rem;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n font-size: 0.95rem;\n transition: all 0.2s;\n\n &:focus {\n outline: none;\n border-color: #2196f3;\n box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1);\n }\n }\n}\n\n.filter-group[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n\n .filter-label {\n font-size: 0.875rem;\n font-weight: 500;\n color: #374151;\n }\n\n .filter-buttons {\n display: flex;\n background: #f3f4f6;\n border-radius: 8px;\n padding: 4px;\n }\n\n .filter-btn {\n padding: 0.5rem 1rem;\n border: none;\n background: transparent;\n color: #6b7280;\n font-size: 0.875rem;\n font-weight: 500;\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s;\n\n &:hover {\n color: #374151;\n }\n\n &.active {\n background: white;\n color: #2196f3;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n }\n }\n\n .filter-select {\n padding: 0.625rem 1rem;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n background: white;\n font-size: 0.875rem;\n color: #374151;\n cursor: pointer;\n transition: all 0.2s;\n\n &:focus {\n outline: none;\n border-color: #2196f3;\n box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1);\n }\n }\n}\n\n.view-toggle[_ngcontent-%COMP%] {\n display: flex;\n background: #f3f4f6;\n border-radius: 8px;\n padding: 4px;\n\n .view-btn {\n padding: 0.5rem 0.75rem;\n border: none;\n background: transparent;\n color: #6b7280;\n font-size: 1rem;\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s;\n\n &:hover {\n color: #374151;\n }\n\n &.active {\n background: white;\n color: #2196f3;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n }\n }\n}\n\n//[_ngcontent-%COMP%] Content[_ngcontent-%COMP%] Area\n.content-area[_ngcontent-%COMP%] {\n @include scrollable-content;\n padding: 2rem;\n background: white;\n\n @media (max-width: 768px) {\n padding: 1rem;\n }\n}\n\n//[_ngcontent-%COMP%] Table[_ngcontent-%COMP%] View\n.users-table[_ngcontent-%COMP%] {\n width: 100%;\n overflow-x: auto;\n}\n\n.modern-table[_ngcontent-%COMP%] {\n width: 100%;\n border-collapse: collapse;\n\n thead {\n background: #f9fafb;\n border-bottom: 1px solid #e5e7eb;\n\n th {\n padding: 1rem;\n text-align: left;\n font-size: 0.875rem;\n font-weight: 600;\n color: #374151;\n white-space: nowrap;\n\n &.th-checkbox {\n width: 50px;\n }\n\n &.th-actions {\n text-align: center;\n width: 150px;\n }\n }\n }\n\n tbody {\n tr {\n border-bottom: 1px solid #f3f4f6;\n transition: background-color 0.2s;\n cursor: pointer;\n\n &:hover {\n background-color: #f9fafb;\n }\n }\n\n td {\n padding: 1rem;\n font-size: 0.875rem;\n color: #374151;\n\n &.td-checkbox {\n width: 50px;\n }\n\n &.td-actions {\n text-align: center;\n }\n }\n }\n}\n\n.checkbox[_ngcontent-%COMP%] {\n width: 18px;\n height: 18px;\n cursor: pointer;\n}\n\n.user-cell[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n}\n\n.user-avatar[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n border-radius: 50%;\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n display: flex;\n align-items: center;\n justify-content: center;\n font-weight: 600;\n font-size: 0.875rem;\n}\n\n.user-avatar-large[_ngcontent-%COMP%] {\n width: 80px;\n height: 80px;\n border-radius: 50%;\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n display: flex;\n align-items: center;\n justify-content: center;\n font-weight: 600;\n font-size: 1.5rem;\n margin: 0 auto 1rem;\n}\n\n.user-info[_ngcontent-%COMP%] {\n .user-name {\n font-weight: 600;\n color: #1f2937;\n }\n\n .user-fullname {\n font-size: 0.75rem;\n color: #6b7280;\n }\n}\n\n.user-type[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 0.5rem;\n color: #4b5563;\n\n i {\n font-size: 0.875rem;\n }\n}\n\n.status-badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.25rem 0.75rem;\n border-radius: 20px;\n font-size: 0.75rem;\n font-weight: 500;\n\n &.status-active {\n background: rgba(76, 175, 80, 0.1);\n color: #388e3c;\n }\n\n &.status-inactive {\n background: rgba(244, 67, 54, 0.1);\n color: #d32f2f;\n }\n\n i {\n font-size: 0.625rem;\n }\n}\n\n.last-login[_ngcontent-%COMP%] {\n color: #6b7280;\n font-size: 0.875rem;\n}\n\n.action-btn[_ngcontent-%COMP%] {\n padding: 0.5rem;\n border: none;\n background: transparent;\n color: #6b7280;\n font-size: 1rem;\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s;\n\n &:hover {\n background: #f3f4f6;\n color: #2196f3;\n }\n\n &-danger:hover {\n color: #f44336;\n }\n}\n\n//[_ngcontent-%COMP%] Card[_ngcontent-%COMP%] View\n.users-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));\n gap: 1.5rem;\n padding: 1.5rem;\n\n @media (max-width: 768px) {\n grid-template-columns: 1fr;\n gap: 1rem;\n padding: 1rem;\n }\n}\n\n.user-card[_ngcontent-%COMP%] {\n background: white;\n border: 1px solid #e5e7eb;\n border-radius: 12px;\n padding: 1.5rem;\n cursor: pointer;\n transition: all 0.3s ease;\n\n &:hover {\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);\n transform: translateY(-2px);\n border-color: #2196f3;\n }\n}\n\n.card-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 1rem;\n}\n\n.card-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.5rem;\n}\n\n.card-body[_ngcontent-%COMP%] {\n text-align: center;\n\n .user-name {\n font-size: 1.25rem;\n font-weight: 600;\n color: #1f2937;\n margin: 0 0 0.25rem 0;\n }\n\n .user-fullname {\n color: #6b7280;\n margin: 0 0 0.75rem 0;\n }\n\n .user-email {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n color: #4b5563;\n font-size: 0.875rem;\n margin-bottom: 1rem;\n\n i {\n color: #6b7280;\n }\n }\n}\n\n.card-meta[_ngcontent-%COMP%] {\n display: flex;\n justify-content: center;\n align-items: center;\n gap: 1rem;\n padding: 1rem 0;\n border-top: 1px solid #f3f4f6;\n border-bottom: 1px solid #f3f4f6;\n margin-bottom: 1rem;\n\n .meta-item {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n color: #4b5563;\n font-size: 0.875rem;\n }\n}\n\n.card-footer[_ngcontent-%COMP%] {\n .last-login {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0.375rem;\n color: #6b7280;\n font-size: 0.75rem;\n\n i {\n font-size: 0.875rem;\n }\n }\n}\n\n//[_ngcontent-%COMP%] Empty[_ngcontent-%COMP%] State\n.empty-state[_ngcontent-%COMP%] {\n text-align: center;\n padding: 4rem 2rem;\n\n .empty-icon {\n font-size: 4rem;\n color: #e5e7eb;\n margin-bottom: 1rem;\n }\n\n .empty-text {\n font-size: 1.25rem;\n font-weight: 600;\n color: #374151;\n margin: 0 0 0.5rem 0;\n }\n\n .empty-subtext {\n color: #6b7280;\n margin: 0;\n }\n}\n\n//[_ngcontent-%COMP%] Loading[_ngcontent-%COMP%] State\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.loading-spinner[_ngcontent-%COMP%] {\n position: relative;\n width: 60px;\n height: 60px;\n margin-bottom: 1rem;\n\n .spinner-ring {\n position: absolute;\n width: 100%;\n height: 100%;\n border: 3px solid transparent;\n border-radius: 50%;\n animation: _ngcontent-%COMP%_spin 1.5s cubic-bezier(0.5, 0, 0.5, 1) infinite;\n\n &:nth-child(1) {\n border-color: #2196f3 transparent transparent transparent;\n animation-delay: -0.45s;\n }\n\n &:nth-child(2) {\n border-color: transparent #4caf50 transparent transparent;\n animation-delay: -0.3s;\n }\n\n &:nth-child(3) {\n border-color: transparent transparent #ff9800 transparent;\n animation-delay: -0.15s;\n }\n }\n}\n\n@keyframes _ngcontent-%COMP%_spin {\n 0% {\n transform: rotate(0deg);\n }\n 100% {\n transform: rotate(360deg);\n }\n}\n\n.loading-text[_ngcontent-%COMP%] {\n color: #6b7280;\n font-size: 0.95rem;\n}\n\n//[_ngcontent-%COMP%] Error[_ngcontent-%COMP%] State\n.error-container[_ngcontent-%COMP%] {\n text-align: center;\n padding: 4rem 2rem;\n\n .error-icon {\n font-size: 3rem;\n color: #f44336;\n margin-bottom: 1rem;\n }\n\n .error-message {\n color: #374151;\n margin-bottom: 1.5rem;\n }\n\n .retry-button {\n @include button-base;\n background-color: #2196f3;\n color: white;\n }\n}\n\n//[_ngcontent-%COMP%] Modal[_ngcontent-%COMP%] Styles\n.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.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n animation: fadeIn 0.2s ease;\n}\n\n.modal-dialog[_ngcontent-%COMP%] {\n background: white;\n border-radius: 12px;\n box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);\n max-width: 500px;\n width: 90%;\n max-height: 90vh;\n overflow: hidden;\n animation: _ngcontent-%COMP%_slideUp 0.3s ease;\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 #e5e7eb;\n\n .modal-title {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n font-size: 1.25rem;\n font-weight: 600;\n color: #1f2937;\n margin: 0;\n }\n\n .modal-close {\n padding: 0.5rem;\n border: none;\n background: transparent;\n color: #6b7280;\n font-size: 1.25rem;\n cursor: pointer;\n border-radius: 6px;\n transition: all 0.2s;\n\n &:hover {\n background: #f3f4f6;\n color: #374151;\n }\n }\n}\n\n.modal-body[_ngcontent-%COMP%] {\n padding: 1.5rem;\n\n p {\n margin: 0 0 1rem 0;\n color: #374151;\n\n &:last-child {\n margin-bottom: 0;\n }\n }\n\n .text-muted {\n color: #6b7280;\n font-size: 0.875rem;\n }\n}\n\n.modal-footer[_ngcontent-%COMP%] {\n display: flex;\n justify-content: flex-end;\n gap: 0.75rem;\n padding: 1.5rem;\n border-top: 1px solid #e5e7eb;\n background: #f9fafb;\n}\n\n//[_ngcontent-%COMP%] Animations\n@keyframes[_ngcontent-%COMP%] fadeIn[_ngcontent-%COMP%] {\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//[_ngcontent-%COMP%] Utility[_ngcontent-%COMP%] Classes\n.text-danger[_ngcontent-%COMP%] {\n color: #f44336;\n}"] });
633
746
  }
634
747
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(UserManagementComponent, [{
635
748
  type: Component,
636
749
  args: [{ selector: 'mj-user-management', standalone: true, imports: [
637
750
  CommonModule,
638
751
  FormsModule,
639
- SharedSettingsModule
640
- ], template: "<div class=\"user-management-container\">\n <!-- Action Buttons -->\n <div class=\"action-buttons\">\n <button class=\"btn-secondary\" (click)=\"refreshData()\" [disabled]=\"isLoading\">\n <i class=\"fa-solid fa-refresh\" [class.fa-spin]=\"isLoading\"></i>\n Refresh\n </button>\n <button class=\"btn-secondary\" (click)=\"exportUsers()\">\n <i class=\"fa-solid fa-download\"></i>\n Export\n </button>\n <button class=\"btn-primary\" (click)=\"createNewUser()\">\n <i class=\"fa-solid fa-plus\"></i>\n Add User\n </button>\n </div>\n\n <!-- Stats Cards -->\n <div class=\"stats-grid\" style=\"display: flex\">\n <div class=\"stat-card\">\n <div class=\"stat-icon stat-icon-total\">\n <i class=\"fa-solid fa-users\"></i>\n </div>\n <div class=\"stat-content\">\n <div class=\"stat-value\">{{ stats.totalUsers }}</div>\n <div class=\"stat-label\">Total Users</div>\n </div>\n </div>\n \n <div class=\"stat-card\">\n <div class=\"stat-icon stat-icon-active\">\n <i class=\"fa-solid fa-user-check\"></i>\n </div>\n <div class=\"stat-content\">\n <div class=\"stat-value\">{{ stats.activeUsers }}</div>\n <div class=\"stat-label\">Active Users</div>\n </div>\n </div>\n \n <div class=\"stat-card\">\n <div class=\"stat-icon stat-icon-inactive\">\n <i class=\"fa-solid fa-user-xmark\"></i>\n </div>\n <div class=\"stat-content\">\n <div class=\"stat-value\">{{ stats.inactiveUsers }}</div>\n <div class=\"stat-label\">Inactive Users</div>\n </div>\n </div>\n \n <div class=\"stat-card\">\n <div class=\"stat-icon stat-icon-admin\">\n <i class=\"fa-solid fa-shield-halved\"></i>\n </div>\n <div class=\"stat-content\">\n <div class=\"stat-value\">{{ 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\">\n <div class=\"filters-row\">\n <!-- Search -->\n <div class=\"search-container\">\n <i class=\"fa-solid fa-search search-icon\"></i>\n <input \n type=\"text\" \n class=\"search-input\" \n placeholder=\"Search users by name or email...\"\n (input)=\"onSearchChange($event)\"\n [value]=\"filters$.value.search\"\n />\n </div>\n \n <!-- Status Filter -->\n <div class=\"filter-group\">\n <label class=\"filter-label\">Status</label>\n <div class=\"filter-buttons\">\n <button \n class=\"filter-btn\"\n [class.active]=\"filters$.value.status === 'all'\"\n (click)=\"onStatusFilterChange('all')\"\n >\n All\n </button>\n <button \n class=\"filter-btn\"\n [class.active]=\"filters$.value.status === 'active'\"\n (click)=\"onStatusFilterChange('active')\"\n >\n Active\n </button>\n <button \n class=\"filter-btn\"\n [class.active]=\"filters$.value.status === 'inactive'\"\n (click)=\"onStatusFilterChange('inactive')\"\n >\n Inactive\n </button>\n </div>\n </div>\n \n <!-- Role Filter -->\n <div class=\"filter-group\">\n <label class=\"filter-label\">Role</label>\n <select class=\"filter-select\" (change)=\"onRoleFilterChange($any($event.target).value)\">\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 <!-- View Toggle -->\n <div class=\"view-toggle\">\n <button \n class=\"view-btn\"\n [class.active]=\"viewMode === 'grid'\"\n (click)=\"viewMode = 'grid'\"\n title=\"Grid View\"\n >\n <i class=\"fa-solid fa-table\"></i>\n </button>\n <button \n class=\"view-btn\"\n [class.active]=\"viewMode === 'cards'\"\n (click)=\"viewMode = 'cards'\"\n title=\"Card View\"\n >\n <i class=\"fa-solid fa-th-large\"></i>\n </button>\n </div>\n </div>\n </div>\n\n <!-- Loading State -->\n @if (isLoading) {\n <div class=\"loading-container\">\n <div class=\"loading-spinner\">\n <div class=\"spinner-ring\"></div>\n <div class=\"spinner-ring\"></div>\n <div class=\"spinner-ring\"></div>\n </div>\n <div class=\"loading-text\">Loading users...</div>\n </div>\n }\n\n <!-- Error State -->\n @if (error && !isLoading) {\n <div class=\"error-container\">\n <div class=\"error-content\">\n <i class=\"fa-solid fa-exclamation-triangle error-icon\"></i>\n <p class=\"error-message\">{{ error }}</p>\n <button class=\"retry-button\" (click)=\"loadInitialData()\">\n <i class=\"fa-solid fa-refresh\"></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 <!-- Grid View -->\n @if (viewMode === 'grid') {\n <div class=\"users-table\">\n <table class=\"modern-table\">\n <thead>\n <tr>\n <th class=\"th-checkbox\">\n <input type=\"checkbox\" class=\"checkbox\" />\n </th>\n <th>User</th>\n <th>Email</th>\n <th>Type</th>\n <th>Status</th>\n <th>Last Updated</th>\n <th class=\"th-actions\">Actions</th>\n </tr>\n </thead>\n <tbody>\n @for (user of filteredUsers; track user.ID) {\n <tr class=\"table-row\" (click)=\"selectUser(user)\">\n <td class=\"td-checkbox\" (click)=\"$event.stopPropagation()\">\n <input type=\"checkbox\" class=\"checkbox\" />\n </td>\n <td>\n <div class=\"user-cell\">\n <div class=\"user-avatar\">\n {{ getUserInitials(user) }}\n </div>\n <div class=\"user-info\">\n <div class=\"user-name\">{{ user.Name }}</div>\n <div class=\"user-fullname\">\n {{ user.FirstName }} {{ user.LastName }}\n </div>\n </div>\n </div>\n </td>\n <td>{{ user.Email }}</td>\n <td>\n <div class=\"user-type\">\n <i [class]=\"'fa-solid ' + getUserTypeIcon(user)\"></i>\n {{ user.Type }}\n </div>\n </td>\n <td>\n <span class=\"status-badge\" [class]=\"getStatusClass(user)\">\n <i [class]=\"'fa-solid ' + getStatusIcon(user)\"></i>\n {{ user.IsActive ? 'Active' : 'Inactive' }}\n </span>\n </td>\n <td>\n <span class=\"last-login\">\n {{ user.__mj_UpdatedAt ? (user.__mj_UpdatedAt | date:'short') : 'Never' }}\n </span>\n </td>\n <td class=\"td-actions\" (click)=\"$event.stopPropagation()\">\n <button class=\"action-btn\" (click)=\"editUser(user)\" title=\"Edit\">\n <i class=\"fa-solid fa-edit\"></i>\n </button>\n <button \n class=\"action-btn\" \n (click)=\"toggleUserStatus(user)\"\n [title]=\"user.IsActive ? 'Deactivate' : 'Activate'\"\n >\n <i [class]=\"user.IsActive ? 'fa-solid fa-toggle-on' : 'fa-solid fa-toggle-off'\"></i>\n </button>\n <button class=\"action-btn action-btn-danger\" (click)=\"confirmDeleteUser(user)\" title=\"Delete\">\n <i class=\"fa-solid fa-trash\"></i>\n </button>\n </td>\n </tr>\n }\n </tbody>\n </table>\n \n @if (filteredUsers.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-users-slash empty-icon\"></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\n <!-- Card View -->\n @if (viewMode === 'cards') {\n <div class=\"users-grid\">\n @for (user of filteredUsers; track user.ID) {\n <div class=\"user-card\" (click)=\"selectUser(user)\">\n <div class=\"card-header\">\n <div class=\"user-avatar-large\">\n {{ getUserInitials(user) }}\n </div>\n <div class=\"card-actions\">\n <button class=\"action-btn\" (click)=\"editUser(user); $event.stopPropagation()\" title=\"Edit\">\n <i class=\"fa-solid fa-edit\"></i>\n </button>\n <button class=\"action-btn action-btn-danger\" (click)=\"confirmDeleteUser(user); $event.stopPropagation()\" title=\"Delete\">\n <i class=\"fa-solid fa-trash\"></i>\n </button>\n </div>\n </div>\n \n <div class=\"card-body\">\n <h3 class=\"user-name\">{{ user.Name }}</h3>\n <p class=\"user-fullname\">{{ user.FirstName }} {{ user.LastName }}</p>\n <p class=\"user-email\">\n <i class=\"fa-solid fa-envelope\"></i>\n {{ user.Email }}\n </p>\n \n <div class=\"card-meta\">\n <div class=\"meta-item\">\n <i [class]=\"'fa-solid ' + getUserTypeIcon(user)\"></i>\n {{ user.Type }}\n </div>\n <span class=\"status-badge\" [class]=\"getStatusClass(user)\">\n <i [class]=\"'fa-solid ' + getStatusIcon(user)\"></i>\n {{ user.IsActive ? 'Active' : 'Inactive' }}\n </span>\n </div>\n \n <div class=\"card-footer\">\n <div class=\"last-login\">\n <i class=\"fa-solid fa-clock\"></i>\n Last updated: {{ user.__mj_UpdatedAt ? (user.__mj_UpdatedAt | date:'short') : 'Never' }}\n </div>\n </div>\n </div>\n </div>\n }\n \n @if (filteredUsers.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-users-slash empty-icon\"></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 </div>\n }\n\n <!-- Delete Confirmation Dialog -->\n @if (showDeleteConfirm && selectedUser) {\n <div class=\"modal-backdrop\" (click)=\"showDeleteConfirm = false\">\n <div class=\"modal-dialog\" (click)=\"$event.stopPropagation()\">\n <div class=\"modal-header\">\n <h3 class=\"modal-title\">\n <i class=\"fa-solid fa-exclamation-triangle text-danger\"></i>\n Confirm Delete\n </h3>\n <button class=\"modal-close\" (click)=\"showDeleteConfirm = false\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n <div class=\"modal-body\">\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 class=\"btn-secondary\" (click)=\"showDeleteConfirm = false\">Cancel</button>\n <button class=\"btn-danger\" (click)=\"deleteUser()\">\n <i class=\"fa-solid fa-trash\"></i>\n Delete User\n </button>\n </div>\n </div>\n </div>\n }\n</div>", styles: ["@import '../shared/styles/variables';\n@import '../shared/styles/mixins';\n\n.user-management-container {\n @include scrollable-container;\n max-width: 1400px;\n margin: 0 auto;\n padding: 2rem;\n}\n\n// Action Buttons\n.action-buttons {\n display: flex;\n gap: 0.75rem;\n justify-content: flex-end;\n margin-bottom: 1.5rem;\n\n @media (max-width: 768px) {\n justify-content: center;\n flex-wrap: wrap;\n }\n}\n\n// Buttons\n.btn-primary {\n @include button-base;\n background-color: #2196f3;\n color: white;\n \n &:hover {\n background-color: #1976d2;\n transform: translateY(-1px);\n box-shadow: 0 4px 12px rgba(33, 150, 243, 0.3);\n }\n\n &:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n transform: none;\n }\n}\n\n.btn-secondary {\n @include button-base;\n background-color: #ffffff;\n color: #374151;\n border: 1px solid #e5e7eb;\n \n &:hover {\n background-color: #f9fafb;\n border-color: #2196f3;\n color: #2196f3;\n }\n}\n\n.btn-danger {\n @include button-base;\n background-color: #f44336;\n color: white;\n \n &:hover {\n background-color: #d32f2f;\n }\n}\n\n// Stats Grid\n.stats-grid {\n display: grid !important;\n grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));\n gap: 1.5rem;\n margin-bottom: 2rem;\n width: 100%;\n\n @media (max-width: 768px) {\n grid-template-columns: repeat(2, 1fr);\n gap: 1rem;\n }\n}\n\n.stat-card {\n background: white;\n border-radius: 12px;\n padding: 1.5rem;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n display: flex;\n margin-right: 10px;\n align-items: center;\n gap: 1rem;\n transition: all 0.3s ease;\n min-width: 0; // Prevent grid blowout\n\n &:hover {\n transform: translateY(-2px);\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);\n }\n}\n\n.stat-icon {\n width: 60px;\n height: 60px;\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 1.5rem;\n\n &-total {\n background: rgba(33, 150, 243, 0.1);\n color: #2196f3;\n }\n\n &-active {\n background: rgba(76, 175, 80, 0.1);\n color: #4caf50;\n }\n\n &-inactive {\n background: rgba(244, 67, 54, 0.1);\n color: #f44336;\n }\n\n &-admin {\n background: rgba(156, 39, 176, 0.1);\n color: #9c27b0;\n }\n}\n\n.stat-content {\n flex: 1;\n\n .stat-value {\n font-size: 2rem;\n font-weight: 700;\n color: #1f2937;\n line-height: 1;\n }\n\n .stat-label {\n color: #6b7280;\n font-size: 0.875rem;\n margin-top: 0.25rem;\n }\n}\n\n// Filters Section\n.filters-section {\n background: white;\n border-radius: 12px;\n padding: 1.5rem;\n margin-bottom: 1.5rem;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n}\n\n.filters-row {\n display: flex;\n gap: 1.5rem;\n align-items: flex-end;\n flex-wrap: wrap;\n\n @media (max-width: 768px) {\n gap: 1rem;\n }\n}\n\n.search-container {\n flex: 1;\n min-width: 250px;\n position: relative;\n\n .search-icon {\n position: absolute;\n left: 1rem;\n top: 50%;\n transform: translateY(-50%);\n color: #6b7280;\n font-size: 1rem;\n }\n\n .search-input {\n width: 100%;\n padding: 0.75rem 1rem 0.75rem 2.75rem;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n font-size: 0.95rem;\n transition: all 0.2s;\n\n &:focus {\n outline: none;\n border-color: #2196f3;\n box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1);\n }\n }\n}\n\n.filter-group {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n\n .filter-label {\n font-size: 0.875rem;\n font-weight: 500;\n color: #374151;\n }\n\n .filter-buttons {\n display: flex;\n background: #f3f4f6;\n border-radius: 8px;\n padding: 4px;\n }\n\n .filter-btn {\n padding: 0.5rem 1rem;\n border: none;\n background: transparent;\n color: #6b7280;\n font-size: 0.875rem;\n font-weight: 500;\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s;\n\n &:hover {\n color: #374151;\n }\n\n &.active {\n background: white;\n color: #2196f3;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n }\n }\n\n .filter-select {\n padding: 0.625rem 1rem;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n background: white;\n font-size: 0.875rem;\n color: #374151;\n cursor: pointer;\n transition: all 0.2s;\n\n &:focus {\n outline: none;\n border-color: #2196f3;\n box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1);\n }\n }\n}\n\n.view-toggle {\n display: flex;\n background: #f3f4f6;\n border-radius: 8px;\n padding: 4px;\n\n .view-btn {\n padding: 0.5rem 0.75rem;\n border: none;\n background: transparent;\n color: #6b7280;\n font-size: 1rem;\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s;\n\n &:hover {\n color: #374151;\n }\n\n &.active {\n background: white;\n color: #2196f3;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n }\n }\n}\n\n// Content Area\n.content-area {\n @include scrollable-content;\n background: white;\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n overflow: hidden;\n}\n\n// Table View\n.users-table {\n overflow-x: auto;\n max-height: calc(100vh - 450px); // Dynamic height\n overflow-y: auto;\n}\n\n.modern-table {\n width: 100%;\n border-collapse: collapse;\n\n thead {\n background: #f9fafb;\n border-bottom: 1px solid #e5e7eb;\n\n th {\n padding: 1rem;\n text-align: left;\n font-size: 0.875rem;\n font-weight: 600;\n color: #374151;\n white-space: nowrap;\n\n &.th-checkbox {\n width: 50px;\n }\n\n &.th-actions {\n text-align: center;\n width: 150px;\n }\n }\n }\n\n tbody {\n tr {\n border-bottom: 1px solid #f3f4f6;\n transition: background-color 0.2s;\n cursor: pointer;\n\n &:hover {\n background-color: #f9fafb;\n }\n }\n\n td {\n padding: 1rem;\n font-size: 0.875rem;\n color: #374151;\n\n &.td-checkbox {\n width: 50px;\n }\n\n &.td-actions {\n text-align: center;\n }\n }\n }\n}\n\n.checkbox {\n width: 18px;\n height: 18px;\n cursor: pointer;\n}\n\n.user-cell {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n}\n\n.user-avatar {\n width: 40px;\n height: 40px;\n border-radius: 50%;\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n display: flex;\n align-items: center;\n justify-content: center;\n font-weight: 600;\n font-size: 0.875rem;\n}\n\n.user-avatar-large {\n width: 80px;\n height: 80px;\n border-radius: 50%;\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n display: flex;\n align-items: center;\n justify-content: center;\n font-weight: 600;\n font-size: 1.5rem;\n margin: 0 auto 1rem;\n}\n\n.user-info {\n .user-name {\n font-weight: 600;\n color: #1f2937;\n }\n\n .user-fullname {\n font-size: 0.75rem;\n color: #6b7280;\n }\n}\n\n.user-type {\n display: inline-flex;\n align-items: center;\n gap: 0.5rem;\n color: #4b5563;\n\n i {\n font-size: 0.875rem;\n }\n}\n\n.status-badge {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.25rem 0.75rem;\n border-radius: 20px;\n font-size: 0.75rem;\n font-weight: 500;\n\n &.status-active {\n background: rgba(76, 175, 80, 0.1);\n color: #388e3c;\n }\n\n &.status-inactive {\n background: rgba(244, 67, 54, 0.1);\n color: #d32f2f;\n }\n\n i {\n font-size: 0.625rem;\n }\n}\n\n.last-login {\n color: #6b7280;\n font-size: 0.875rem;\n}\n\n.action-btn {\n padding: 0.5rem;\n border: none;\n background: transparent;\n color: #6b7280;\n font-size: 1rem;\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s;\n\n &:hover {\n background: #f3f4f6;\n color: #2196f3;\n }\n\n &-danger:hover {\n color: #f44336;\n }\n}\n\n// Card View\n.users-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));\n gap: 1.5rem;\n padding: 1.5rem;\n\n @media (max-width: 768px) {\n grid-template-columns: 1fr;\n gap: 1rem;\n padding: 1rem;\n }\n}\n\n.user-card {\n background: white;\n border: 1px solid #e5e7eb;\n border-radius: 12px;\n padding: 1.5rem;\n cursor: pointer;\n transition: all 0.3s ease;\n\n &:hover {\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);\n transform: translateY(-2px);\n border-color: #2196f3;\n }\n}\n\n.card-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 1rem;\n}\n\n.card-actions {\n display: flex;\n gap: 0.5rem;\n}\n\n.card-body {\n text-align: center;\n\n .user-name {\n font-size: 1.25rem;\n font-weight: 600;\n color: #1f2937;\n margin: 0 0 0.25rem 0;\n }\n\n .user-fullname {\n color: #6b7280;\n margin: 0 0 0.75rem 0;\n }\n\n .user-email {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n color: #4b5563;\n font-size: 0.875rem;\n margin-bottom: 1rem;\n\n i {\n color: #6b7280;\n }\n }\n}\n\n.card-meta {\n display: flex;\n justify-content: center;\n align-items: center;\n gap: 1rem;\n padding: 1rem 0;\n border-top: 1px solid #f3f4f6;\n border-bottom: 1px solid #f3f4f6;\n margin-bottom: 1rem;\n\n .meta-item {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n color: #4b5563;\n font-size: 0.875rem;\n }\n}\n\n.card-footer {\n .last-login {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0.375rem;\n color: #6b7280;\n font-size: 0.75rem;\n\n i {\n font-size: 0.875rem;\n }\n }\n}\n\n// Empty State\n.empty-state {\n text-align: center;\n padding: 4rem 2rem;\n\n .empty-icon {\n font-size: 4rem;\n color: #e5e7eb;\n margin-bottom: 1rem;\n }\n\n .empty-text {\n font-size: 1.25rem;\n font-weight: 600;\n color: #374151;\n margin: 0 0 0.5rem 0;\n }\n\n .empty-subtext {\n color: #6b7280;\n margin: 0;\n }\n}\n\n// Loading State\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.loading-spinner {\n position: relative;\n width: 60px;\n height: 60px;\n margin-bottom: 1rem;\n\n .spinner-ring {\n position: absolute;\n width: 100%;\n height: 100%;\n border: 3px solid transparent;\n border-radius: 50%;\n animation: spin 1.5s cubic-bezier(0.5, 0, 0.5, 1) infinite;\n\n &:nth-child(1) {\n border-color: #2196f3 transparent transparent transparent;\n animation-delay: -0.45s;\n }\n\n &:nth-child(2) {\n border-color: transparent #4caf50 transparent transparent;\n animation-delay: -0.3s;\n }\n\n &:nth-child(3) {\n border-color: transparent transparent #ff9800 transparent;\n animation-delay: -0.15s;\n }\n }\n}\n\n@keyframes spin {\n 0% {\n transform: rotate(0deg);\n }\n 100% {\n transform: rotate(360deg);\n }\n}\n\n.loading-text {\n color: #6b7280;\n font-size: 0.95rem;\n}\n\n// Error State\n.error-container {\n text-align: center;\n padding: 4rem 2rem;\n\n .error-icon {\n font-size: 3rem;\n color: #f44336;\n margin-bottom: 1rem;\n }\n\n .error-message {\n color: #374151;\n margin-bottom: 1.5rem;\n }\n\n .retry-button {\n @include button-base;\n background-color: #2196f3;\n color: white;\n }\n}\n\n// Modal Styles\n.modal-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n animation: fadeIn 0.2s ease;\n}\n\n.modal-dialog {\n background: white;\n border-radius: 12px;\n box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);\n max-width: 500px;\n width: 90%;\n max-height: 90vh;\n overflow: hidden;\n animation: slideUp 0.3s ease;\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 #e5e7eb;\n\n .modal-title {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n font-size: 1.25rem;\n font-weight: 600;\n color: #1f2937;\n margin: 0;\n }\n\n .modal-close {\n padding: 0.5rem;\n border: none;\n background: transparent;\n color: #6b7280;\n font-size: 1.25rem;\n cursor: pointer;\n border-radius: 6px;\n transition: all 0.2s;\n\n &:hover {\n background: #f3f4f6;\n color: #374151;\n }\n }\n}\n\n.modal-body {\n padding: 1.5rem;\n\n p {\n margin: 0 0 1rem 0;\n color: #374151;\n\n &:last-child {\n margin-bottom: 0;\n }\n }\n\n .text-muted {\n color: #6b7280;\n font-size: 0.875rem;\n }\n}\n\n.modal-footer {\n display: flex;\n justify-content: flex-end;\n gap: 0.75rem;\n padding: 1.5rem;\n border-top: 1px solid #e5e7eb;\n background: #f9fafb;\n}\n\n// Animations\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// Utility Classes\n.text-danger {\n color: #f44336;\n}"] }]
752
+ SharedSettingsModule,
753
+ UserDialogComponent,
754
+ WindowModule
755
+ ], template: "<div class=\"user-management-container\">\n <!-- Action Buttons -->\n <div class=\"action-buttons\">\n <button class=\"mj-btn mj-btn-secondary\" (click)=\"refreshData()\" [disabled]=\"isLoading\">\n <i class=\"fa-solid fa-refresh\" [class.fa-spin]=\"isLoading\"></i>\n Refresh\n </button>\n <button class=\"mj-btn mj-btn-secondary\" (click)=\"exportUsers()\">\n <i class=\"fa-solid fa-download\"></i>\n Export\n </button>\n <button class=\"mj-btn mj-btn-primary\" (click)=\"createNewUser()\">\n <i class=\"fa-solid fa-plus\"></i>\n Add User\n </button>\n </div>\n\n <!-- Stats Cards -->\n <div class=\"mj-grid mj-grid-4\">\n <div class=\"mj-card\">\n <div class=\"stat-icon stat-icon-total\">\n <i class=\"fa-solid fa-users\"></i>\n </div>\n <div class=\"stat-content\">\n <div class=\"stat-value\">{{ 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\">\n <i class=\"fa-solid fa-user-check\"></i>\n </div>\n <div class=\"stat-content\">\n <div class=\"stat-value\">{{ 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\">\n <i class=\"fa-solid fa-user-xmark\"></i>\n </div>\n <div class=\"stat-content\">\n <div class=\"stat-value\">{{ 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\">\n <i class=\"fa-solid fa-shield-halved\"></i>\n </div>\n <div class=\"stat-content\">\n <div class=\"stat-value\">{{ 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\">\n <div class=\"filters-row\">\n <!-- Search -->\n <div class=\"search-container\">\n <i class=\"fa-solid fa-search search-icon\"></i>\n <input \n type=\"text\" \n class=\"search-input\" \n placeholder=\"Search users by name or email...\"\n (input)=\"onSearchChange($event)\"\n [value]=\"filters$.value.search\"\n />\n </div>\n \n <!-- Status Filter -->\n <div class=\"filter-group\">\n <label class=\"filter-label\">Status</label>\n <div class=\"filter-buttons\">\n <button \n class=\"mj-btn mj-btn-ghost\"\n [class.mj-btn-primary]=\"filters$.value.status === 'all'\"\n (click)=\"onStatusFilterChange('all')\"\n >\n All\n </button>\n <button \n class=\"mj-btn mj-btn-ghost\"\n [class.mj-btn-primary]=\"filters$.value.status === 'active'\"\n (click)=\"onStatusFilterChange('active')\"\n >\n Active\n </button>\n <button \n class=\"mj-btn mj-btn-ghost\"\n [class.mj-btn-primary]=\"filters$.value.status === 'inactive'\"\n (click)=\"onStatusFilterChange('inactive')\"\n >\n Inactive\n </button>\n </div>\n </div>\n \n <!-- Role Filter -->\n <div class=\"filter-group\">\n <label class=\"filter-label\">Role</label>\n <select class=\"filter-select\" (change)=\"onRoleFilterChange($any($event.target).value)\">\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 <!-- View Toggle -->\n <div class=\"view-toggle\">\n <button \n class=\"mj-btn mj-btn-icon-only\"\n [class.mj-btn-primary]=\"viewMode === 'grid'\"\n [class.mj-btn-ghost]=\"viewMode !== 'grid'\"\n (click)=\"viewMode = 'grid'\"\n title=\"Grid View\"\n >\n <i class=\"fa-solid fa-table\"></i>\n </button>\n <button \n class=\"mj-btn mj-btn-icon-only\"\n [class.mj-btn-primary]=\"viewMode === 'cards'\"\n [class.mj-btn-ghost]=\"viewMode !== 'cards'\"\n (click)=\"viewMode = 'cards'\"\n title=\"Card View\"\n >\n <i class=\"fa-solid fa-th-large\"></i>\n </button>\n </div>\n </div>\n </div>\n\n <!-- Loading State -->\n @if (isLoading) {\n <div class=\"loading-container\">\n <div class=\"loading-spinner\">\n <div class=\"spinner-ring\"></div>\n <div class=\"spinner-ring\"></div>\n <div class=\"spinner-ring\"></div>\n </div>\n <div class=\"loading-text\">Loading users...</div>\n </div>\n }\n\n <!-- Error State -->\n @if (error && !isLoading) {\n <div class=\"error-container\">\n <div class=\"error-content\">\n <i class=\"fa-solid fa-exclamation-triangle error-icon\"></i>\n <p class=\"error-message\">{{ error }}</p>\n <button class=\"retry-button\" (click)=\"loadInitialData()\">\n <i class=\"fa-solid fa-refresh\"></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 <!-- Grid View -->\n @if (viewMode === 'grid') {\n <div class=\"users-table\">\n <table class=\"modern-table\">\n <thead>\n <tr>\n <th class=\"th-checkbox\">\n <input type=\"checkbox\" class=\"checkbox\" />\n </th>\n <th>User</th>\n <th>Email</th>\n <th>Type</th>\n <th>Status</th>\n <th>Last Updated</th>\n <th class=\"th-actions\">Actions</th>\n </tr>\n </thead>\n <tbody>\n @for (user of filteredUsers; track user.ID) {\n <tr class=\"table-row\" (click)=\"selectUser(user)\">\n <td class=\"td-checkbox\" (click)=\"$event.stopPropagation()\">\n <input type=\"checkbox\" class=\"checkbox\" />\n </td>\n <td>\n <div class=\"user-cell\">\n <div class=\"user-avatar\">\n {{ getUserInitials(user) }}\n </div>\n <div class=\"user-info\">\n <div class=\"user-name\">{{ user.Name }}</div>\n <div class=\"user-fullname\">\n {{ user.FirstName }} {{ user.LastName }}\n </div>\n </div>\n </div>\n </td>\n <td>{{ user.Email }}</td>\n <td>\n <div class=\"user-type\">\n <i [class]=\"'fa-solid ' + getUserTypeIcon(user)\"></i>\n {{ user.Type }}\n </div>\n </td>\n <td>\n <span class=\"status-badge\" [class]=\"getStatusClass(user)\">\n <i [class]=\"'fa-solid ' + getStatusIcon(user)\"></i>\n {{ user.IsActive ? 'Active' : 'Inactive' }}\n </span>\n </td>\n <td>\n <span class=\"last-login\">\n {{ user.__mj_UpdatedAt ? (user.__mj_UpdatedAt | date:'short') : 'Never' }}\n </span>\n </td>\n <td class=\"td-actions\" (click)=\"$event.stopPropagation()\">\n <button class=\"mj-btn mj-btn-ghost mj-btn-sm\" (click)=\"editUser(user)\" title=\"Edit\">\n <i class=\"fa-solid fa-edit\"></i>\n </button>\n <button \n class=\"mj-btn mj-btn-ghost mj-btn-sm\" \n (click)=\"toggleUserStatus(user)\"\n [title]=\"user.IsActive ? 'Deactivate' : 'Activate'\"\n >\n <i [class]=\"user.IsActive ? 'fa-solid fa-toggle-on' : 'fa-solid fa-toggle-off'\"></i>\n </button>\n <button class=\"mj-btn mj-btn-ghost mj-btn-sm text-danger\" (click)=\"confirmDeleteUser(user)\" title=\"Delete\">\n <i class=\"fa-solid fa-trash\"></i>\n </button>\n </td>\n </tr>\n }\n </tbody>\n </table>\n \n @if (filteredUsers.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-users-slash empty-icon\"></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\n <!-- Card View -->\n @if (viewMode === 'cards') {\n <div class=\"users-grid\">\n @for (user of filteredUsers; track user.ID) {\n <div class=\"user-card\" (click)=\"selectUser(user)\">\n <div class=\"card-header\">\n <div class=\"user-avatar-large\">\n {{ getUserInitials(user) }}\n </div>\n <div class=\"card-actions\">\n <button class=\"mj-btn mj-btn-ghost mj-btn-sm\" (click)=\"editUser(user); $event.stopPropagation()\" title=\"Edit\">\n <i class=\"fa-solid fa-edit\"></i>\n </button>\n <button class=\"mj-btn mj-btn-ghost mj-btn-sm text-danger\" (click)=\"confirmDeleteUser(user); $event.stopPropagation()\" title=\"Delete\">\n <i class=\"fa-solid fa-trash\"></i>\n </button>\n </div>\n </div>\n \n <div class=\"card-body\">\n <h3 class=\"user-name\">{{ user.Name }}</h3>\n <p class=\"user-fullname\">{{ user.FirstName }} {{ user.LastName }}</p>\n <p class=\"user-email\">\n <i class=\"fa-solid fa-envelope\"></i>\n {{ user.Email }}\n </p>\n \n <div class=\"card-meta\">\n <div class=\"meta-item\">\n <i [class]=\"'fa-solid ' + getUserTypeIcon(user)\"></i>\n {{ user.Type }}\n </div>\n <span class=\"status-badge\" [class]=\"getStatusClass(user)\">\n <i [class]=\"'fa-solid ' + getStatusIcon(user)\"></i>\n {{ user.IsActive ? 'Active' : 'Inactive' }}\n </span>\n </div>\n \n <div class=\"card-footer\">\n <div class=\"last-login\">\n <i class=\"fa-solid fa-clock\"></i>\n Last updated: {{ user.__mj_UpdatedAt ? (user.__mj_UpdatedAt | date:'short') : 'Never' }}\n </div>\n </div>\n </div>\n </div>\n }\n \n @if (filteredUsers.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-users-slash empty-icon\"></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 </div>\n }\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 class=\"modal-backdrop\" (click)=\"showDeleteConfirm = false\">\n <div class=\"modal-dialog\" (click)=\"$event.stopPropagation()\">\n <div class=\"modal-header\">\n <h3 class=\"modal-title\">\n <i class=\"fa-solid fa-exclamation-triangle text-danger\"></i>\n Confirm Delete\n </h3>\n <button class=\"modal-close\" (click)=\"showDeleteConfirm = false\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n <div class=\"modal-body\">\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 class=\"mj-btn mj-btn-secondary\" (click)=\"showDeleteConfirm = false\">Cancel</button>\n <button class=\"mj-btn mj-btn-primary text-danger\" (click)=\"deleteUser()\">\n <i class=\"fa-solid fa-trash\"></i>\n Delete User\n </button>\n </div>\n </div>\n </div>\n }\n</div>", styles: ["@import '../shared/styles/variables';\n@import '../shared/styles/mixins';\n\n.user-management-container {\n @include scrollable-container;\n width: 100%;\n height: 100%;\n}\n\n// Action Buttons\n.action-buttons {\n @include fixed-header;\n display: flex;\n gap: 0.75rem;\n justify-content: flex-end;\n padding: 1rem 2rem;\n background: white;\n border-bottom: 1px solid $border-light;\n\n @media (max-width: 768px) {\n justify-content: center;\n flex-wrap: wrap;\n padding: 1rem;\n }\n}\n\n// Buttons\n.btn-primary {\n @include button-base;\n background-color: #2196f3;\n color: white;\n \n &:hover {\n background-color: #1976d2;\n transform: translateY(-1px);\n box-shadow: 0 4px 12px rgba(33, 150, 243, 0.3);\n }\n\n &:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n transform: none;\n }\n}\n\n.btn-secondary {\n @include button-base;\n background-color: #ffffff;\n color: #374151;\n border: 1px solid #e5e7eb;\n \n &:hover {\n background-color: #f9fafb;\n border-color: #2196f3;\n color: #2196f3;\n }\n}\n\n.btn-danger {\n @include button-base;\n background-color: #f44336;\n color: white;\n \n &:hover {\n background-color: #d32f2f;\n }\n}\n\n// Stats Grid\n.stats-grid {\n @include fixed-header;\n display: grid !important;\n grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));\n gap: 1.5rem;\n padding: 1rem 2rem;\n background: white;\n border-bottom: 1px solid $border-light;\n width: 100%;\n\n @media (max-width: 768px) {\n grid-template-columns: repeat(2, 1fr);\n gap: 1rem;\n padding: 1rem;\n }\n}\n\n.stat-card {\n background: white;\n border-radius: 12px;\n padding: 1.5rem;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n display: flex;\n margin-right: 10px;\n align-items: center;\n gap: 1rem;\n transition: all 0.3s ease;\n min-width: 0; // Prevent grid blowout\n\n &:hover {\n transform: translateY(-2px);\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);\n }\n}\n\n.stat-icon {\n width: 60px;\n height: 60px;\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 1.5rem;\n\n &-total {\n background: rgba(33, 150, 243, 0.1);\n color: #2196f3;\n }\n\n &-active {\n background: rgba(76, 175, 80, 0.1);\n color: #4caf50;\n }\n\n &-inactive {\n background: rgba(244, 67, 54, 0.1);\n color: #f44336;\n }\n\n &-admin {\n background: rgba(156, 39, 176, 0.1);\n color: #9c27b0;\n }\n}\n\n.stat-content {\n flex: 1;\n\n .stat-value {\n font-size: 2rem;\n font-weight: 700;\n color: #1f2937;\n line-height: 1;\n }\n\n .stat-label {\n color: #6b7280;\n font-size: 0.875rem;\n margin-top: 0.25rem;\n }\n}\n\n// Filters Section\n.filters-section {\n @include fixed-header;\n background: white;\n padding: 1.5rem 2rem;\n border-bottom: 1px solid $border-light;\n\n @media (max-width: 768px) {\n padding: 1rem;\n }\n}\n\n.filters-row {\n display: flex;\n gap: 1.5rem;\n align-items: flex-end;\n flex-wrap: wrap;\n\n @media (max-width: 768px) {\n gap: 1rem;\n }\n}\n\n.search-container {\n flex: 1;\n min-width: 250px;\n position: relative;\n\n .search-icon {\n position: absolute;\n left: 1rem;\n top: 50%;\n transform: translateY(-50%);\n color: #6b7280;\n font-size: 1rem;\n }\n\n .search-input {\n width: 100%;\n padding: 0.75rem 1rem 0.75rem 2.75rem;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n font-size: 0.95rem;\n transition: all 0.2s;\n\n &:focus {\n outline: none;\n border-color: #2196f3;\n box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1);\n }\n }\n}\n\n.filter-group {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n\n .filter-label {\n font-size: 0.875rem;\n font-weight: 500;\n color: #374151;\n }\n\n .filter-buttons {\n display: flex;\n background: #f3f4f6;\n border-radius: 8px;\n padding: 4px;\n }\n\n .filter-btn {\n padding: 0.5rem 1rem;\n border: none;\n background: transparent;\n color: #6b7280;\n font-size: 0.875rem;\n font-weight: 500;\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s;\n\n &:hover {\n color: #374151;\n }\n\n &.active {\n background: white;\n color: #2196f3;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n }\n }\n\n .filter-select {\n padding: 0.625rem 1rem;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n background: white;\n font-size: 0.875rem;\n color: #374151;\n cursor: pointer;\n transition: all 0.2s;\n\n &:focus {\n outline: none;\n border-color: #2196f3;\n box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1);\n }\n }\n}\n\n.view-toggle {\n display: flex;\n background: #f3f4f6;\n border-radius: 8px;\n padding: 4px;\n\n .view-btn {\n padding: 0.5rem 0.75rem;\n border: none;\n background: transparent;\n color: #6b7280;\n font-size: 1rem;\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s;\n\n &:hover {\n color: #374151;\n }\n\n &.active {\n background: white;\n color: #2196f3;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n }\n }\n}\n\n// Content Area\n.content-area {\n @include scrollable-content;\n padding: 2rem;\n background: white;\n\n @media (max-width: 768px) {\n padding: 1rem;\n }\n}\n\n// Table View\n.users-table {\n width: 100%;\n overflow-x: auto;\n}\n\n.modern-table {\n width: 100%;\n border-collapse: collapse;\n\n thead {\n background: #f9fafb;\n border-bottom: 1px solid #e5e7eb;\n\n th {\n padding: 1rem;\n text-align: left;\n font-size: 0.875rem;\n font-weight: 600;\n color: #374151;\n white-space: nowrap;\n\n &.th-checkbox {\n width: 50px;\n }\n\n &.th-actions {\n text-align: center;\n width: 150px;\n }\n }\n }\n\n tbody {\n tr {\n border-bottom: 1px solid #f3f4f6;\n transition: background-color 0.2s;\n cursor: pointer;\n\n &:hover {\n background-color: #f9fafb;\n }\n }\n\n td {\n padding: 1rem;\n font-size: 0.875rem;\n color: #374151;\n\n &.td-checkbox {\n width: 50px;\n }\n\n &.td-actions {\n text-align: center;\n }\n }\n }\n}\n\n.checkbox {\n width: 18px;\n height: 18px;\n cursor: pointer;\n}\n\n.user-cell {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n}\n\n.user-avatar {\n width: 40px;\n height: 40px;\n border-radius: 50%;\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n display: flex;\n align-items: center;\n justify-content: center;\n font-weight: 600;\n font-size: 0.875rem;\n}\n\n.user-avatar-large {\n width: 80px;\n height: 80px;\n border-radius: 50%;\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n display: flex;\n align-items: center;\n justify-content: center;\n font-weight: 600;\n font-size: 1.5rem;\n margin: 0 auto 1rem;\n}\n\n.user-info {\n .user-name {\n font-weight: 600;\n color: #1f2937;\n }\n\n .user-fullname {\n font-size: 0.75rem;\n color: #6b7280;\n }\n}\n\n.user-type {\n display: inline-flex;\n align-items: center;\n gap: 0.5rem;\n color: #4b5563;\n\n i {\n font-size: 0.875rem;\n }\n}\n\n.status-badge {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.25rem 0.75rem;\n border-radius: 20px;\n font-size: 0.75rem;\n font-weight: 500;\n\n &.status-active {\n background: rgba(76, 175, 80, 0.1);\n color: #388e3c;\n }\n\n &.status-inactive {\n background: rgba(244, 67, 54, 0.1);\n color: #d32f2f;\n }\n\n i {\n font-size: 0.625rem;\n }\n}\n\n.last-login {\n color: #6b7280;\n font-size: 0.875rem;\n}\n\n.action-btn {\n padding: 0.5rem;\n border: none;\n background: transparent;\n color: #6b7280;\n font-size: 1rem;\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s;\n\n &:hover {\n background: #f3f4f6;\n color: #2196f3;\n }\n\n &-danger:hover {\n color: #f44336;\n }\n}\n\n// Card View\n.users-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));\n gap: 1.5rem;\n padding: 1.5rem;\n\n @media (max-width: 768px) {\n grid-template-columns: 1fr;\n gap: 1rem;\n padding: 1rem;\n }\n}\n\n.user-card {\n background: white;\n border: 1px solid #e5e7eb;\n border-radius: 12px;\n padding: 1.5rem;\n cursor: pointer;\n transition: all 0.3s ease;\n\n &:hover {\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);\n transform: translateY(-2px);\n border-color: #2196f3;\n }\n}\n\n.card-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 1rem;\n}\n\n.card-actions {\n display: flex;\n gap: 0.5rem;\n}\n\n.card-body {\n text-align: center;\n\n .user-name {\n font-size: 1.25rem;\n font-weight: 600;\n color: #1f2937;\n margin: 0 0 0.25rem 0;\n }\n\n .user-fullname {\n color: #6b7280;\n margin: 0 0 0.75rem 0;\n }\n\n .user-email {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n color: #4b5563;\n font-size: 0.875rem;\n margin-bottom: 1rem;\n\n i {\n color: #6b7280;\n }\n }\n}\n\n.card-meta {\n display: flex;\n justify-content: center;\n align-items: center;\n gap: 1rem;\n padding: 1rem 0;\n border-top: 1px solid #f3f4f6;\n border-bottom: 1px solid #f3f4f6;\n margin-bottom: 1rem;\n\n .meta-item {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n color: #4b5563;\n font-size: 0.875rem;\n }\n}\n\n.card-footer {\n .last-login {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0.375rem;\n color: #6b7280;\n font-size: 0.75rem;\n\n i {\n font-size: 0.875rem;\n }\n }\n}\n\n// Empty State\n.empty-state {\n text-align: center;\n padding: 4rem 2rem;\n\n .empty-icon {\n font-size: 4rem;\n color: #e5e7eb;\n margin-bottom: 1rem;\n }\n\n .empty-text {\n font-size: 1.25rem;\n font-weight: 600;\n color: #374151;\n margin: 0 0 0.5rem 0;\n }\n\n .empty-subtext {\n color: #6b7280;\n margin: 0;\n }\n}\n\n// Loading State\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.loading-spinner {\n position: relative;\n width: 60px;\n height: 60px;\n margin-bottom: 1rem;\n\n .spinner-ring {\n position: absolute;\n width: 100%;\n height: 100%;\n border: 3px solid transparent;\n border-radius: 50%;\n animation: spin 1.5s cubic-bezier(0.5, 0, 0.5, 1) infinite;\n\n &:nth-child(1) {\n border-color: #2196f3 transparent transparent transparent;\n animation-delay: -0.45s;\n }\n\n &:nth-child(2) {\n border-color: transparent #4caf50 transparent transparent;\n animation-delay: -0.3s;\n }\n\n &:nth-child(3) {\n border-color: transparent transparent #ff9800 transparent;\n animation-delay: -0.15s;\n }\n }\n}\n\n@keyframes spin {\n 0% {\n transform: rotate(0deg);\n }\n 100% {\n transform: rotate(360deg);\n }\n}\n\n.loading-text {\n color: #6b7280;\n font-size: 0.95rem;\n}\n\n// Error State\n.error-container {\n text-align: center;\n padding: 4rem 2rem;\n\n .error-icon {\n font-size: 3rem;\n color: #f44336;\n margin-bottom: 1rem;\n }\n\n .error-message {\n color: #374151;\n margin-bottom: 1.5rem;\n }\n\n .retry-button {\n @include button-base;\n background-color: #2196f3;\n color: white;\n }\n}\n\n// Modal Styles\n.modal-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n animation: fadeIn 0.2s ease;\n}\n\n.modal-dialog {\n background: white;\n border-radius: 12px;\n box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);\n max-width: 500px;\n width: 90%;\n max-height: 90vh;\n overflow: hidden;\n animation: slideUp 0.3s ease;\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 #e5e7eb;\n\n .modal-title {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n font-size: 1.25rem;\n font-weight: 600;\n color: #1f2937;\n margin: 0;\n }\n\n .modal-close {\n padding: 0.5rem;\n border: none;\n background: transparent;\n color: #6b7280;\n font-size: 1.25rem;\n cursor: pointer;\n border-radius: 6px;\n transition: all 0.2s;\n\n &:hover {\n background: #f3f4f6;\n color: #374151;\n }\n }\n}\n\n.modal-body {\n padding: 1.5rem;\n\n p {\n margin: 0 0 1rem 0;\n color: #374151;\n\n &:last-child {\n margin-bottom: 0;\n }\n }\n\n .text-muted {\n color: #6b7280;\n font-size: 0.875rem;\n }\n}\n\n.modal-footer {\n display: flex;\n justify-content: flex-end;\n gap: 0.75rem;\n padding: 1.5rem;\n border-top: 1px solid #e5e7eb;\n background: #f9fafb;\n}\n\n// Animations\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// Utility Classes\n.text-danger {\n color: #f44336;\n}"] }]
641
756
  }], () => [], null); })();
642
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(UserManagementComponent, { className: "UserManagementComponent", filePath: "src/lib/user-management/user-management.component.ts", lineNumber: 34 }); })();
757
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(UserManagementComponent, { className: "UserManagementComponent", filePath: "src/lib/user-management/user-management.component.ts", lineNumber: 38 }); })();
643
758
  //# sourceMappingURL=user-management.component.js.map