@memberjunction/ng-list-management 0.0.1 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/components/list-management-dialog/list-management-dialog.component.d.ts +170 -0
- package/dist/lib/components/list-management-dialog/list-management-dialog.component.d.ts.map +1 -0
- package/dist/lib/components/list-management-dialog/list-management-dialog.component.js +943 -0
- package/dist/lib/components/list-management-dialog/list-management-dialog.component.js.map +1 -0
- package/dist/lib/components/list-share-dialog/list-share-dialog.component.d.ts +137 -0
- package/dist/lib/components/list-share-dialog/list-share-dialog.component.d.ts.map +1 -0
- package/dist/lib/components/list-share-dialog/list-share-dialog.component.js +658 -0
- package/dist/lib/components/list-share-dialog/list-share-dialog.component.js.map +1 -0
- package/dist/lib/models/list-management.models.d.ts +206 -0
- package/dist/lib/models/list-management.models.d.ts.map +1 -0
- package/dist/lib/models/list-management.models.js +2 -0
- package/dist/lib/models/list-management.models.js.map +1 -0
- package/dist/lib/models/list-sharing.models.d.ts +193 -0
- package/dist/lib/models/list-sharing.models.d.ts.map +1 -0
- package/dist/lib/models/list-sharing.models.js +2 -0
- package/dist/lib/models/list-sharing.models.js.map +1 -0
- package/dist/lib/module.d.ts +44 -0
- package/dist/lib/module.d.ts.map +1 -0
- package/dist/lib/module.js +101 -0
- package/dist/lib/module.js.map +1 -0
- package/dist/lib/services/list-management.service.d.ts +69 -0
- package/dist/lib/services/list-management.service.d.ts.map +1 -0
- package/dist/lib/services/list-management.service.js +411 -0
- package/dist/lib/services/list-management.service.js.map +1 -0
- package/dist/lib/services/list-sharing.service.d.ts +98 -0
- package/dist/lib/services/list-sharing.service.d.ts.map +1 -0
- package/dist/lib/services/list-sharing.service.js +483 -0
- package/dist/lib/services/list-sharing.service.js.map +1 -0
- package/dist/public-api.d.ts +13 -0
- package/dist/public-api.d.ts.map +1 -0
- package/dist/public-api.js +23 -0
- package/dist/public-api.js.map +1 -0
- package/package.json +48 -6
- package/README.md +0 -45
|
@@ -0,0 +1,943 @@
|
|
|
1
|
+
import { Component, Input, Output, EventEmitter } from '@angular/core';
|
|
2
|
+
import { Subject } from 'rxjs';
|
|
3
|
+
import { debounceTime, takeUntil } from 'rxjs/operators';
|
|
4
|
+
import { Metadata } from '@memberjunction/core';
|
|
5
|
+
import * as i0 from "@angular/core";
|
|
6
|
+
import * as i1 from "../../services/list-management.service";
|
|
7
|
+
import * as i2 from "@angular/forms";
|
|
8
|
+
import * as i3 from "@memberjunction/ng-shared-generic";
|
|
9
|
+
const _forTrack0 = ($index, $item) => $item.ID;
|
|
10
|
+
const _forTrack1 = ($index, $item) => $item.list.ID;
|
|
11
|
+
function ListManagementDialogComponent_Conditional_0_Conditional_17_Template(rf, ctx) { if (rf & 1) {
|
|
12
|
+
const _r3 = i0.ɵɵgetCurrentView();
|
|
13
|
+
i0.ɵɵelementStart(0, "button", 38);
|
|
14
|
+
i0.ɵɵlistener("click", function ListManagementDialogComponent_Conditional_0_Conditional_17_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.clearSearch()); });
|
|
15
|
+
i0.ɵɵelement(1, "span", 39);
|
|
16
|
+
i0.ɵɵelementEnd();
|
|
17
|
+
} }
|
|
18
|
+
function ListManagementDialogComponent_Conditional_0_Conditional_18_Template(rf, ctx) { if (rf & 1) {
|
|
19
|
+
const _r4 = i0.ɵɵgetCurrentView();
|
|
20
|
+
i0.ɵɵelementStart(0, "button", 40);
|
|
21
|
+
i0.ɵɵlistener("click", function ListManagementDialogComponent_Conditional_0_Conditional_18_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.showCreateListForm()); });
|
|
22
|
+
i0.ɵɵelement(1, "span", 41);
|
|
23
|
+
i0.ɵɵelementStart(2, "span", 42);
|
|
24
|
+
i0.ɵɵtext(3, "New");
|
|
25
|
+
i0.ɵɵelementEnd()();
|
|
26
|
+
} if (rf & 2) {
|
|
27
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
28
|
+
i0.ɵɵproperty("disabled", ctx_r1.showCreateForm);
|
|
29
|
+
} }
|
|
30
|
+
function ListManagementDialogComponent_Conditional_0_Conditional_35_Conditional_11_For_5_Template(rf, ctx) { if (rf & 1) {
|
|
31
|
+
i0.ɵɵelementStart(0, "option", 51);
|
|
32
|
+
i0.ɵɵtext(1);
|
|
33
|
+
i0.ɵɵelementEnd();
|
|
34
|
+
} if (rf & 2) {
|
|
35
|
+
const category_r7 = ctx.$implicit;
|
|
36
|
+
i0.ɵɵproperty("ngValue", category_r7.ID);
|
|
37
|
+
i0.ɵɵadvance();
|
|
38
|
+
i0.ɵɵtextInterpolate(category_r7.Name);
|
|
39
|
+
} }
|
|
40
|
+
function ListManagementDialogComponent_Conditional_0_Conditional_35_Conditional_11_Template(rf, ctx) { if (rf & 1) {
|
|
41
|
+
const _r6 = i0.ɵɵgetCurrentView();
|
|
42
|
+
i0.ɵɵelementStart(0, "div", 46)(1, "select", 50);
|
|
43
|
+
i0.ɵɵtwoWayListener("ngModelChange", function ListManagementDialogComponent_Conditional_0_Conditional_35_Conditional_11_Template_select_ngModelChange_1_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.newListCategoryId, $event) || (ctx_r1.newListCategoryId = $event); return i0.ɵɵresetView($event); });
|
|
44
|
+
i0.ɵɵelementStart(2, "option", 51);
|
|
45
|
+
i0.ɵɵtext(3, "No category");
|
|
46
|
+
i0.ɵɵelementEnd();
|
|
47
|
+
i0.ɵɵrepeaterCreate(4, ListManagementDialogComponent_Conditional_0_Conditional_35_Conditional_11_For_5_Template, 2, 2, "option", 51, _forTrack0);
|
|
48
|
+
i0.ɵɵelementEnd()();
|
|
49
|
+
} if (rf & 2) {
|
|
50
|
+
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
51
|
+
i0.ɵɵadvance();
|
|
52
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.newListCategoryId);
|
|
53
|
+
i0.ɵɵproperty("disabled", ctx_r1.saving);
|
|
54
|
+
i0.ɵɵadvance();
|
|
55
|
+
i0.ɵɵproperty("ngValue", null);
|
|
56
|
+
i0.ɵɵadvance(2);
|
|
57
|
+
i0.ɵɵrepeater(ctx_r1.categories);
|
|
58
|
+
} }
|
|
59
|
+
function ListManagementDialogComponent_Conditional_0_Conditional_35_Conditional_14_Template(rf, ctx) { if (rf & 1) {
|
|
60
|
+
i0.ɵɵelement(0, "span", 37);
|
|
61
|
+
} }
|
|
62
|
+
function ListManagementDialogComponent_Conditional_0_Conditional_35_Template(rf, ctx) { if (rf & 1) {
|
|
63
|
+
const _r5 = i0.ɵɵgetCurrentView();
|
|
64
|
+
i0.ɵɵelementStart(0, "div", 26)(1, "div", 43);
|
|
65
|
+
i0.ɵɵelement(2, "span", 44);
|
|
66
|
+
i0.ɵɵelementStart(3, "span");
|
|
67
|
+
i0.ɵɵtext(4, "Create New List");
|
|
68
|
+
i0.ɵɵelementEnd()();
|
|
69
|
+
i0.ɵɵelementStart(5, "div", 45)(6, "div", 46)(7, "input", 47);
|
|
70
|
+
i0.ɵɵtwoWayListener("ngModelChange", function ListManagementDialogComponent_Conditional_0_Conditional_35_Template_input_ngModelChange_7_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r1.newListName, $event) || (ctx_r1.newListName = $event); return i0.ɵɵresetView($event); });
|
|
71
|
+
i0.ɵɵlistener("keyup.enter", function ListManagementDialogComponent_Conditional_0_Conditional_35_Template_input_keyup_enter_7_listener() { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.createList()); });
|
|
72
|
+
i0.ɵɵelementEnd()();
|
|
73
|
+
i0.ɵɵelementStart(8, "div", 46)(9, "textarea", 48);
|
|
74
|
+
i0.ɵɵtwoWayListener("ngModelChange", function ListManagementDialogComponent_Conditional_0_Conditional_35_Template_textarea_ngModelChange_9_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r1.newListDescription, $event) || (ctx_r1.newListDescription = $event); return i0.ɵɵresetView($event); });
|
|
75
|
+
i0.ɵɵtext(10, " ");
|
|
76
|
+
i0.ɵɵelementEnd()();
|
|
77
|
+
i0.ɵɵtemplate(11, ListManagementDialogComponent_Conditional_0_Conditional_35_Conditional_11_Template, 6, 3, "div", 46);
|
|
78
|
+
i0.ɵɵelementStart(12, "div", 49)(13, "button", 36);
|
|
79
|
+
i0.ɵɵlistener("click", function ListManagementDialogComponent_Conditional_0_Conditional_35_Template_button_click_13_listener() { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.createList()); });
|
|
80
|
+
i0.ɵɵtemplate(14, ListManagementDialogComponent_Conditional_0_Conditional_35_Conditional_14_Template, 1, 0, "span", 37);
|
|
81
|
+
i0.ɵɵtext(15, " Create List ");
|
|
82
|
+
i0.ɵɵelementEnd();
|
|
83
|
+
i0.ɵɵelementStart(16, "button", 35);
|
|
84
|
+
i0.ɵɵlistener("click", function ListManagementDialogComponent_Conditional_0_Conditional_35_Template_button_click_16_listener() { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.cancelCreateList()); });
|
|
85
|
+
i0.ɵɵtext(17, " Cancel ");
|
|
86
|
+
i0.ɵɵelementEnd()()()();
|
|
87
|
+
} if (rf & 2) {
|
|
88
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
89
|
+
i0.ɵɵadvance(7);
|
|
90
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.newListName);
|
|
91
|
+
i0.ɵɵproperty("disabled", ctx_r1.saving);
|
|
92
|
+
i0.ɵɵadvance(2);
|
|
93
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.newListDescription);
|
|
94
|
+
i0.ɵɵproperty("disabled", ctx_r1.saving);
|
|
95
|
+
i0.ɵɵadvance(2);
|
|
96
|
+
i0.ɵɵconditional(ctx_r1.categories.length > 0 ? 11 : -1);
|
|
97
|
+
i0.ɵɵadvance(2);
|
|
98
|
+
i0.ɵɵproperty("disabled", !ctx_r1.newListName.trim() || ctx_r1.saving);
|
|
99
|
+
i0.ɵɵadvance();
|
|
100
|
+
i0.ɵɵconditional(ctx_r1.saving ? 14 : -1);
|
|
101
|
+
i0.ɵɵadvance(2);
|
|
102
|
+
i0.ɵɵproperty("disabled", ctx_r1.saving);
|
|
103
|
+
} }
|
|
104
|
+
function ListManagementDialogComponent_Conditional_0_Conditional_37_Template(rf, ctx) { if (rf & 1) {
|
|
105
|
+
i0.ɵɵelementStart(0, "div", 28);
|
|
106
|
+
i0.ɵɵelement(1, "mj-loading", 52);
|
|
107
|
+
i0.ɵɵelementEnd();
|
|
108
|
+
} }
|
|
109
|
+
function ListManagementDialogComponent_Conditional_0_Conditional_38_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
110
|
+
i0.ɵɵelement(0, "span", 53);
|
|
111
|
+
i0.ɵɵelementStart(1, "p", 54);
|
|
112
|
+
i0.ɵɵtext(2, "No lists found");
|
|
113
|
+
i0.ɵɵelementEnd();
|
|
114
|
+
i0.ɵɵelementStart(3, "p", 55);
|
|
115
|
+
i0.ɵɵtext(4, "Try a different search term");
|
|
116
|
+
i0.ɵɵelementEnd();
|
|
117
|
+
} }
|
|
118
|
+
function ListManagementDialogComponent_Conditional_0_Conditional_38_Conditional_2_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
119
|
+
const _r8 = i0.ɵɵgetCurrentView();
|
|
120
|
+
i0.ɵɵelementStart(0, "button", 58);
|
|
121
|
+
i0.ɵɵlistener("click", function ListManagementDialogComponent_Conditional_0_Conditional_38_Conditional_2_Conditional_5_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.showCreateListForm()); });
|
|
122
|
+
i0.ɵɵelement(1, "span", 41);
|
|
123
|
+
i0.ɵɵtext(2, " Create List ");
|
|
124
|
+
i0.ɵɵelementEnd();
|
|
125
|
+
} }
|
|
126
|
+
function ListManagementDialogComponent_Conditional_0_Conditional_38_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
127
|
+
i0.ɵɵelement(0, "span", 56);
|
|
128
|
+
i0.ɵɵelementStart(1, "p", 54);
|
|
129
|
+
i0.ɵɵtext(2, "No lists yet");
|
|
130
|
+
i0.ɵɵelementEnd();
|
|
131
|
+
i0.ɵɵelementStart(3, "p", 55);
|
|
132
|
+
i0.ɵɵtext(4, "Create your first list to get started");
|
|
133
|
+
i0.ɵɵelementEnd();
|
|
134
|
+
i0.ɵɵtemplate(5, ListManagementDialogComponent_Conditional_0_Conditional_38_Conditional_2_Conditional_5_Template, 3, 0, "button", 57);
|
|
135
|
+
} if (rf & 2) {
|
|
136
|
+
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
137
|
+
i0.ɵɵadvance(5);
|
|
138
|
+
i0.ɵɵconditional(ctx_r1.config.allowCreate !== false ? 5 : -1);
|
|
139
|
+
} }
|
|
140
|
+
function ListManagementDialogComponent_Conditional_0_Conditional_38_Template(rf, ctx) { if (rf & 1) {
|
|
141
|
+
i0.ɵɵelementStart(0, "div", 29);
|
|
142
|
+
i0.ɵɵtemplate(1, ListManagementDialogComponent_Conditional_0_Conditional_38_Conditional_1_Template, 5, 0)(2, ListManagementDialogComponent_Conditional_0_Conditional_38_Conditional_2_Template, 6, 1);
|
|
143
|
+
i0.ɵɵelementEnd();
|
|
144
|
+
} if (rf & 2) {
|
|
145
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
146
|
+
i0.ɵɵadvance();
|
|
147
|
+
i0.ɵɵconditional(ctx_r1.searchText ? 1 : 2);
|
|
148
|
+
} }
|
|
149
|
+
function ListManagementDialogComponent_Conditional_0_Conditional_39_For_2_Conditional_2_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
150
|
+
i0.ɵɵelement(0, "span", 75);
|
|
151
|
+
} }
|
|
152
|
+
function ListManagementDialogComponent_Conditional_0_Conditional_39_For_2_Conditional_2_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
153
|
+
i0.ɵɵelement(0, "span", 41);
|
|
154
|
+
} }
|
|
155
|
+
function ListManagementDialogComponent_Conditional_0_Conditional_39_For_2_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
156
|
+
const _r9 = i0.ɵɵgetCurrentView();
|
|
157
|
+
i0.ɵɵelementStart(0, "button", 74);
|
|
158
|
+
i0.ɵɵlistener("click", function ListManagementDialogComponent_Conditional_0_Conditional_39_For_2_Conditional_2_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r9); const vm_r10 = i0.ɵɵnextContext().$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.toggleListForAdd(vm_r10)); });
|
|
159
|
+
i0.ɵɵtemplate(1, ListManagementDialogComponent_Conditional_0_Conditional_39_For_2_Conditional_2_Conditional_1_Template, 1, 0, "span", 75)(2, ListManagementDialogComponent_Conditional_0_Conditional_39_For_2_Conditional_2_Conditional_2_Template, 1, 0, "span", 41);
|
|
160
|
+
i0.ɵɵelementEnd();
|
|
161
|
+
} if (rf & 2) {
|
|
162
|
+
const vm_r10 = i0.ɵɵnextContext().$implicit;
|
|
163
|
+
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
164
|
+
i0.ɵɵclassProp("selected", vm_r10.isSelectedForAdd || ctx_r1.addedToLists.has(vm_r10.list.ID));
|
|
165
|
+
i0.ɵɵproperty("title", vm_r10.isSelectedForAdd || ctx_r1.addedToLists.has(vm_r10.list.ID) ? "Remove from selection" : "Add to this list");
|
|
166
|
+
i0.ɵɵadvance();
|
|
167
|
+
i0.ɵɵconditional(vm_r10.isSelectedForAdd || ctx_r1.addedToLists.has(vm_r10.list.ID) ? 1 : 2);
|
|
168
|
+
} }
|
|
169
|
+
function ListManagementDialogComponent_Conditional_0_Conditional_39_For_2_Conditional_3_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
170
|
+
i0.ɵɵelement(0, "span", 77);
|
|
171
|
+
} }
|
|
172
|
+
function ListManagementDialogComponent_Conditional_0_Conditional_39_For_2_Conditional_3_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
173
|
+
i0.ɵɵelement(0, "span", 78);
|
|
174
|
+
} }
|
|
175
|
+
function ListManagementDialogComponent_Conditional_0_Conditional_39_For_2_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
176
|
+
const _r11 = i0.ɵɵgetCurrentView();
|
|
177
|
+
i0.ɵɵelementStart(0, "button", 76);
|
|
178
|
+
i0.ɵɵlistener("click", function ListManagementDialogComponent_Conditional_0_Conditional_39_For_2_Conditional_3_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r11); const vm_r10 = i0.ɵɵnextContext().$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.toggleListForRemove(vm_r10)); });
|
|
179
|
+
i0.ɵɵtemplate(1, ListManagementDialogComponent_Conditional_0_Conditional_39_For_2_Conditional_3_Conditional_1_Template, 1, 0, "span", 77)(2, ListManagementDialogComponent_Conditional_0_Conditional_39_For_2_Conditional_3_Conditional_2_Template, 1, 0, "span", 78);
|
|
180
|
+
i0.ɵɵelementEnd();
|
|
181
|
+
} if (rf & 2) {
|
|
182
|
+
const vm_r10 = i0.ɵɵnextContext().$implicit;
|
|
183
|
+
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
184
|
+
i0.ɵɵclassProp("selected", vm_r10.isSelectedForRemove || ctx_r1.removedFromLists.has(vm_r10.list.ID));
|
|
185
|
+
i0.ɵɵproperty("title", vm_r10.isSelectedForRemove || ctx_r1.removedFromLists.has(vm_r10.list.ID) ? "Cancel removal" : "Remove from this list");
|
|
186
|
+
i0.ɵɵadvance();
|
|
187
|
+
i0.ɵɵconditional(vm_r10.isSelectedForRemove || ctx_r1.removedFromLists.has(vm_r10.list.ID) ? 1 : 2);
|
|
188
|
+
} }
|
|
189
|
+
function ListManagementDialogComponent_Conditional_0_Conditional_39_For_2_Conditional_9_Template(rf, ctx) { if (rf & 1) {
|
|
190
|
+
i0.ɵɵelementStart(0, "span", 68);
|
|
191
|
+
i0.ɵɵtext(1, "New");
|
|
192
|
+
i0.ɵɵelementEnd();
|
|
193
|
+
} }
|
|
194
|
+
function ListManagementDialogComponent_Conditional_0_Conditional_39_For_2_Conditional_11_Template(rf, ctx) { if (rf & 1) {
|
|
195
|
+
i0.ɵɵelementStart(0, "span", 79);
|
|
196
|
+
i0.ɵɵtext(1);
|
|
197
|
+
i0.ɵɵelementEnd();
|
|
198
|
+
i0.ɵɵelementStart(2, "span", 71);
|
|
199
|
+
i0.ɵɵtext(3, "\u2022");
|
|
200
|
+
i0.ɵɵelementEnd();
|
|
201
|
+
} if (rf & 2) {
|
|
202
|
+
const vm_r10 = i0.ɵɵnextContext().$implicit;
|
|
203
|
+
i0.ɵɵadvance();
|
|
204
|
+
i0.ɵɵtextInterpolate(vm_r10.list.Description);
|
|
205
|
+
} }
|
|
206
|
+
function ListManagementDialogComponent_Conditional_0_Conditional_39_For_2_Conditional_18_Template(rf, ctx) { if (rf & 1) {
|
|
207
|
+
i0.ɵɵelementStart(0, "div", 80);
|
|
208
|
+
i0.ɵɵelement(1, "span");
|
|
209
|
+
i0.ɵɵelementStart(2, "span", 81);
|
|
210
|
+
i0.ɵɵtext(3);
|
|
211
|
+
i0.ɵɵelementEnd()();
|
|
212
|
+
} if (rf & 2) {
|
|
213
|
+
const vm_r10 = i0.ɵɵnextContext().$implicit;
|
|
214
|
+
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
215
|
+
i0.ɵɵclassMap(ctx_r1.getMembershipClass(vm_r10));
|
|
216
|
+
i0.ɵɵadvance();
|
|
217
|
+
i0.ɵɵclassMap(ctx_r1.getMembershipIcon(vm_r10));
|
|
218
|
+
i0.ɵɵadvance(2);
|
|
219
|
+
i0.ɵɵtextInterpolate(ctx_r1.getMembershipText(vm_r10));
|
|
220
|
+
} }
|
|
221
|
+
function ListManagementDialogComponent_Conditional_0_Conditional_39_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
222
|
+
i0.ɵɵelementStart(0, "div", 60)(1, "div", 61);
|
|
223
|
+
i0.ɵɵtemplate(2, ListManagementDialogComponent_Conditional_0_Conditional_39_For_2_Conditional_2_Template, 3, 4, "button", 62)(3, ListManagementDialogComponent_Conditional_0_Conditional_39_For_2_Conditional_3_Template, 3, 4, "button", 63);
|
|
224
|
+
i0.ɵɵelementEnd();
|
|
225
|
+
i0.ɵɵelementStart(4, "div", 64)(5, "div", 65);
|
|
226
|
+
i0.ɵɵelement(6, "span", 66);
|
|
227
|
+
i0.ɵɵelementStart(7, "span", 67);
|
|
228
|
+
i0.ɵɵtext(8);
|
|
229
|
+
i0.ɵɵelementEnd();
|
|
230
|
+
i0.ɵɵtemplate(9, ListManagementDialogComponent_Conditional_0_Conditional_39_For_2_Conditional_9_Template, 2, 0, "span", 68);
|
|
231
|
+
i0.ɵɵelementEnd();
|
|
232
|
+
i0.ɵɵelementStart(10, "div", 69);
|
|
233
|
+
i0.ɵɵtemplate(11, ListManagementDialogComponent_Conditional_0_Conditional_39_For_2_Conditional_11_Template, 4, 1);
|
|
234
|
+
i0.ɵɵelementStart(12, "span", 70);
|
|
235
|
+
i0.ɵɵtext(13);
|
|
236
|
+
i0.ɵɵelementEnd();
|
|
237
|
+
i0.ɵɵelementStart(14, "span", 71);
|
|
238
|
+
i0.ɵɵtext(15, "\u2022");
|
|
239
|
+
i0.ɵɵelementEnd();
|
|
240
|
+
i0.ɵɵelementStart(16, "span", 72);
|
|
241
|
+
i0.ɵɵtext(17);
|
|
242
|
+
i0.ɵɵelementEnd()()();
|
|
243
|
+
i0.ɵɵtemplate(18, ListManagementDialogComponent_Conditional_0_Conditional_39_For_2_Conditional_18_Template, 4, 5, "div", 73);
|
|
244
|
+
i0.ɵɵelementEnd();
|
|
245
|
+
} if (rf & 2) {
|
|
246
|
+
const vm_r10 = ctx.$implicit;
|
|
247
|
+
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
248
|
+
i0.ɵɵclassProp("selected-add", vm_r10.isSelectedForAdd || ctx_r1.addedToLists.has(vm_r10.list.ID))("selected-remove", vm_r10.isSelectedForRemove || ctx_r1.removedFromLists.has(vm_r10.list.ID))("is-member", vm_r10.isFullMember || vm_r10.isPartialMember);
|
|
249
|
+
i0.ɵɵadvance(2);
|
|
250
|
+
i0.ɵɵconditional(ctx_r1.showAddButton(vm_r10) ? 2 : -1);
|
|
251
|
+
i0.ɵɵadvance();
|
|
252
|
+
i0.ɵɵconditional(ctx_r1.showRemoveButton(vm_r10) && (vm_r10.isFullMember || vm_r10.isPartialMember) ? 3 : -1);
|
|
253
|
+
i0.ɵɵadvance(5);
|
|
254
|
+
i0.ɵɵtextInterpolate(vm_r10.list.Name);
|
|
255
|
+
i0.ɵɵadvance();
|
|
256
|
+
i0.ɵɵconditional(ctx_r1.newlyCreatedLists.includes(vm_r10.list) ? 9 : -1);
|
|
257
|
+
i0.ɵɵadvance(2);
|
|
258
|
+
i0.ɵɵconditional(vm_r10.list.Description ? 11 : -1);
|
|
259
|
+
i0.ɵɵadvance(2);
|
|
260
|
+
i0.ɵɵtextInterpolate2("", vm_r10.itemCount, " item", vm_r10.itemCount !== 1 ? "s" : "", "");
|
|
261
|
+
i0.ɵɵadvance(4);
|
|
262
|
+
i0.ɵɵtextInterpolate(ctx_r1.formatDate(vm_r10.lastUpdated));
|
|
263
|
+
i0.ɵɵadvance();
|
|
264
|
+
i0.ɵɵconditional(ctx_r1.config.showMembership !== false ? 18 : -1);
|
|
265
|
+
} }
|
|
266
|
+
function ListManagementDialogComponent_Conditional_0_Conditional_39_Template(rf, ctx) { if (rf & 1) {
|
|
267
|
+
i0.ɵɵelementStart(0, "div", 30);
|
|
268
|
+
i0.ɵɵrepeaterCreate(1, ListManagementDialogComponent_Conditional_0_Conditional_39_For_2_Template, 19, 15, "div", 59, _forTrack1);
|
|
269
|
+
i0.ɵɵelementEnd();
|
|
270
|
+
} if (rf & 2) {
|
|
271
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
272
|
+
i0.ɵɵadvance();
|
|
273
|
+
i0.ɵɵrepeater(ctx_r1.filteredLists);
|
|
274
|
+
} }
|
|
275
|
+
function ListManagementDialogComponent_Conditional_0_Conditional_42_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
276
|
+
i0.ɵɵelementStart(0, "span", 82);
|
|
277
|
+
i0.ɵɵelement(1, "span", 44);
|
|
278
|
+
i0.ɵɵtext(2);
|
|
279
|
+
i0.ɵɵelementEnd();
|
|
280
|
+
} if (rf & 2) {
|
|
281
|
+
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
282
|
+
i0.ɵɵadvance(2);
|
|
283
|
+
i0.ɵɵtextInterpolate2(" ", ctx_r1.addCount, " list", ctx_r1.addCount !== 1 ? "s" : "", " ");
|
|
284
|
+
} }
|
|
285
|
+
function ListManagementDialogComponent_Conditional_0_Conditional_42_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
286
|
+
i0.ɵɵelementStart(0, "span", 83);
|
|
287
|
+
i0.ɵɵelement(1, "span", 84);
|
|
288
|
+
i0.ɵɵtext(2);
|
|
289
|
+
i0.ɵɵelementEnd();
|
|
290
|
+
} if (rf & 2) {
|
|
291
|
+
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
292
|
+
i0.ɵɵadvance(2);
|
|
293
|
+
i0.ɵɵtextInterpolate2(" ", ctx_r1.removeCount, " list", ctx_r1.removeCount !== 1 ? "s" : "", " ");
|
|
294
|
+
} }
|
|
295
|
+
function ListManagementDialogComponent_Conditional_0_Conditional_42_Template(rf, ctx) { if (rf & 1) {
|
|
296
|
+
i0.ɵɵtemplate(0, ListManagementDialogComponent_Conditional_0_Conditional_42_Conditional_0_Template, 3, 2, "span", 82)(1, ListManagementDialogComponent_Conditional_0_Conditional_42_Conditional_1_Template, 3, 2, "span", 83);
|
|
297
|
+
} if (rf & 2) {
|
|
298
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
299
|
+
i0.ɵɵconditional(ctx_r1.addCount > 0 ? 0 : -1);
|
|
300
|
+
i0.ɵɵadvance();
|
|
301
|
+
i0.ɵɵconditional(ctx_r1.removeCount > 0 ? 1 : -1);
|
|
302
|
+
} }
|
|
303
|
+
function ListManagementDialogComponent_Conditional_0_Conditional_43_Template(rf, ctx) { if (rf & 1) {
|
|
304
|
+
i0.ɵɵelementStart(0, "span", 33);
|
|
305
|
+
i0.ɵɵtext(1, "No changes");
|
|
306
|
+
i0.ɵɵelementEnd();
|
|
307
|
+
} }
|
|
308
|
+
function ListManagementDialogComponent_Conditional_0_Conditional_48_Template(rf, ctx) { if (rf & 1) {
|
|
309
|
+
i0.ɵɵelement(0, "span", 37);
|
|
310
|
+
} }
|
|
311
|
+
function ListManagementDialogComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
312
|
+
const _r1 = i0.ɵɵgetCurrentView();
|
|
313
|
+
i0.ɵɵelementStart(0, "div", 1);
|
|
314
|
+
i0.ɵɵlistener("click", function ListManagementDialogComponent_Conditional_0_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onCancel()); });
|
|
315
|
+
i0.ɵɵelementStart(1, "div", 2);
|
|
316
|
+
i0.ɵɵlistener("click", function ListManagementDialogComponent_Conditional_0_Template_div_click_1_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
317
|
+
i0.ɵɵelementStart(2, "div", 3)(3, "div", 4)(4, "div", 5);
|
|
318
|
+
i0.ɵɵelement(5, "span", 6);
|
|
319
|
+
i0.ɵɵelementEnd();
|
|
320
|
+
i0.ɵɵelementStart(6, "div", 7)(7, "h2", 8);
|
|
321
|
+
i0.ɵɵtext(8);
|
|
322
|
+
i0.ɵɵelementEnd();
|
|
323
|
+
i0.ɵɵelementStart(9, "p", 9);
|
|
324
|
+
i0.ɵɵtext(10);
|
|
325
|
+
i0.ɵɵelementEnd()()();
|
|
326
|
+
i0.ɵɵelementStart(11, "button", 10);
|
|
327
|
+
i0.ɵɵlistener("click", function ListManagementDialogComponent_Conditional_0_Template_button_click_11_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onCancel()); });
|
|
328
|
+
i0.ɵɵelement(12, "span", 11);
|
|
329
|
+
i0.ɵɵelementEnd()();
|
|
330
|
+
i0.ɵɵelementStart(13, "div", 12)(14, "div", 13);
|
|
331
|
+
i0.ɵɵelement(15, "span", 14);
|
|
332
|
+
i0.ɵɵelementStart(16, "input", 15);
|
|
333
|
+
i0.ɵɵlistener("input", function ListManagementDialogComponent_Conditional_0_Template_input_input_16_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onSearchInput($event)); });
|
|
334
|
+
i0.ɵɵelementEnd();
|
|
335
|
+
i0.ɵɵtemplate(17, ListManagementDialogComponent_Conditional_0_Conditional_17_Template, 2, 0, "button", 16);
|
|
336
|
+
i0.ɵɵelementEnd();
|
|
337
|
+
i0.ɵɵtemplate(18, ListManagementDialogComponent_Conditional_0_Conditional_18_Template, 4, 1, "button", 17);
|
|
338
|
+
i0.ɵɵelementEnd();
|
|
339
|
+
i0.ɵɵelementStart(19, "div", 18)(20, "div", 19)(21, "button", 20);
|
|
340
|
+
i0.ɵɵlistener("click", function ListManagementDialogComponent_Conditional_0_Template_button_click_21_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.setActiveTab("all")); });
|
|
341
|
+
i0.ɵɵtext(22, " All ");
|
|
342
|
+
i0.ɵɵelementEnd();
|
|
343
|
+
i0.ɵɵelementStart(23, "button", 20);
|
|
344
|
+
i0.ɵɵlistener("click", function ListManagementDialogComponent_Conditional_0_Template_button_click_23_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.setActiveTab("my-lists")); });
|
|
345
|
+
i0.ɵɵtext(24, " My Lists ");
|
|
346
|
+
i0.ɵɵelementEnd();
|
|
347
|
+
i0.ɵɵelementStart(25, "button", 20);
|
|
348
|
+
i0.ɵɵlistener("click", function ListManagementDialogComponent_Conditional_0_Template_button_click_25_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.setActiveTab("recent")); });
|
|
349
|
+
i0.ɵɵtext(26, " Recent ");
|
|
350
|
+
i0.ɵɵelementEnd()();
|
|
351
|
+
i0.ɵɵelementStart(27, "div", 21)(28, "select", 22);
|
|
352
|
+
i0.ɵɵlistener("change", function ListManagementDialogComponent_Conditional_0_Template_select_change_28_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.setSortOption($event.target.value)); });
|
|
353
|
+
i0.ɵɵelementStart(29, "option", 23);
|
|
354
|
+
i0.ɵɵtext(30, "Sort: Name");
|
|
355
|
+
i0.ɵɵelementEnd();
|
|
356
|
+
i0.ɵɵelementStart(31, "option", 24);
|
|
357
|
+
i0.ɵɵtext(32, "Sort: Recent");
|
|
358
|
+
i0.ɵɵelementEnd();
|
|
359
|
+
i0.ɵɵelementStart(33, "option", 25);
|
|
360
|
+
i0.ɵɵtext(34, "Sort: Items");
|
|
361
|
+
i0.ɵɵelementEnd()()()();
|
|
362
|
+
i0.ɵɵtemplate(35, ListManagementDialogComponent_Conditional_0_Conditional_35_Template, 18, 8, "div", 26);
|
|
363
|
+
i0.ɵɵelementStart(36, "div", 27);
|
|
364
|
+
i0.ɵɵtemplate(37, ListManagementDialogComponent_Conditional_0_Conditional_37_Template, 2, 0, "div", 28)(38, ListManagementDialogComponent_Conditional_0_Conditional_38_Template, 3, 1, "div", 29)(39, ListManagementDialogComponent_Conditional_0_Conditional_39_Template, 3, 0, "div", 30);
|
|
365
|
+
i0.ɵɵelementEnd();
|
|
366
|
+
i0.ɵɵelementStart(40, "div", 31)(41, "div", 32);
|
|
367
|
+
i0.ɵɵtemplate(42, ListManagementDialogComponent_Conditional_0_Conditional_42_Template, 2, 2)(43, ListManagementDialogComponent_Conditional_0_Conditional_43_Template, 2, 0, "span", 33);
|
|
368
|
+
i0.ɵɵelementEnd();
|
|
369
|
+
i0.ɵɵelementStart(44, "div", 34)(45, "button", 35);
|
|
370
|
+
i0.ɵɵlistener("click", function ListManagementDialogComponent_Conditional_0_Template_button_click_45_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onCancel()); });
|
|
371
|
+
i0.ɵɵtext(46, " Cancel ");
|
|
372
|
+
i0.ɵɵelementEnd();
|
|
373
|
+
i0.ɵɵelementStart(47, "button", 36);
|
|
374
|
+
i0.ɵɵlistener("click", function ListManagementDialogComponent_Conditional_0_Template_button_click_47_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.applyChanges()); });
|
|
375
|
+
i0.ɵɵtemplate(48, ListManagementDialogComponent_Conditional_0_Conditional_48_Template, 1, 0, "span", 37);
|
|
376
|
+
i0.ɵɵtext(49, " Apply Changes ");
|
|
377
|
+
i0.ɵɵelementEnd()()()()();
|
|
378
|
+
} if (rf & 2) {
|
|
379
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
380
|
+
i0.ɵɵadvance(8);
|
|
381
|
+
i0.ɵɵtextInterpolate(ctx_r1.dialogTitle);
|
|
382
|
+
i0.ɵɵadvance(2);
|
|
383
|
+
i0.ɵɵtextInterpolate(ctx_r1.dialogSubtitle);
|
|
384
|
+
i0.ɵɵadvance(6);
|
|
385
|
+
i0.ɵɵproperty("value", ctx_r1.searchText);
|
|
386
|
+
i0.ɵɵadvance();
|
|
387
|
+
i0.ɵɵconditional(ctx_r1.searchText ? 17 : -1);
|
|
388
|
+
i0.ɵɵadvance();
|
|
389
|
+
i0.ɵɵconditional(ctx_r1.config.allowCreate !== false ? 18 : -1);
|
|
390
|
+
i0.ɵɵadvance(3);
|
|
391
|
+
i0.ɵɵclassProp("active", ctx_r1.activeTab === "all");
|
|
392
|
+
i0.ɵɵadvance(2);
|
|
393
|
+
i0.ɵɵclassProp("active", ctx_r1.activeTab === "my-lists");
|
|
394
|
+
i0.ɵɵadvance(2);
|
|
395
|
+
i0.ɵɵclassProp("active", ctx_r1.activeTab === "recent");
|
|
396
|
+
i0.ɵɵadvance(3);
|
|
397
|
+
i0.ɵɵproperty("value", ctx_r1.sortOption);
|
|
398
|
+
i0.ɵɵadvance(7);
|
|
399
|
+
i0.ɵɵconditional(ctx_r1.showCreateForm ? 35 : -1);
|
|
400
|
+
i0.ɵɵadvance(2);
|
|
401
|
+
i0.ɵɵconditional(ctx_r1.loading ? 37 : ctx_r1.filteredLists.length === 0 ? 38 : 39);
|
|
402
|
+
i0.ɵɵadvance(5);
|
|
403
|
+
i0.ɵɵconditional(ctx_r1.hasChanges ? 42 : 43);
|
|
404
|
+
i0.ɵɵadvance(3);
|
|
405
|
+
i0.ɵɵproperty("disabled", ctx_r1.saving);
|
|
406
|
+
i0.ɵɵadvance(2);
|
|
407
|
+
i0.ɵɵproperty("disabled", !ctx_r1.hasChanges || ctx_r1.saving);
|
|
408
|
+
i0.ɵɵadvance();
|
|
409
|
+
i0.ɵɵconditional(ctx_r1.saving ? 48 : -1);
|
|
410
|
+
} }
|
|
411
|
+
/**
|
|
412
|
+
* A gorgeous, responsive dialog for managing list membership.
|
|
413
|
+
* Supports adding/removing records from multiple lists with membership indicators.
|
|
414
|
+
*
|
|
415
|
+
* Features:
|
|
416
|
+
* - Search and filter lists
|
|
417
|
+
* - Visual membership indicators (full/partial/none)
|
|
418
|
+
* - Inline list creation
|
|
419
|
+
* - Mobile-responsive bottom sheet on small screens
|
|
420
|
+
* - Batch operations with progress feedback
|
|
421
|
+
*/
|
|
422
|
+
export class ListManagementDialogComponent {
|
|
423
|
+
listService;
|
|
424
|
+
cdr;
|
|
425
|
+
/**
|
|
426
|
+
* Configuration for the dialog
|
|
427
|
+
*/
|
|
428
|
+
config;
|
|
429
|
+
/**
|
|
430
|
+
* Controls dialog visibility
|
|
431
|
+
*/
|
|
432
|
+
get visible() {
|
|
433
|
+
return this._visible;
|
|
434
|
+
}
|
|
435
|
+
set visible(value) {
|
|
436
|
+
if (value && !this._visible) {
|
|
437
|
+
this.initializeDialog();
|
|
438
|
+
}
|
|
439
|
+
this._visible = value;
|
|
440
|
+
}
|
|
441
|
+
_visible = false;
|
|
442
|
+
/**
|
|
443
|
+
* Emitted when dialog is closed with results
|
|
444
|
+
*/
|
|
445
|
+
complete = new EventEmitter();
|
|
446
|
+
/**
|
|
447
|
+
* Emitted when dialog is cancelled
|
|
448
|
+
*/
|
|
449
|
+
cancel = new EventEmitter();
|
|
450
|
+
// State
|
|
451
|
+
loading = false;
|
|
452
|
+
saving = false;
|
|
453
|
+
searchText = '';
|
|
454
|
+
activeTab = 'all';
|
|
455
|
+
sortOption = 'name';
|
|
456
|
+
showCreateForm = false;
|
|
457
|
+
// Data
|
|
458
|
+
allLists = [];
|
|
459
|
+
filteredLists = [];
|
|
460
|
+
categories = [];
|
|
461
|
+
// Create form state
|
|
462
|
+
newListName = '';
|
|
463
|
+
newListDescription = '';
|
|
464
|
+
newListCategoryId = null;
|
|
465
|
+
// Track changes
|
|
466
|
+
originalMembership = new Map();
|
|
467
|
+
addedToLists = new Set();
|
|
468
|
+
removedFromLists = new Set();
|
|
469
|
+
newlyCreatedLists = [];
|
|
470
|
+
// Cleanup
|
|
471
|
+
destroy$ = new Subject();
|
|
472
|
+
searchSubject = new Subject();
|
|
473
|
+
constructor(listService, cdr) {
|
|
474
|
+
this.listService = listService;
|
|
475
|
+
this.cdr = cdr;
|
|
476
|
+
}
|
|
477
|
+
ngOnInit() {
|
|
478
|
+
this.setupSearchDebounce();
|
|
479
|
+
}
|
|
480
|
+
ngOnDestroy() {
|
|
481
|
+
this.destroy$.next();
|
|
482
|
+
this.destroy$.complete();
|
|
483
|
+
}
|
|
484
|
+
/**
|
|
485
|
+
* Get dialog title based on config
|
|
486
|
+
*/
|
|
487
|
+
get dialogTitle() {
|
|
488
|
+
if (this.config?.dialogTitle) {
|
|
489
|
+
return this.config.dialogTitle;
|
|
490
|
+
}
|
|
491
|
+
const recordCount = this.config?.recordIds?.length || 0;
|
|
492
|
+
const recordText = recordCount === 1 ? '1 record' : `${recordCount} records`;
|
|
493
|
+
switch (this.config?.mode) {
|
|
494
|
+
case 'add':
|
|
495
|
+
return `Add ${recordText} to Lists`;
|
|
496
|
+
case 'remove':
|
|
497
|
+
return `Remove ${recordText} from Lists`;
|
|
498
|
+
default:
|
|
499
|
+
return `Manage List Membership`;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Get subtitle showing context
|
|
504
|
+
*/
|
|
505
|
+
get dialogSubtitle() {
|
|
506
|
+
const recordCount = this.config?.recordIds?.length || 0;
|
|
507
|
+
const entityName = this.config?.entityName || 'records';
|
|
508
|
+
if (recordCount === 1 && this.config?.recordDisplayNames?.[0]) {
|
|
509
|
+
return `"${this.config.recordDisplayNames[0]}" from ${entityName}`;
|
|
510
|
+
}
|
|
511
|
+
return `${recordCount} ${entityName} record${recordCount !== 1 ? 's' : ''}`;
|
|
512
|
+
}
|
|
513
|
+
/**
|
|
514
|
+
* Check if there are pending changes
|
|
515
|
+
*/
|
|
516
|
+
get hasChanges() {
|
|
517
|
+
return this.addedToLists.size > 0 || this.removedFromLists.size > 0;
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* Get count of lists to add to
|
|
521
|
+
*/
|
|
522
|
+
get addCount() {
|
|
523
|
+
return this.addedToLists.size;
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* Get count of lists to remove from
|
|
527
|
+
*/
|
|
528
|
+
get removeCount() {
|
|
529
|
+
return this.removedFromLists.size;
|
|
530
|
+
}
|
|
531
|
+
/**
|
|
532
|
+
* Setup search with debounce
|
|
533
|
+
*/
|
|
534
|
+
setupSearchDebounce() {
|
|
535
|
+
this.searchSubject.pipe(debounceTime(300), takeUntil(this.destroy$)).subscribe((searchText) => {
|
|
536
|
+
this.searchText = searchText;
|
|
537
|
+
this.applyFilters();
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
/**
|
|
541
|
+
* Initialize dialog when opened
|
|
542
|
+
*/
|
|
543
|
+
async initializeDialog() {
|
|
544
|
+
this.resetState();
|
|
545
|
+
await this.loadData();
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* Reset all state
|
|
549
|
+
*/
|
|
550
|
+
resetState() {
|
|
551
|
+
this.searchText = '';
|
|
552
|
+
this.activeTab = 'all';
|
|
553
|
+
this.sortOption = 'name';
|
|
554
|
+
this.showCreateForm = false;
|
|
555
|
+
this.newListName = '';
|
|
556
|
+
this.newListDescription = '';
|
|
557
|
+
this.newListCategoryId = null;
|
|
558
|
+
this.addedToLists.clear();
|
|
559
|
+
this.removedFromLists.clear();
|
|
560
|
+
this.newlyCreatedLists = [];
|
|
561
|
+
this.originalMembership.clear();
|
|
562
|
+
}
|
|
563
|
+
/**
|
|
564
|
+
* Load lists and membership data
|
|
565
|
+
*/
|
|
566
|
+
async loadData() {
|
|
567
|
+
if (!this.config)
|
|
568
|
+
return;
|
|
569
|
+
this.loading = true;
|
|
570
|
+
this.cdr.detectChanges();
|
|
571
|
+
try {
|
|
572
|
+
const md = new Metadata();
|
|
573
|
+
// Load lists and membership in parallel
|
|
574
|
+
const [lists, membership, categories] = await Promise.all([
|
|
575
|
+
this.listService.getListsForEntity(this.config.entityId, md.CurrentUser.ID, true // Force refresh
|
|
576
|
+
),
|
|
577
|
+
this.listService.getRecordMembership(this.config.entityId, this.config.recordIds),
|
|
578
|
+
this.listService.getListCategories()
|
|
579
|
+
]);
|
|
580
|
+
this.categories = categories;
|
|
581
|
+
// Build view models
|
|
582
|
+
this.allLists = await this.listService.buildListViewModels(lists, this.config.recordIds, membership);
|
|
583
|
+
// Store original membership state
|
|
584
|
+
for (const vm of this.allLists) {
|
|
585
|
+
this.originalMembership.set(vm.list.ID, vm.isFullMember || vm.isPartialMember);
|
|
586
|
+
}
|
|
587
|
+
// Pre-select lists if configured
|
|
588
|
+
if (this.config.preSelectedListIds) {
|
|
589
|
+
for (const listId of this.config.preSelectedListIds) {
|
|
590
|
+
const vm = this.allLists.find(l => l.list.ID === listId);
|
|
591
|
+
if (vm) {
|
|
592
|
+
vm.isSelectedForAdd = true;
|
|
593
|
+
this.addedToLists.add(listId);
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
this.applyFilters();
|
|
598
|
+
}
|
|
599
|
+
catch (error) {
|
|
600
|
+
console.error('Error loading list data:', error);
|
|
601
|
+
}
|
|
602
|
+
finally {
|
|
603
|
+
this.loading = false;
|
|
604
|
+
this.cdr.detectChanges();
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
/**
|
|
608
|
+
* Handle search input
|
|
609
|
+
*/
|
|
610
|
+
onSearchInput(event) {
|
|
611
|
+
const value = event.target.value;
|
|
612
|
+
this.searchSubject.next(value);
|
|
613
|
+
}
|
|
614
|
+
/**
|
|
615
|
+
* Clear search
|
|
616
|
+
*/
|
|
617
|
+
clearSearch() {
|
|
618
|
+
this.searchText = '';
|
|
619
|
+
this.searchSubject.next('');
|
|
620
|
+
}
|
|
621
|
+
/**
|
|
622
|
+
* Change active tab
|
|
623
|
+
*/
|
|
624
|
+
setActiveTab(tab) {
|
|
625
|
+
this.activeTab = tab;
|
|
626
|
+
this.applyFilters();
|
|
627
|
+
}
|
|
628
|
+
/**
|
|
629
|
+
* Change sort option
|
|
630
|
+
*/
|
|
631
|
+
setSortOption(option) {
|
|
632
|
+
this.sortOption = option;
|
|
633
|
+
this.applyFilters();
|
|
634
|
+
}
|
|
635
|
+
/**
|
|
636
|
+
* Apply all filters and sorting
|
|
637
|
+
*/
|
|
638
|
+
applyFilters() {
|
|
639
|
+
let result = [...this.allLists];
|
|
640
|
+
// Apply search filter
|
|
641
|
+
if (this.searchText.trim()) {
|
|
642
|
+
const search = this.searchText.toLowerCase();
|
|
643
|
+
result = result.filter(vm => vm.list.Name.toLowerCase().includes(search) ||
|
|
644
|
+
(vm.list.Description?.toLowerCase().includes(search)));
|
|
645
|
+
}
|
|
646
|
+
// Apply tab filter
|
|
647
|
+
switch (this.activeTab) {
|
|
648
|
+
case 'my-lists':
|
|
649
|
+
// Already filtered by user in loadData
|
|
650
|
+
break;
|
|
651
|
+
case 'recent':
|
|
652
|
+
// Sort by last updated and take top 10
|
|
653
|
+
result = result
|
|
654
|
+
.sort((a, b) => b.lastUpdated.getTime() - a.lastUpdated.getTime())
|
|
655
|
+
.slice(0, 10);
|
|
656
|
+
break;
|
|
657
|
+
// 'all' and 'shared' - no additional filtering for now
|
|
658
|
+
}
|
|
659
|
+
// Apply sorting
|
|
660
|
+
switch (this.sortOption) {
|
|
661
|
+
case 'name':
|
|
662
|
+
result.sort((a, b) => a.list.Name.localeCompare(b.list.Name));
|
|
663
|
+
break;
|
|
664
|
+
case 'recent':
|
|
665
|
+
result.sort((a, b) => b.lastUpdated.getTime() - a.lastUpdated.getTime());
|
|
666
|
+
break;
|
|
667
|
+
case 'item-count':
|
|
668
|
+
result.sort((a, b) => b.itemCount - a.itemCount);
|
|
669
|
+
break;
|
|
670
|
+
}
|
|
671
|
+
this.filteredLists = result;
|
|
672
|
+
this.cdr.detectChanges();
|
|
673
|
+
}
|
|
674
|
+
/**
|
|
675
|
+
* Toggle list selection for adding
|
|
676
|
+
*/
|
|
677
|
+
toggleListForAdd(vm) {
|
|
678
|
+
if (this.config?.mode === 'remove')
|
|
679
|
+
return;
|
|
680
|
+
const listId = vm.list.ID;
|
|
681
|
+
if (vm.isSelectedForAdd || this.addedToLists.has(listId)) {
|
|
682
|
+
// Deselect
|
|
683
|
+
vm.isSelectedForAdd = false;
|
|
684
|
+
this.addedToLists.delete(listId);
|
|
685
|
+
}
|
|
686
|
+
else {
|
|
687
|
+
// Select for add
|
|
688
|
+
vm.isSelectedForAdd = true;
|
|
689
|
+
vm.isSelectedForRemove = false;
|
|
690
|
+
this.addedToLists.add(listId);
|
|
691
|
+
this.removedFromLists.delete(listId);
|
|
692
|
+
}
|
|
693
|
+
this.cdr.detectChanges();
|
|
694
|
+
}
|
|
695
|
+
/**
|
|
696
|
+
* Toggle list selection for removal
|
|
697
|
+
*/
|
|
698
|
+
toggleListForRemove(vm) {
|
|
699
|
+
if (this.config?.mode === 'add')
|
|
700
|
+
return;
|
|
701
|
+
if (!this.config?.allowRemove && this.config?.mode !== 'manage')
|
|
702
|
+
return;
|
|
703
|
+
const listId = vm.list.ID;
|
|
704
|
+
if (vm.isSelectedForRemove || this.removedFromLists.has(listId)) {
|
|
705
|
+
// Deselect
|
|
706
|
+
vm.isSelectedForRemove = false;
|
|
707
|
+
this.removedFromLists.delete(listId);
|
|
708
|
+
}
|
|
709
|
+
else {
|
|
710
|
+
// Select for remove
|
|
711
|
+
vm.isSelectedForRemove = true;
|
|
712
|
+
vm.isSelectedForAdd = false;
|
|
713
|
+
this.removedFromLists.add(listId);
|
|
714
|
+
this.addedToLists.delete(listId);
|
|
715
|
+
}
|
|
716
|
+
this.cdr.detectChanges();
|
|
717
|
+
}
|
|
718
|
+
/**
|
|
719
|
+
* Get membership indicator class
|
|
720
|
+
*/
|
|
721
|
+
getMembershipClass(vm) {
|
|
722
|
+
if (vm.isFullMember)
|
|
723
|
+
return 'full-member';
|
|
724
|
+
if (vm.isPartialMember)
|
|
725
|
+
return 'partial-member';
|
|
726
|
+
return 'not-member';
|
|
727
|
+
}
|
|
728
|
+
/**
|
|
729
|
+
* Get membership indicator text
|
|
730
|
+
*/
|
|
731
|
+
getMembershipText(vm) {
|
|
732
|
+
if (vm.isFullMember) {
|
|
733
|
+
return `${vm.membershipCount}/${vm.totalSelectedRecords}`;
|
|
734
|
+
}
|
|
735
|
+
if (vm.isPartialMember) {
|
|
736
|
+
return `${vm.membershipCount}/${vm.totalSelectedRecords}`;
|
|
737
|
+
}
|
|
738
|
+
return `0/${vm.totalSelectedRecords}`;
|
|
739
|
+
}
|
|
740
|
+
/**
|
|
741
|
+
* Get membership icon
|
|
742
|
+
*/
|
|
743
|
+
getMembershipIcon(vm) {
|
|
744
|
+
if (vm.isFullMember)
|
|
745
|
+
return 'fa-solid fa-check-circle';
|
|
746
|
+
if (vm.isPartialMember)
|
|
747
|
+
return 'fa-solid fa-circle-half-stroke';
|
|
748
|
+
return 'fa-regular fa-circle';
|
|
749
|
+
}
|
|
750
|
+
/**
|
|
751
|
+
* Show create list form
|
|
752
|
+
*/
|
|
753
|
+
showCreateListForm() {
|
|
754
|
+
this.showCreateForm = true;
|
|
755
|
+
this.newListName = '';
|
|
756
|
+
this.newListDescription = '';
|
|
757
|
+
this.newListCategoryId = null;
|
|
758
|
+
}
|
|
759
|
+
/**
|
|
760
|
+
* Cancel create list form
|
|
761
|
+
*/
|
|
762
|
+
cancelCreateList() {
|
|
763
|
+
this.showCreateForm = false;
|
|
764
|
+
this.newListName = '';
|
|
765
|
+
this.newListDescription = '';
|
|
766
|
+
this.newListCategoryId = null;
|
|
767
|
+
}
|
|
768
|
+
/**
|
|
769
|
+
* Create a new list
|
|
770
|
+
*/
|
|
771
|
+
async createList() {
|
|
772
|
+
if (!this.newListName.trim() || !this.config)
|
|
773
|
+
return;
|
|
774
|
+
this.saving = true;
|
|
775
|
+
try {
|
|
776
|
+
const createConfig = {
|
|
777
|
+
name: this.newListName.trim(),
|
|
778
|
+
description: this.newListDescription.trim() || undefined,
|
|
779
|
+
categoryId: this.newListCategoryId || undefined,
|
|
780
|
+
entityId: this.config.entityId
|
|
781
|
+
};
|
|
782
|
+
const newList = await this.listService.createList(createConfig);
|
|
783
|
+
if (newList) {
|
|
784
|
+
this.newlyCreatedLists.push(newList);
|
|
785
|
+
// Add to view models and select for add
|
|
786
|
+
const vm = {
|
|
787
|
+
list: newList,
|
|
788
|
+
itemCount: 0,
|
|
789
|
+
membershipCount: 0,
|
|
790
|
+
totalSelectedRecords: this.config.recordIds.length,
|
|
791
|
+
isFullMember: false,
|
|
792
|
+
isPartialMember: false,
|
|
793
|
+
isNotMember: true,
|
|
794
|
+
lastUpdated: new Date(),
|
|
795
|
+
isSelectedForAdd: true,
|
|
796
|
+
isSelectedForRemove: false
|
|
797
|
+
};
|
|
798
|
+
this.allLists.unshift(vm);
|
|
799
|
+
this.addedToLists.add(newList.ID);
|
|
800
|
+
this.showCreateForm = false;
|
|
801
|
+
this.newListName = '';
|
|
802
|
+
this.newListDescription = '';
|
|
803
|
+
this.newListCategoryId = null;
|
|
804
|
+
this.applyFilters();
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
catch (error) {
|
|
808
|
+
console.error('Error creating list:', error);
|
|
809
|
+
}
|
|
810
|
+
finally {
|
|
811
|
+
this.saving = false;
|
|
812
|
+
this.cdr.detectChanges();
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
/**
|
|
816
|
+
* Apply changes and close dialog
|
|
817
|
+
*/
|
|
818
|
+
async applyChanges() {
|
|
819
|
+
if (!this.config)
|
|
820
|
+
return;
|
|
821
|
+
this.saving = true;
|
|
822
|
+
const result = {
|
|
823
|
+
action: 'apply',
|
|
824
|
+
added: [],
|
|
825
|
+
removed: [],
|
|
826
|
+
newListsCreated: this.newlyCreatedLists
|
|
827
|
+
};
|
|
828
|
+
try {
|
|
829
|
+
// Process additions
|
|
830
|
+
if (this.addedToLists.size > 0) {
|
|
831
|
+
console.log(`[ListManagementDialog] Processing additions:`);
|
|
832
|
+
console.log(` - Lists to add to:`, [...this.addedToLists]);
|
|
833
|
+
console.log(` - Record IDs:`, this.config.recordIds);
|
|
834
|
+
const addResult = await this.listService.addRecordsToLists([...this.addedToLists], this.config.recordIds, true // Skip duplicates
|
|
835
|
+
);
|
|
836
|
+
console.log(`[ListManagementDialog] Add result:`, addResult);
|
|
837
|
+
for (const listId of this.addedToLists) {
|
|
838
|
+
const vm = this.allLists.find(l => l.list.ID === listId);
|
|
839
|
+
if (vm) {
|
|
840
|
+
result.added.push({
|
|
841
|
+
listId,
|
|
842
|
+
listName: vm.list.Name,
|
|
843
|
+
recordIds: this.config.recordIds
|
|
844
|
+
});
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
// Process removals
|
|
849
|
+
if (this.removedFromLists.size > 0) {
|
|
850
|
+
const removeResult = await this.listService.removeRecordsFromLists([...this.removedFromLists], this.config.recordIds);
|
|
851
|
+
for (const listId of this.removedFromLists) {
|
|
852
|
+
const vm = this.allLists.find(l => l.list.ID === listId);
|
|
853
|
+
if (vm) {
|
|
854
|
+
result.removed.push({
|
|
855
|
+
listId,
|
|
856
|
+
listName: vm.list.Name,
|
|
857
|
+
recordIds: this.config.recordIds
|
|
858
|
+
});
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
this.complete.emit(result);
|
|
863
|
+
}
|
|
864
|
+
catch (error) {
|
|
865
|
+
console.error('Error applying changes:', error);
|
|
866
|
+
}
|
|
867
|
+
finally {
|
|
868
|
+
this.saving = false;
|
|
869
|
+
this._visible = false;
|
|
870
|
+
this.cdr.detectChanges();
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
/**
|
|
874
|
+
* Cancel and close dialog
|
|
875
|
+
*/
|
|
876
|
+
onCancel() {
|
|
877
|
+
const result = {
|
|
878
|
+
action: 'cancel',
|
|
879
|
+
added: [],
|
|
880
|
+
removed: [],
|
|
881
|
+
newListsCreated: []
|
|
882
|
+
};
|
|
883
|
+
this._visible = false;
|
|
884
|
+
this.cancel.emit();
|
|
885
|
+
}
|
|
886
|
+
/**
|
|
887
|
+
* Format date for display
|
|
888
|
+
*/
|
|
889
|
+
formatDate(date) {
|
|
890
|
+
const now = new Date();
|
|
891
|
+
const diff = now.getTime() - date.getTime();
|
|
892
|
+
const minutes = Math.floor(diff / 60000);
|
|
893
|
+
const hours = Math.floor(minutes / 60);
|
|
894
|
+
const days = Math.floor(hours / 24);
|
|
895
|
+
if (minutes < 1)
|
|
896
|
+
return 'just now';
|
|
897
|
+
if (minutes < 60)
|
|
898
|
+
return `${minutes}m ago`;
|
|
899
|
+
if (hours < 24)
|
|
900
|
+
return `${hours}h ago`;
|
|
901
|
+
if (days < 7)
|
|
902
|
+
return `${days}d ago`;
|
|
903
|
+
return date.toLocaleDateString();
|
|
904
|
+
}
|
|
905
|
+
/**
|
|
906
|
+
* Check if we should show the add button for a list
|
|
907
|
+
*/
|
|
908
|
+
showAddButton(vm) {
|
|
909
|
+
if (this.config?.mode === 'remove')
|
|
910
|
+
return false;
|
|
911
|
+
return !vm.isFullMember || !this.originalMembership.get(vm.list.ID);
|
|
912
|
+
}
|
|
913
|
+
/**
|
|
914
|
+
* Check if we should show the remove button for a list
|
|
915
|
+
*/
|
|
916
|
+
showRemoveButton(vm) {
|
|
917
|
+
if (this.config?.mode === 'add')
|
|
918
|
+
return false;
|
|
919
|
+
if (!this.config?.allowRemove && this.config?.mode !== 'manage')
|
|
920
|
+
return false;
|
|
921
|
+
return vm.isFullMember || vm.isPartialMember || this.originalMembership.get(vm.list.ID) === true;
|
|
922
|
+
}
|
|
923
|
+
static ɵfac = function ListManagementDialogComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ListManagementDialogComponent)(i0.ɵɵdirectiveInject(i1.ListManagementService), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
|
|
924
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ListManagementDialogComponent, selectors: [["mj-list-management-dialog"]], inputs: { config: "config", visible: "visible" }, outputs: { complete: "complete", cancel: "cancel" }, decls: 1, vars: 1, consts: [[1, "dialog-overlay"], [1, "dialog-overlay", 3, "click"], [1, "dialog-container", 3, "click"], [1, "dialog-header"], [1, "header-content"], [1, "header-icon"], [1, "fa-solid", "fa-rectangle-list"], [1, "header-text"], [1, "dialog-title"], [1, "dialog-subtitle"], ["title", "Close", 1, "close-button", 3, "click"], [1, "fa-solid", "fa-times"], [1, "search-section"], [1, "search-bar"], [1, "fa-solid", "fa-search", "search-icon"], ["type", "text", "placeholder", "Search lists...", 1, "search-input", 3, "input", "value"], [1, "clear-search"], [1, "create-button", 3, "disabled"], [1, "filter-tabs"], [1, "tabs-left"], [1, "tab-button", 3, "click"], [1, "tabs-right"], [1, "sort-select", 3, "change", "value"], ["value", "name"], ["value", "recent"], ["value", "item-count"], [1, "create-form"], [1, "list-content"], [1, "loading-state"], [1, "empty-state"], [1, "list-items"], [1, "dialog-footer"], [1, "footer-summary"], [1, "summary-empty"], [1, "footer-actions"], [1, "btn", "btn-secondary", 3, "click", "disabled"], [1, "btn", "btn-primary", 3, "click", "disabled"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "clear-search", 3, "click"], [1, "fa-solid", "fa-times-circle"], [1, "create-button", 3, "click", "disabled"], [1, "fa-solid", "fa-plus"], [1, "button-text"], [1, "create-form-header"], [1, "fa-solid", "fa-plus-circle"], [1, "create-form-body"], [1, "form-group"], ["type", "text", "placeholder", "List name *", 1, "form-input", 3, "ngModelChange", "keyup.enter", "ngModel", "disabled"], ["placeholder", "Description (optional)", "rows", "2", 1, "form-input", "form-textarea", 3, "ngModelChange", "ngModel", "disabled"], [1, "create-form-actions"], [1, "form-input", 3, "ngModelChange", "ngModel", "disabled"], [3, "ngValue"], ["text", "Loading lists...", "size", "medium"], [1, "fa-solid", "fa-search", "empty-icon"], [1, "empty-title"], [1, "empty-subtitle"], [1, "fa-solid", "fa-rectangle-list", "empty-icon"], [1, "btn", "btn-primary"], [1, "btn", "btn-primary", 3, "click"], [1, "list-item", 3, "selected-add", "selected-remove", "is-member"], [1, "list-item"], [1, "list-item-select"], [1, "select-btn", "add-btn", 3, "selected", "title"], [1, "select-btn", "remove-btn", 3, "selected", "title"], [1, "list-item-content"], [1, "list-item-header"], [1, "fa-solid", "fa-folder", "list-icon"], [1, "list-name"], [1, "badge", "badge-new"], [1, "list-item-meta"], [1, "list-count"], [1, "meta-separator"], [1, "list-updated"], [1, "membership-indicator", 3, "class"], [1, "select-btn", "add-btn", 3, "click", "title"], [1, "fa-solid", "fa-check"], [1, "select-btn", "remove-btn", 3, "click", "title"], [1, "fa-solid", "fa-undo"], [1, "fa-solid", "fa-minus"], [1, "list-description"], [1, "membership-indicator"], [1, "membership-text"], [1, "summary-item", "add"], [1, "summary-item", "remove"], [1, "fa-solid", "fa-minus-circle"]], template: function ListManagementDialogComponent_Template(rf, ctx) { if (rf & 1) {
|
|
925
|
+
i0.ɵɵtemplate(0, ListManagementDialogComponent_Conditional_0_Template, 50, 18, "div", 0);
|
|
926
|
+
} if (rf & 2) {
|
|
927
|
+
i0.ɵɵconditional(ctx.visible ? 0 : -1);
|
|
928
|
+
} }, dependencies: [i2.NgSelectOption, i2.ɵNgSelectMultipleOption, i2.DefaultValueAccessor, i2.SelectControlValueAccessor, i2.NgControlStatus, i2.NgModel, i3.LoadingComponent], styles: ["\n\n\n\n\n\n\n.dialog-overlay[_ngcontent-%COMP%] {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10000;\n animation: _ngcontent-%COMP%_fadeIn 0.2s ease-out;\n backdrop-filter: blur(2px);\n}\n\n@keyframes _ngcontent-%COMP%_fadeIn {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n\n\n.dialog-container[_ngcontent-%COMP%] {\n background: #ffffff;\n border-radius: 16px;\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);\n width: 90vw;\n max-width: 600px;\n max-height: 85vh;\n display: flex;\n flex-direction: column;\n animation: _ngcontent-%COMP%_slideUp 0.3s ease-out;\n overflow: hidden;\n}\n\n@keyframes _ngcontent-%COMP%_slideUp {\n from {\n opacity: 0;\n transform: translateY(20px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n\n\n.dialog-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 20px 24px;\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n}\n\n.header-content[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 16px;\n}\n\n.header-icon[_ngcontent-%COMP%] {\n width: 48px;\n height: 48px;\n background: rgba(255, 255, 255, 0.2);\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 22px;\n}\n\n.header-text[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.dialog-title[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 18px;\n font-weight: 600;\n letter-spacing: -0.01em;\n}\n\n.dialog-subtitle[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 13px;\n opacity: 0.85;\n}\n\n.close-button[_ngcontent-%COMP%] {\n width: 36px;\n height: 36px;\n border: none;\n background: rgba(255, 255, 255, 0.15);\n border-radius: 8px;\n color: white;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 16px;\n transition: background 0.2s;\n}\n\n.close-button[_ngcontent-%COMP%]:hover {\n background: rgba(255, 255, 255, 0.25);\n}\n\n\n\n.search-section[_ngcontent-%COMP%] {\n display: flex;\n gap: 12px;\n padding: 16px 20px;\n background: #f8fafc;\n border-bottom: 1px solid #e2e8f0;\n}\n\n.search-bar[_ngcontent-%COMP%] {\n flex: 1;\n position: relative;\n display: flex;\n align-items: center;\n}\n\n.search-icon[_ngcontent-%COMP%] {\n position: absolute;\n left: 14px;\n color: #94a3b8;\n font-size: 14px;\n pointer-events: none;\n}\n\n.search-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 12px 40px 12px 42px;\n border: 1px solid #e2e8f0;\n border-radius: 10px;\n font-size: 14px;\n background: white;\n transition: all 0.2s;\n}\n\n.search-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: #667eea;\n box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.15);\n}\n\n.search-input[_ngcontent-%COMP%]::placeholder {\n color: #94a3b8;\n}\n\n.clear-search[_ngcontent-%COMP%] {\n position: absolute;\n right: 12px;\n border: none;\n background: none;\n color: #94a3b8;\n cursor: pointer;\n padding: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.clear-search[_ngcontent-%COMP%]:hover {\n color: #64748b;\n}\n\n.create-button[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 18px;\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n border: none;\n border-radius: 10px;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s;\n white-space: nowrap;\n}\n\n.create-button[_ngcontent-%COMP%]:hover:not(:disabled) {\n transform: translateY(-1px);\n box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);\n}\n\n.create-button[_ngcontent-%COMP%]:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n\n\n.filter-tabs[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 20px;\n border-bottom: 1px solid #e2e8f0;\n background: white;\n}\n\n.tabs-left[_ngcontent-%COMP%] {\n display: flex;\n gap: 4px;\n}\n\n.tab-button[_ngcontent-%COMP%] {\n padding: 8px 16px;\n border: none;\n background: none;\n color: #64748b;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n border-radius: 6px;\n transition: all 0.2s;\n}\n\n.tab-button[_ngcontent-%COMP%]:hover {\n background: #f1f5f9;\n color: #334155;\n}\n\n.tab-button.active[_ngcontent-%COMP%] {\n background: #ede9fe;\n color: #7c3aed;\n}\n\n.sort-select[_ngcontent-%COMP%] {\n padding: 8px 12px;\n border: 1px solid #e2e8f0;\n border-radius: 6px;\n font-size: 13px;\n color: #64748b;\n background: white;\n cursor: pointer;\n}\n\n.sort-select[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: #667eea;\n}\n\n\n\n.create-form[_ngcontent-%COMP%] {\n background: #fefce8;\n border-bottom: 1px solid #fde047;\n animation: _ngcontent-%COMP%_slideDown 0.2s ease-out;\n}\n\n@keyframes _ngcontent-%COMP%_slideDown {\n from {\n opacity: 0;\n max-height: 0;\n }\n to {\n opacity: 1;\n max-height: 300px;\n }\n}\n\n.create-form-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 12px 20px;\n font-weight: 600;\n color: #854d0e;\n font-size: 14px;\n border-bottom: 1px solid #fde047;\n}\n\n.create-form-body[_ngcontent-%COMP%] {\n padding: 16px 20px;\n}\n\n.form-group[_ngcontent-%COMP%] {\n margin-bottom: 12px;\n}\n\n.form-group[_ngcontent-%COMP%]:last-of-type {\n margin-bottom: 16px;\n}\n\n.form-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 12px 14px;\n border: 1px solid #e2e8f0;\n border-radius: 8px;\n font-size: 14px;\n background: white;\n transition: all 0.2s;\n box-sizing: border-box;\n}\n\n.form-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: #667eea;\n box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.15);\n}\n\n.form-textarea[_ngcontent-%COMP%] {\n resize: vertical;\n min-height: 60px;\n}\n\n.create-form-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 10px;\n justify-content: flex-end;\n}\n\n\n\n.list-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n min-height: 200px;\n max-height: 400px;\n}\n\n\n\n.loading-state[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 60px 20px;\n}\n\n\n\n.empty-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 20px;\n text-align: center;\n}\n\n.empty-icon[_ngcontent-%COMP%] {\n font-size: 48px;\n color: #cbd5e1;\n margin-bottom: 16px;\n}\n\n.empty-title[_ngcontent-%COMP%] {\n font-size: 16px;\n font-weight: 600;\n color: #334155;\n margin: 0 0 6px 0;\n}\n\n.empty-subtitle[_ngcontent-%COMP%] {\n font-size: 14px;\n color: #64748b;\n margin: 0 0 20px 0;\n}\n\n\n\n.list-items[_ngcontent-%COMP%] {\n padding: 8px 12px;\n}\n\n.list-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 14px 16px;\n margin-bottom: 8px;\n background: white;\n border: 1px solid #e2e8f0;\n border-radius: 12px;\n transition: all 0.2s;\n}\n\n.list-item[_ngcontent-%COMP%]:last-child {\n margin-bottom: 0;\n}\n\n.list-item[_ngcontent-%COMP%]:hover {\n border-color: #cbd5e1;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);\n}\n\n.list-item.selected-add[_ngcontent-%COMP%] {\n background: #ecfdf5;\n border-color: #10b981;\n}\n\n.list-item.selected-remove[_ngcontent-%COMP%] {\n background: #fef2f2;\n border-color: #ef4444;\n}\n\n.list-item.is-member[_ngcontent-%COMP%] {\n border-left: 3px solid #667eea;\n}\n\n\n\n.list-item-select[_ngcontent-%COMP%] {\n display: flex;\n gap: 6px;\n}\n\n.select-btn[_ngcontent-%COMP%] {\n width: 32px;\n height: 32px;\n border: 1px solid #e2e8f0;\n border-radius: 8px;\n background: white;\n color: #64748b;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n transition: all 0.2s;\n}\n\n.select-btn.add-btn[_ngcontent-%COMP%]:hover {\n border-color: #10b981;\n color: #10b981;\n background: #ecfdf5;\n}\n\n.select-btn.add-btn.selected[_ngcontent-%COMP%] {\n background: #10b981;\n border-color: #10b981;\n color: white;\n}\n\n.select-btn.remove-btn[_ngcontent-%COMP%]:hover {\n border-color: #ef4444;\n color: #ef4444;\n background: #fef2f2;\n}\n\n.select-btn.remove-btn.selected[_ngcontent-%COMP%] {\n background: #ef4444;\n border-color: #ef4444;\n color: white;\n}\n\n\n\n.list-item-content[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.list-item-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n margin-bottom: 4px;\n}\n\n.list-icon[_ngcontent-%COMP%] {\n color: #667eea;\n font-size: 14px;\n}\n\n.list-name[_ngcontent-%COMP%] {\n font-weight: 600;\n font-size: 14px;\n color: #1e293b;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.badge[_ngcontent-%COMP%] {\n padding: 2px 8px;\n border-radius: 10px;\n font-size: 10px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.02em;\n}\n\n.badge-new[_ngcontent-%COMP%] {\n background: #dbeafe;\n color: #2563eb;\n}\n\n.list-item-meta[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 4px;\n font-size: 12px;\n color: #64748b;\n}\n\n.list-description[_ngcontent-%COMP%] {\n max-width: 180px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.meta-separator[_ngcontent-%COMP%] {\n color: #cbd5e1;\n}\n\n\n\n.membership-indicator[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n border-radius: 20px;\n font-size: 12px;\n font-weight: 500;\n white-space: nowrap;\n}\n\n.membership-indicator.full-member[_ngcontent-%COMP%] {\n background: #dcfce7;\n color: #16a34a;\n}\n\n.membership-indicator.partial-member[_ngcontent-%COMP%] {\n background: #fef3c7;\n color: #d97706;\n}\n\n.membership-indicator.not-member[_ngcontent-%COMP%] {\n background: #f1f5f9;\n color: #64748b;\n}\n\n.membership-text[_ngcontent-%COMP%] {\n font-variant-numeric: tabular-nums;\n}\n\n\n\n.dialog-footer[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 20px;\n background: #f8fafc;\n border-top: 1px solid #e2e8f0;\n}\n\n.footer-summary[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 16px;\n}\n\n.summary-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 13px;\n font-weight: 500;\n}\n\n.summary-item.add[_ngcontent-%COMP%] {\n color: #16a34a;\n}\n\n.summary-item.remove[_ngcontent-%COMP%] {\n color: #dc2626;\n}\n\n.summary-empty[_ngcontent-%COMP%] {\n color: #94a3b8;\n font-size: 13px;\n}\n\n.footer-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 10px;\n}\n\n\n\n.btn[_ngcontent-%COMP%] {\n padding: 10px 20px;\n border-radius: 8px;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 8px;\n transition: all 0.2s;\n border: none;\n}\n\n.btn-primary[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n}\n\n.btn-primary[_ngcontent-%COMP%]:hover:not(:disabled) {\n box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);\n transform: translateY(-1px);\n}\n\n.btn-primary[_ngcontent-%COMP%]:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n transform: none;\n}\n\n.btn-secondary[_ngcontent-%COMP%] {\n background: white;\n color: #64748b;\n border: 1px solid #e2e8f0;\n}\n\n.btn-secondary[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: #f8fafc;\n border-color: #cbd5e1;\n}\n\n.btn-secondary[_ngcontent-%COMP%]:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n\n\n\n\n\n@media (max-width: 640px) {\n .dialog-overlay[_ngcontent-%COMP%] {\n align-items: flex-end;\n }\n\n .dialog-container[_ngcontent-%COMP%] {\n width: 100%;\n max-width: 100%;\n max-height: 90vh;\n border-radius: 24px 24px 0 0;\n animation: slideUpMobile 0.3s ease-out;\n }\n\n @keyframes slideUpMobile {\n from {\n transform: translateY(100%);\n }\n to {\n transform: translateY(0);\n }\n }\n\n .dialog-header[_ngcontent-%COMP%] {\n padding: 16px 20px;\n border-radius: 24px 24px 0 0;\n }\n\n .header-icon[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n font-size: 18px;\n }\n\n .dialog-title[_ngcontent-%COMP%] {\n font-size: 16px;\n }\n\n .dialog-subtitle[_ngcontent-%COMP%] {\n font-size: 12px;\n }\n\n .search-section[_ngcontent-%COMP%] {\n padding: 12px 16px;\n flex-wrap: wrap;\n }\n\n .search-bar[_ngcontent-%COMP%] {\n width: 100%;\n order: 1;\n }\n\n .create-button[_ngcontent-%COMP%] {\n order: 2;\n width: 100%;\n justify-content: center;\n margin-top: 8px;\n }\n\n .button-text[_ngcontent-%COMP%] {\n display: inline;\n }\n\n .filter-tabs[_ngcontent-%COMP%] {\n padding: 10px 16px;\n flex-wrap: wrap;\n gap: 8px;\n }\n\n .tabs-left[_ngcontent-%COMP%] {\n width: 100%;\n justify-content: space-between;\n }\n\n .tab-button[_ngcontent-%COMP%] {\n flex: 1;\n text-align: center;\n padding: 10px 8px;\n }\n\n .tabs-right[_ngcontent-%COMP%] {\n width: 100%;\n }\n\n .sort-select[_ngcontent-%COMP%] {\n width: 100%;\n }\n\n .list-content[_ngcontent-%COMP%] {\n max-height: 50vh;\n }\n\n .list-items[_ngcontent-%COMP%] {\n padding: 8px;\n }\n\n .list-item[_ngcontent-%COMP%] {\n padding: 12px;\n gap: 10px;\n }\n\n .list-item-content[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n }\n\n .list-description[_ngcontent-%COMP%] {\n display: none;\n }\n\n .membership-indicator[_ngcontent-%COMP%] {\n padding: 4px 8px;\n font-size: 11px;\n }\n\n .dialog-footer[_ngcontent-%COMP%] {\n padding: 12px 16px;\n flex-direction: column;\n gap: 12px;\n }\n\n .footer-summary[_ngcontent-%COMP%] {\n width: 100%;\n justify-content: center;\n }\n\n .footer-actions[_ngcontent-%COMP%] {\n width: 100%;\n }\n\n .footer-actions[_ngcontent-%COMP%] .btn[_ngcontent-%COMP%] {\n flex: 1;\n justify-content: center;\n }\n\n .create-form-body[_ngcontent-%COMP%] {\n padding: 12px 16px;\n }\n\n .create-form-actions[_ngcontent-%COMP%] {\n flex-direction: column;\n }\n\n .create-form-actions[_ngcontent-%COMP%] .btn[_ngcontent-%COMP%] {\n width: 100%;\n justify-content: center;\n }\n}\n\n\n\n@media (min-width: 641px) and (max-width: 1024px) {\n .dialog-container[_ngcontent-%COMP%] {\n max-width: 550px;\n }\n\n .list-description[_ngcontent-%COMP%] {\n max-width: 140px;\n }\n}\n\n\n\n@media (min-width: 1025px) {\n .list-content[_ngcontent-%COMP%] {\n max-height: 450px;\n }\n\n .list-item[_ngcontent-%COMP%]:hover {\n transform: translateX(4px);\n }\n}\n\n\n\n.search-input[_ngcontent-%COMP%]:focus-visible, \n.tab-button[_ngcontent-%COMP%]:focus-visible, \n.select-btn[_ngcontent-%COMP%]:focus-visible, \n.btn[_ngcontent-%COMP%]:focus-visible {\n outline: 2px solid #667eea;\n outline-offset: 2px;\n}\n\n\n\n@media (prefers-reduced-motion: reduce) {\n .dialog-overlay[_ngcontent-%COMP%], \n .dialog-container[_ngcontent-%COMP%], \n .create-form[_ngcontent-%COMP%], \n .list-item[_ngcontent-%COMP%], \n .btn[_ngcontent-%COMP%] {\n animation: none;\n transition: none;\n }\n}"] });
|
|
929
|
+
}
|
|
930
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ListManagementDialogComponent, [{
|
|
931
|
+
type: Component,
|
|
932
|
+
args: [{ selector: 'mj-list-management-dialog', template: "@if (visible) {\n <div class=\"dialog-overlay\" (click)=\"onCancel()\">\n <div class=\"dialog-container\" (click)=\"$event.stopPropagation()\">\n <!-- Header -->\n <div class=\"dialog-header\">\n <div class=\"header-content\">\n <div class=\"header-icon\">\n <span class=\"fa-solid fa-rectangle-list\"></span>\n </div>\n <div class=\"header-text\">\n <h2 class=\"dialog-title\">{{ dialogTitle }}</h2>\n <p class=\"dialog-subtitle\">{{ dialogSubtitle }}</p>\n </div>\n </div>\n <button class=\"close-button\" (click)=\"onCancel()\" title=\"Close\">\n <span class=\"fa-solid fa-times\"></span>\n </button>\n </div>\n\n <!-- Search and Filters -->\n <div class=\"search-section\">\n <div class=\"search-bar\">\n <span class=\"fa-solid fa-search search-icon\"></span>\n <input\n type=\"text\"\n class=\"search-input\"\n placeholder=\"Search lists...\"\n [value]=\"searchText\"\n (input)=\"onSearchInput($event)\"\n />\n @if (searchText) {\n <button class=\"clear-search\" (click)=\"clearSearch()\">\n <span class=\"fa-solid fa-times-circle\"></span>\n </button>\n }\n </div>\n\n @if (config.allowCreate !== false) {\n <button class=\"create-button\" (click)=\"showCreateListForm()\" [disabled]=\"showCreateForm\">\n <span class=\"fa-solid fa-plus\"></span>\n <span class=\"button-text\">New</span>\n </button>\n }\n </div>\n\n <!-- Filter Tabs -->\n <div class=\"filter-tabs\">\n <div class=\"tabs-left\">\n <button\n class=\"tab-button\"\n [class.active]=\"activeTab === 'all'\"\n (click)=\"setActiveTab('all')\">\n All\n </button>\n <button\n class=\"tab-button\"\n [class.active]=\"activeTab === 'my-lists'\"\n (click)=\"setActiveTab('my-lists')\">\n My Lists\n </button>\n <button\n class=\"tab-button\"\n [class.active]=\"activeTab === 'recent'\"\n (click)=\"setActiveTab('recent')\">\n Recent\n </button>\n </div>\n <div class=\"tabs-right\">\n <select class=\"sort-select\" [value]=\"sortOption\" (change)=\"setSortOption($any($event.target).value)\">\n <option value=\"name\">Sort: Name</option>\n <option value=\"recent\">Sort: Recent</option>\n <option value=\"item-count\">Sort: Items</option>\n </select>\n </div>\n </div>\n\n <!-- Create List Form -->\n @if (showCreateForm) {\n <div class=\"create-form\">\n <div class=\"create-form-header\">\n <span class=\"fa-solid fa-plus-circle\"></span>\n <span>Create New List</span>\n </div>\n <div class=\"create-form-body\">\n <div class=\"form-group\">\n <input\n type=\"text\"\n class=\"form-input\"\n placeholder=\"List name *\"\n [(ngModel)]=\"newListName\"\n [disabled]=\"saving\"\n (keyup.enter)=\"createList()\"\n />\n </div>\n <div class=\"form-group\">\n <textarea\n class=\"form-input form-textarea\"\n placeholder=\"Description (optional)\"\n [(ngModel)]=\"newListDescription\"\n [disabled]=\"saving\"\n rows=\"2\">\n </textarea>\n </div>\n @if (categories.length > 0) {\n <div class=\"form-group\">\n <select class=\"form-input\" [(ngModel)]=\"newListCategoryId\" [disabled]=\"saving\">\n <option [ngValue]=\"null\">No category</option>\n @for (category of categories; track category.ID) {\n <option [ngValue]=\"category.ID\">{{ category.Name }}</option>\n }\n </select>\n </div>\n }\n <div class=\"create-form-actions\">\n <button\n class=\"btn btn-primary\"\n (click)=\"createList()\"\n [disabled]=\"!newListName.trim() || saving\">\n @if (saving) {\n <span class=\"fa-solid fa-spinner fa-spin\"></span>\n }\n Create List\n </button>\n <button class=\"btn btn-secondary\" (click)=\"cancelCreateList()\" [disabled]=\"saving\">\n Cancel\n </button>\n </div>\n </div>\n </div>\n }\n\n <!-- List Content -->\n <div class=\"list-content\">\n @if (loading) {\n <div class=\"loading-state\">\n <mj-loading text=\"Loading lists...\" size=\"medium\"></mj-loading>\n </div>\n } @else if (filteredLists.length === 0) {\n <div class=\"empty-state\">\n @if (searchText) {\n <span class=\"fa-solid fa-search empty-icon\"></span>\n <p class=\"empty-title\">No lists found</p>\n <p class=\"empty-subtitle\">Try a different search term</p>\n } @else {\n <span class=\"fa-solid fa-rectangle-list empty-icon\"></span>\n <p class=\"empty-title\">No lists yet</p>\n <p class=\"empty-subtitle\">Create your first list to get started</p>\n @if (config.allowCreate !== false) {\n <button class=\"btn btn-primary\" (click)=\"showCreateListForm()\">\n <span class=\"fa-solid fa-plus\"></span>\n Create List\n </button>\n }\n }\n </div>\n } @else {\n <div class=\"list-items\">\n @for (vm of filteredLists; track vm.list.ID) {\n <div\n class=\"list-item\"\n [class.selected-add]=\"vm.isSelectedForAdd || addedToLists.has(vm.list.ID)\"\n [class.selected-remove]=\"vm.isSelectedForRemove || removedFromLists.has(vm.list.ID)\"\n [class.is-member]=\"vm.isFullMember || vm.isPartialMember\">\n\n <!-- Checkbox / Selection Area -->\n <div class=\"list-item-select\">\n @if (showAddButton(vm)) {\n <button\n class=\"select-btn add-btn\"\n [class.selected]=\"vm.isSelectedForAdd || addedToLists.has(vm.list.ID)\"\n (click)=\"toggleListForAdd(vm)\"\n [title]=\"(vm.isSelectedForAdd || addedToLists.has(vm.list.ID)) ? 'Remove from selection' : 'Add to this list'\">\n @if (vm.isSelectedForAdd || addedToLists.has(vm.list.ID)) {\n <span class=\"fa-solid fa-check\"></span>\n } @else {\n <span class=\"fa-solid fa-plus\"></span>\n }\n </button>\n }\n @if (showRemoveButton(vm) && (vm.isFullMember || vm.isPartialMember)) {\n <button\n class=\"select-btn remove-btn\"\n [class.selected]=\"vm.isSelectedForRemove || removedFromLists.has(vm.list.ID)\"\n (click)=\"toggleListForRemove(vm)\"\n [title]=\"(vm.isSelectedForRemove || removedFromLists.has(vm.list.ID)) ? 'Cancel removal' : 'Remove from this list'\">\n @if (vm.isSelectedForRemove || removedFromLists.has(vm.list.ID)) {\n <span class=\"fa-solid fa-undo\"></span>\n } @else {\n <span class=\"fa-solid fa-minus\"></span>\n }\n </button>\n }\n </div>\n\n <!-- List Info -->\n <div class=\"list-item-content\">\n <div class=\"list-item-header\">\n <span class=\"fa-solid fa-folder list-icon\"></span>\n <span class=\"list-name\">{{ vm.list.Name }}</span>\n @if (newlyCreatedLists.includes(vm.list)) {\n <span class=\"badge badge-new\">New</span>\n }\n </div>\n <div class=\"list-item-meta\">\n @if (vm.list.Description) {\n <span class=\"list-description\">{{ vm.list.Description }}</span>\n <span class=\"meta-separator\">\u2022</span>\n }\n <span class=\"list-count\">{{ vm.itemCount }} item{{ vm.itemCount !== 1 ? 's' : '' }}</span>\n <span class=\"meta-separator\">\u2022</span>\n <span class=\"list-updated\">{{ formatDate(vm.lastUpdated) }}</span>\n </div>\n </div>\n\n <!-- Membership Indicator -->\n @if (config.showMembership !== false) {\n <div class=\"membership-indicator\" [class]=\"getMembershipClass(vm)\">\n <span [class]=\"getMembershipIcon(vm)\"></span>\n <span class=\"membership-text\">{{ getMembershipText(vm) }}</span>\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Footer -->\n <div class=\"dialog-footer\">\n <div class=\"footer-summary\">\n @if (hasChanges) {\n @if (addCount > 0) {\n <span class=\"summary-item add\">\n <span class=\"fa-solid fa-plus-circle\"></span>\n {{ addCount }} list{{ addCount !== 1 ? 's' : '' }}\n </span>\n }\n @if (removeCount > 0) {\n <span class=\"summary-item remove\">\n <span class=\"fa-solid fa-minus-circle\"></span>\n {{ removeCount }} list{{ removeCount !== 1 ? 's' : '' }}\n </span>\n }\n } @else {\n <span class=\"summary-empty\">No changes</span>\n }\n </div>\n <div class=\"footer-actions\">\n <button class=\"btn btn-secondary\" (click)=\"onCancel()\" [disabled]=\"saving\">\n Cancel\n </button>\n <button\n class=\"btn btn-primary\"\n (click)=\"applyChanges()\"\n [disabled]=\"!hasChanges || saving\">\n @if (saving) {\n <span class=\"fa-solid fa-spinner fa-spin\"></span>\n }\n Apply Changes\n </button>\n </div>\n </div>\n </div>\n </div>\n}\n", styles: ["/* ============================================\n List Management Dialog - Gorgeous Responsive Design\n ============================================ */\n\n/* Overlay */\n.dialog-overlay {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10000;\n animation: fadeIn 0.2s ease-out;\n backdrop-filter: blur(2px);\n}\n\n@keyframes fadeIn {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n/* Dialog Container */\n.dialog-container {\n background: #ffffff;\n border-radius: 16px;\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);\n width: 90vw;\n max-width: 600px;\n max-height: 85vh;\n display: flex;\n flex-direction: column;\n animation: slideUp 0.3s ease-out;\n overflow: hidden;\n}\n\n@keyframes slideUp {\n from {\n opacity: 0;\n transform: translateY(20px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n/* Header */\n.dialog-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 20px 24px;\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n}\n\n.header-content {\n display: flex;\n align-items: center;\n gap: 16px;\n}\n\n.header-icon {\n width: 48px;\n height: 48px;\n background: rgba(255, 255, 255, 0.2);\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 22px;\n}\n\n.header-text {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.dialog-title {\n margin: 0;\n font-size: 18px;\n font-weight: 600;\n letter-spacing: -0.01em;\n}\n\n.dialog-subtitle {\n margin: 0;\n font-size: 13px;\n opacity: 0.85;\n}\n\n.close-button {\n width: 36px;\n height: 36px;\n border: none;\n background: rgba(255, 255, 255, 0.15);\n border-radius: 8px;\n color: white;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 16px;\n transition: background 0.2s;\n}\n\n.close-button:hover {\n background: rgba(255, 255, 255, 0.25);\n}\n\n/* Search Section */\n.search-section {\n display: flex;\n gap: 12px;\n padding: 16px 20px;\n background: #f8fafc;\n border-bottom: 1px solid #e2e8f0;\n}\n\n.search-bar {\n flex: 1;\n position: relative;\n display: flex;\n align-items: center;\n}\n\n.search-icon {\n position: absolute;\n left: 14px;\n color: #94a3b8;\n font-size: 14px;\n pointer-events: none;\n}\n\n.search-input {\n width: 100%;\n padding: 12px 40px 12px 42px;\n border: 1px solid #e2e8f0;\n border-radius: 10px;\n font-size: 14px;\n background: white;\n transition: all 0.2s;\n}\n\n.search-input:focus {\n outline: none;\n border-color: #667eea;\n box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.15);\n}\n\n.search-input::placeholder {\n color: #94a3b8;\n}\n\n.clear-search {\n position: absolute;\n right: 12px;\n border: none;\n background: none;\n color: #94a3b8;\n cursor: pointer;\n padding: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.clear-search:hover {\n color: #64748b;\n}\n\n.create-button {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 18px;\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n border: none;\n border-radius: 10px;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s;\n white-space: nowrap;\n}\n\n.create-button:hover:not(:disabled) {\n transform: translateY(-1px);\n box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);\n}\n\n.create-button:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n/* Filter Tabs */\n.filter-tabs {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 20px;\n border-bottom: 1px solid #e2e8f0;\n background: white;\n}\n\n.tabs-left {\n display: flex;\n gap: 4px;\n}\n\n.tab-button {\n padding: 8px 16px;\n border: none;\n background: none;\n color: #64748b;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n border-radius: 6px;\n transition: all 0.2s;\n}\n\n.tab-button:hover {\n background: #f1f5f9;\n color: #334155;\n}\n\n.tab-button.active {\n background: #ede9fe;\n color: #7c3aed;\n}\n\n.sort-select {\n padding: 8px 12px;\n border: 1px solid #e2e8f0;\n border-radius: 6px;\n font-size: 13px;\n color: #64748b;\n background: white;\n cursor: pointer;\n}\n\n.sort-select:focus {\n outline: none;\n border-color: #667eea;\n}\n\n/* Create Form */\n.create-form {\n background: #fefce8;\n border-bottom: 1px solid #fde047;\n animation: slideDown 0.2s ease-out;\n}\n\n@keyframes slideDown {\n from {\n opacity: 0;\n max-height: 0;\n }\n to {\n opacity: 1;\n max-height: 300px;\n }\n}\n\n.create-form-header {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 12px 20px;\n font-weight: 600;\n color: #854d0e;\n font-size: 14px;\n border-bottom: 1px solid #fde047;\n}\n\n.create-form-body {\n padding: 16px 20px;\n}\n\n.form-group {\n margin-bottom: 12px;\n}\n\n.form-group:last-of-type {\n margin-bottom: 16px;\n}\n\n.form-input {\n width: 100%;\n padding: 12px 14px;\n border: 1px solid #e2e8f0;\n border-radius: 8px;\n font-size: 14px;\n background: white;\n transition: all 0.2s;\n box-sizing: border-box;\n}\n\n.form-input:focus {\n outline: none;\n border-color: #667eea;\n box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.15);\n}\n\n.form-textarea {\n resize: vertical;\n min-height: 60px;\n}\n\n.create-form-actions {\n display: flex;\n gap: 10px;\n justify-content: flex-end;\n}\n\n/* List Content */\n.list-content {\n flex: 1;\n overflow-y: auto;\n min-height: 200px;\n max-height: 400px;\n}\n\n/* Loading State */\n.loading-state {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 60px 20px;\n}\n\n/* Empty State */\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 20px;\n text-align: center;\n}\n\n.empty-icon {\n font-size: 48px;\n color: #cbd5e1;\n margin-bottom: 16px;\n}\n\n.empty-title {\n font-size: 16px;\n font-weight: 600;\n color: #334155;\n margin: 0 0 6px 0;\n}\n\n.empty-subtitle {\n font-size: 14px;\n color: #64748b;\n margin: 0 0 20px 0;\n}\n\n/* List Items */\n.list-items {\n padding: 8px 12px;\n}\n\n.list-item {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 14px 16px;\n margin-bottom: 8px;\n background: white;\n border: 1px solid #e2e8f0;\n border-radius: 12px;\n transition: all 0.2s;\n}\n\n.list-item:last-child {\n margin-bottom: 0;\n}\n\n.list-item:hover {\n border-color: #cbd5e1;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);\n}\n\n.list-item.selected-add {\n background: #ecfdf5;\n border-color: #10b981;\n}\n\n.list-item.selected-remove {\n background: #fef2f2;\n border-color: #ef4444;\n}\n\n.list-item.is-member {\n border-left: 3px solid #667eea;\n}\n\n/* Selection Buttons */\n.list-item-select {\n display: flex;\n gap: 6px;\n}\n\n.select-btn {\n width: 32px;\n height: 32px;\n border: 1px solid #e2e8f0;\n border-radius: 8px;\n background: white;\n color: #64748b;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n transition: all 0.2s;\n}\n\n.select-btn.add-btn:hover {\n border-color: #10b981;\n color: #10b981;\n background: #ecfdf5;\n}\n\n.select-btn.add-btn.selected {\n background: #10b981;\n border-color: #10b981;\n color: white;\n}\n\n.select-btn.remove-btn:hover {\n border-color: #ef4444;\n color: #ef4444;\n background: #fef2f2;\n}\n\n.select-btn.remove-btn.selected {\n background: #ef4444;\n border-color: #ef4444;\n color: white;\n}\n\n/* List Item Content */\n.list-item-content {\n flex: 1;\n min-width: 0;\n}\n\n.list-item-header {\n display: flex;\n align-items: center;\n gap: 10px;\n margin-bottom: 4px;\n}\n\n.list-icon {\n color: #667eea;\n font-size: 14px;\n}\n\n.list-name {\n font-weight: 600;\n font-size: 14px;\n color: #1e293b;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.badge {\n padding: 2px 8px;\n border-radius: 10px;\n font-size: 10px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.02em;\n}\n\n.badge-new {\n background: #dbeafe;\n color: #2563eb;\n}\n\n.list-item-meta {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 4px;\n font-size: 12px;\n color: #64748b;\n}\n\n.list-description {\n max-width: 180px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.meta-separator {\n color: #cbd5e1;\n}\n\n/* Membership Indicator */\n.membership-indicator {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n border-radius: 20px;\n font-size: 12px;\n font-weight: 500;\n white-space: nowrap;\n}\n\n.membership-indicator.full-member {\n background: #dcfce7;\n color: #16a34a;\n}\n\n.membership-indicator.partial-member {\n background: #fef3c7;\n color: #d97706;\n}\n\n.membership-indicator.not-member {\n background: #f1f5f9;\n color: #64748b;\n}\n\n.membership-text {\n font-variant-numeric: tabular-nums;\n}\n\n/* Footer */\n.dialog-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 20px;\n background: #f8fafc;\n border-top: 1px solid #e2e8f0;\n}\n\n.footer-summary {\n display: flex;\n align-items: center;\n gap: 16px;\n}\n\n.summary-item {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 13px;\n font-weight: 500;\n}\n\n.summary-item.add {\n color: #16a34a;\n}\n\n.summary-item.remove {\n color: #dc2626;\n}\n\n.summary-empty {\n color: #94a3b8;\n font-size: 13px;\n}\n\n.footer-actions {\n display: flex;\n gap: 10px;\n}\n\n/* Buttons */\n.btn {\n padding: 10px 20px;\n border-radius: 8px;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 8px;\n transition: all 0.2s;\n border: none;\n}\n\n.btn-primary {\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n}\n\n.btn-primary:hover:not(:disabled) {\n box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);\n transform: translateY(-1px);\n}\n\n.btn-primary:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n transform: none;\n}\n\n.btn-secondary {\n background: white;\n color: #64748b;\n border: 1px solid #e2e8f0;\n}\n\n.btn-secondary:hover:not(:disabled) {\n background: #f8fafc;\n border-color: #cbd5e1;\n}\n\n.btn-secondary:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n/* ============================================\n Mobile Responsive - Bottom Sheet Pattern\n ============================================ */\n\n@media (max-width: 640px) {\n .dialog-overlay {\n align-items: flex-end;\n }\n\n .dialog-container {\n width: 100%;\n max-width: 100%;\n max-height: 90vh;\n border-radius: 24px 24px 0 0;\n animation: slideUpMobile 0.3s ease-out;\n }\n\n @keyframes slideUpMobile {\n from {\n transform: translateY(100%);\n }\n to {\n transform: translateY(0);\n }\n }\n\n .dialog-header {\n padding: 16px 20px;\n border-radius: 24px 24px 0 0;\n }\n\n .header-icon {\n width: 40px;\n height: 40px;\n font-size: 18px;\n }\n\n .dialog-title {\n font-size: 16px;\n }\n\n .dialog-subtitle {\n font-size: 12px;\n }\n\n .search-section {\n padding: 12px 16px;\n flex-wrap: wrap;\n }\n\n .search-bar {\n width: 100%;\n order: 1;\n }\n\n .create-button {\n order: 2;\n width: 100%;\n justify-content: center;\n margin-top: 8px;\n }\n\n .button-text {\n display: inline;\n }\n\n .filter-tabs {\n padding: 10px 16px;\n flex-wrap: wrap;\n gap: 8px;\n }\n\n .tabs-left {\n width: 100%;\n justify-content: space-between;\n }\n\n .tab-button {\n flex: 1;\n text-align: center;\n padding: 10px 8px;\n }\n\n .tabs-right {\n width: 100%;\n }\n\n .sort-select {\n width: 100%;\n }\n\n .list-content {\n max-height: 50vh;\n }\n\n .list-items {\n padding: 8px;\n }\n\n .list-item {\n padding: 12px;\n gap: 10px;\n }\n\n .list-item-content {\n flex: 1;\n min-width: 0;\n }\n\n .list-description {\n display: none;\n }\n\n .membership-indicator {\n padding: 4px 8px;\n font-size: 11px;\n }\n\n .dialog-footer {\n padding: 12px 16px;\n flex-direction: column;\n gap: 12px;\n }\n\n .footer-summary {\n width: 100%;\n justify-content: center;\n }\n\n .footer-actions {\n width: 100%;\n }\n\n .footer-actions .btn {\n flex: 1;\n justify-content: center;\n }\n\n .create-form-body {\n padding: 12px 16px;\n }\n\n .create-form-actions {\n flex-direction: column;\n }\n\n .create-form-actions .btn {\n width: 100%;\n justify-content: center;\n }\n}\n\n/* Tablet adjustments */\n@media (min-width: 641px) and (max-width: 1024px) {\n .dialog-container {\n max-width: 550px;\n }\n\n .list-description {\n max-width: 140px;\n }\n}\n\n/* Large screen enhancements */\n@media (min-width: 1025px) {\n .list-content {\n max-height: 450px;\n }\n\n .list-item:hover {\n transform: translateX(4px);\n }\n}\n\n/* Accessibility - Focus states */\n.search-input:focus-visible,\n.tab-button:focus-visible,\n.select-btn:focus-visible,\n.btn:focus-visible {\n outline: 2px solid #667eea;\n outline-offset: 2px;\n}\n\n/* Reduced motion preference */\n@media (prefers-reduced-motion: reduce) {\n .dialog-overlay,\n .dialog-container,\n .create-form,\n .list-item,\n .btn {\n animation: none;\n transition: none;\n }\n}\n"] }]
|
|
933
|
+
}], () => [{ type: i1.ListManagementService }, { type: i0.ChangeDetectorRef }], { config: [{
|
|
934
|
+
type: Input
|
|
935
|
+
}], visible: [{
|
|
936
|
+
type: Input
|
|
937
|
+
}], complete: [{
|
|
938
|
+
type: Output
|
|
939
|
+
}], cancel: [{
|
|
940
|
+
type: Output
|
|
941
|
+
}] }); })();
|
|
942
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ListManagementDialogComponent, { className: "ListManagementDialogComponent" }); })();
|
|
943
|
+
//# sourceMappingURL=list-management-dialog.component.js.map
|