@mj-biz-apps/common-ng 5.60.0 → 5.61.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 (77) hide show
  1. package/dist/lib/components/contact-method-list/contact-method-list.component.d.ts +112 -8
  2. package/dist/lib/components/contact-method-list/contact-method-list.component.d.ts.map +1 -1
  3. package/dist/lib/components/contact-method-list/contact-method-list.component.js +662 -150
  4. package/dist/lib/components/contact-method-list/contact-method-list.component.js.map +1 -1
  5. package/dist/lib/components/identity-header/person-identity.component.d.ts.map +1 -1
  6. package/dist/lib/components/identity-header/person-identity.component.js +3 -2
  7. package/dist/lib/components/identity-header/person-identity.component.js.map +1 -1
  8. package/dist/lib/components/org-hierarchy-tree/org-hierarchy-tree.component.d.ts.map +1 -1
  9. package/dist/lib/components/org-hierarchy-tree/org-hierarchy-tree.component.js +5 -4
  10. package/dist/lib/components/org-hierarchy-tree/org-hierarchy-tree.component.js.map +1 -1
  11. package/dist/lib/components/person-job-functions/person-job-functions.component.d.ts.map +1 -1
  12. package/dist/lib/components/person-job-functions/person-job-functions.component.js +3 -2
  13. package/dist/lib/components/person-job-functions/person-job-functions.component.js.map +1 -1
  14. package/dist/lib/custom/panels/activity-files.panel.d.ts.map +1 -1
  15. package/dist/lib/custom/panels/activity-files.panel.js +5 -2
  16. package/dist/lib/custom/panels/activity-files.panel.js.map +1 -1
  17. package/dist/lib/custom/panels/activity-hierarchy.panel.d.ts.map +1 -1
  18. package/dist/lib/custom/panels/activity-hierarchy.panel.js +5 -2
  19. package/dist/lib/custom/panels/activity-hierarchy.panel.js.map +1 -1
  20. package/dist/lib/custom/panels/activity-links.panel.d.ts.map +1 -1
  21. package/dist/lib/custom/panels/activity-links.panel.js +4 -2
  22. package/dist/lib/custom/panels/activity-links.panel.js.map +1 -1
  23. package/dist/lib/custom/panels/activity-type-hierarchy.panel.d.ts.map +1 -1
  24. package/dist/lib/custom/panels/activity-type-hierarchy.panel.js +5 -2
  25. package/dist/lib/custom/panels/activity-type-hierarchy.panel.js.map +1 -1
  26. package/dist/lib/custom/panels/organization-addresses.panel.d.ts.map +1 -1
  27. package/dist/lib/custom/panels/organization-addresses.panel.js +2 -1
  28. package/dist/lib/custom/panels/organization-addresses.panel.js.map +1 -1
  29. package/dist/lib/custom/panels/organization-contact-methods.panel.d.ts.map +1 -1
  30. package/dist/lib/custom/panels/organization-contact-methods.panel.js +2 -1
  31. package/dist/lib/custom/panels/organization-contact-methods.panel.js.map +1 -1
  32. package/dist/lib/custom/panels/organization-hierarchy.panel.d.ts.map +1 -1
  33. package/dist/lib/custom/panels/organization-hierarchy.panel.js +4 -1
  34. package/dist/lib/custom/panels/organization-hierarchy.panel.js.map +1 -1
  35. package/dist/lib/custom/panels/organization-relationships.panel.d.ts.map +1 -1
  36. package/dist/lib/custom/panels/organization-relationships.panel.js +2 -1
  37. package/dist/lib/custom/panels/organization-relationships.panel.js.map +1 -1
  38. package/dist/lib/custom/panels/person-addresses.panel.d.ts.map +1 -1
  39. package/dist/lib/custom/panels/person-addresses.panel.js +2 -1
  40. package/dist/lib/custom/panels/person-addresses.panel.js.map +1 -1
  41. package/dist/lib/custom/panels/person-contact-methods.panel.d.ts.map +1 -1
  42. package/dist/lib/custom/panels/person-contact-methods.panel.js +2 -1
  43. package/dist/lib/custom/panels/person-contact-methods.panel.js.map +1 -1
  44. package/dist/lib/custom/panels/person-job-functions.panel.d.ts.map +1 -1
  45. package/dist/lib/custom/panels/person-job-functions.panel.js +3 -1
  46. package/dist/lib/custom/panels/person-job-functions.panel.js.map +1 -1
  47. package/dist/lib/custom/panels/person-relationships.panel.d.ts.map +1 -1
  48. package/dist/lib/custom/panels/person-relationships.panel.js +2 -1
  49. package/dist/lib/custom/panels/person-relationships.panel.js.map +1 -1
  50. package/dist/lib/data/organization-staff.d.ts.map +1 -1
  51. package/dist/lib/data/organization-staff.js +2 -1
  52. package/dist/lib/data/organization-staff.js.map +1 -1
  53. package/dist/lib/generated/Entities/mjBizAppsCommonConsentPurpose/mjbizappscommonconsentpurpose.form.component.d.ts +10 -0
  54. package/dist/lib/generated/Entities/mjBizAppsCommonConsentPurpose/mjbizappscommonconsentpurpose.form.component.d.ts.map +1 -0
  55. package/dist/lib/generated/Entities/mjBizAppsCommonConsentPurpose/mjbizappscommonconsentpurpose.form.component.js +88 -0
  56. package/dist/lib/generated/Entities/mjBizAppsCommonConsentPurpose/mjbizappscommonconsentpurpose.form.component.js.map +1 -0
  57. package/dist/lib/generated/Entities/mjBizAppsCommonContactMethod/mjbizappscommoncontactmethod.form.component.d.ts.map +1 -1
  58. package/dist/lib/generated/Entities/mjBizAppsCommonContactMethod/mjbizappscommoncontactmethod.form.component.js +25 -6
  59. package/dist/lib/generated/Entities/mjBizAppsCommonContactMethod/mjbizappscommoncontactmethod.form.component.js.map +1 -1
  60. package/dist/lib/generated/Entities/mjBizAppsCommonContactMethodConsent/mjbizappscommoncontactmethodconsent.form.component.d.ts +10 -0
  61. package/dist/lib/generated/Entities/mjBizAppsCommonContactMethodConsent/mjbizappscommoncontactmethodconsent.form.component.d.ts.map +1 -0
  62. package/dist/lib/generated/Entities/mjBizAppsCommonContactMethodConsent/mjbizappscommoncontactmethodconsent.form.component.js +94 -0
  63. package/dist/lib/generated/Entities/mjBizAppsCommonContactMethodConsent/mjbizappscommoncontactmethodconsent.form.component.js.map +1 -0
  64. package/dist/lib/generated/Entities/mjBizAppsCommonContactMethodConsentHistory/mjbizappscommoncontactmethodconsenthistory.form.component.d.ts +10 -0
  65. package/dist/lib/generated/Entities/mjBizAppsCommonContactMethodConsentHistory/mjbizappscommoncontactmethodconsenthistory.form.component.d.ts.map +1 -0
  66. package/dist/lib/generated/Entities/mjBizAppsCommonContactMethodConsentHistory/mjbizappscommoncontactmethodconsenthistory.form.component.js +79 -0
  67. package/dist/lib/generated/Entities/mjBizAppsCommonContactMethodConsentHistory/mjbizappscommoncontactmethodconsenthistory.form.component.js.map +1 -0
  68. package/dist/lib/generated/Entities/mjBizAppsCommonContactType/mjbizappscommoncontacttype.form.component.js +17 -15
  69. package/dist/lib/generated/Entities/mjBizAppsCommonContactType/mjbizappscommoncontacttype.form.component.js.map +1 -1
  70. package/dist/lib/generated/Entities/mjBizAppsCommonOrganization/mjbizappscommonorganization.form.component.d.ts.map +1 -1
  71. package/dist/lib/generated/Entities/mjBizAppsCommonOrganization/mjbizappscommonorganization.form.component.js +26 -8
  72. package/dist/lib/generated/Entities/mjBizAppsCommonOrganization/mjbizappscommonorganization.form.component.js.map +1 -1
  73. package/dist/lib/generated/generated-forms.module.d.ts +38 -25
  74. package/dist/lib/generated/generated-forms.module.d.ts.map +1 -1
  75. package/dist/lib/generated/generated-forms.module.js +70 -1
  76. package/dist/lib/generated/generated-forms.module.js.map +1 -1
  77. package/package.json +2 -2
@@ -1,10 +1,14 @@
1
1
  import { Component, Input, Output, EventEmitter, inject, ChangeDetectorRef } from '@angular/core';
2
2
  import { CommonModule } from '@angular/common';
3
3
  import { FormsModule } from '@angular/forms';
4
- import { Metadata, RunView } from '@memberjunction/core';
4
+ import { LogError, Metadata, RunView } from '@memberjunction/core';
5
+ import { EscapeSQLString, UUIDsEqual } from '@memberjunction/global';
6
+ import { SharedGenericModule } from '@memberjunction/ng-shared-generic';
7
+ import { ContactMethodConsentEntity } from '@mj-biz-apps/common-entities';
5
8
  import * as i0 from "@angular/core";
6
9
  import * as i1 from "@angular/common";
7
10
  import * as i2 from "@angular/forms";
11
+ import * as i3 from "@memberjunction/ng-shared-generic";
8
12
  const _forTrack0 = ($index, $item) => $item.ID;
9
13
  function ContactMethodListComponent_Conditional_4_Template(rf, ctx) { if (rf & 1) {
10
14
  i0.ɵɵelementStart(0, "span", 3);
@@ -40,6 +44,65 @@ function ContactMethodListComponent_Conditional_6_For_3_Conditional_0_For_7_Temp
40
44
  function ContactMethodListComponent_Conditional_6_For_3_Conditional_0_Conditional_22_Template(rf, ctx) { if (rf & 1) {
41
45
  i0.ɵɵelement(0, "i", 25);
42
46
  } }
47
+ function ContactMethodListComponent_Conditional_6_For_3_Conditional_0_Conditional_26_For_6_Template(rf, ctx) { if (rf & 1) {
48
+ i0.ɵɵelementStart(0, "option", 15);
49
+ i0.ɵɵtext(1);
50
+ i0.ɵɵelementEnd();
51
+ } if (rf & 2) {
52
+ const s_r5 = ctx.$implicit;
53
+ i0.ɵɵproperty("value", s_r5);
54
+ i0.ɵɵadvance();
55
+ i0.ɵɵtextInterpolate(s_r5);
56
+ } }
57
+ function ContactMethodListComponent_Conditional_6_For_3_Conditional_0_Conditional_26_For_8_For_5_Template(rf, ctx) { if (rf & 1) {
58
+ i0.ɵɵelementStart(0, "option", 15);
59
+ i0.ɵɵtext(1);
60
+ i0.ɵɵelementEnd();
61
+ } if (rf & 2) {
62
+ const s_r8 = ctx.$implicit;
63
+ i0.ɵɵproperty("value", s_r8);
64
+ i0.ɵɵadvance();
65
+ i0.ɵɵtextInterpolate(s_r8);
66
+ } }
67
+ function ContactMethodListComponent_Conditional_6_For_3_Conditional_0_Conditional_26_For_8_Template(rf, ctx) { if (rf & 1) {
68
+ const _r6 = i0.ɵɵgetCurrentView();
69
+ i0.ɵɵelementStart(0, "div", 28)(1, "label");
70
+ i0.ɵɵtext(2);
71
+ i0.ɵɵelementEnd();
72
+ i0.ɵɵelementStart(3, "select", 14);
73
+ i0.ɵɵtwoWayListener("ngModelChange", function ContactMethodListComponent_Conditional_6_For_3_Conditional_0_Conditional_26_For_8_Template_select_ngModelChange_3_listener($event) { const p_r7 = i0.ɵɵrestoreView(_r6).$implicit; const ctx_r0 = i0.ɵɵnextContext(5); i0.ɵɵtwoWayBindingSet(ctx_r0.EditForm.Consents[p_r7.ID], $event) || (ctx_r0.EditForm.Consents[p_r7.ID] = $event); return i0.ɵɵresetView($event); });
74
+ i0.ɵɵrepeaterCreate(4, ContactMethodListComponent_Conditional_6_For_3_Conditional_0_Conditional_26_For_8_For_5_Template, 2, 2, "option", 15, i0.ɵɵrepeaterTrackByIdentity);
75
+ i0.ɵɵelementEnd()();
76
+ } if (rf & 2) {
77
+ const p_r7 = ctx.$implicit;
78
+ const ctx_r0 = i0.ɵɵnextContext(5);
79
+ i0.ɵɵadvance(2);
80
+ i0.ɵɵtextInterpolate(p_r7.Name);
81
+ i0.ɵɵadvance();
82
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r0.EditForm.Consents[p_r7.ID]);
83
+ i0.ɵɵadvance();
84
+ i0.ɵɵrepeater(ctx_r0.ConsentStatuses);
85
+ } }
86
+ function ContactMethodListComponent_Conditional_6_For_3_Conditional_0_Conditional_26_Template(rf, ctx) { if (rf & 1) {
87
+ const _r4 = i0.ɵɵgetCurrentView();
88
+ i0.ɵɵelementStart(0, "div", 27)(1, "div", 28)(2, "label");
89
+ i0.ɵɵtext(3, "General");
90
+ i0.ɵɵelementEnd();
91
+ i0.ɵɵelementStart(4, "select", 14);
92
+ i0.ɵɵtwoWayListener("ngModelChange", function ContactMethodListComponent_Conditional_6_For_3_Conditional_0_Conditional_26_Template_select_ngModelChange_4_listener($event) { i0.ɵɵrestoreView(_r4); const ctx_r0 = i0.ɵɵnextContext(4); i0.ɵɵtwoWayBindingSet(ctx_r0.EditForm.Consents[ctx_r0.GeneralKey], $event) || (ctx_r0.EditForm.Consents[ctx_r0.GeneralKey] = $event); return i0.ɵɵresetView($event); });
93
+ i0.ɵɵrepeaterCreate(5, ContactMethodListComponent_Conditional_6_For_3_Conditional_0_Conditional_26_For_6_Template, 2, 2, "option", 15, i0.ɵɵrepeaterTrackByIdentity);
94
+ i0.ɵɵelementEnd()();
95
+ i0.ɵɵrepeaterCreate(7, ContactMethodListComponent_Conditional_6_For_3_Conditional_0_Conditional_26_For_8_Template, 6, 2, "div", 28, _forTrack0);
96
+ i0.ɵɵelementEnd();
97
+ } if (rf & 2) {
98
+ const ctx_r0 = i0.ɵɵnextContext(4);
99
+ i0.ɵɵadvance(4);
100
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r0.EditForm.Consents[ctx_r0.GeneralKey]);
101
+ i0.ɵɵadvance();
102
+ i0.ɵɵrepeater(ctx_r0.ConsentStatuses);
103
+ i0.ɵɵadvance(2);
104
+ i0.ɵɵrepeater(ctx_r0.ConsentPurposes);
105
+ } }
43
106
  function ContactMethodListComponent_Conditional_6_For_3_Conditional_0_Template(rf, ctx) { if (rf & 1) {
44
107
  const _r2 = i0.ɵɵgetCurrentView();
45
108
  i0.ɵɵelementStart(0, "div", 10)(1, "div", 12)(2, "div", 13)(3, "label");
@@ -75,9 +138,11 @@ function ContactMethodListComponent_Conditional_6_For_3_Conditional_0_Template(r
75
138
  i0.ɵɵelementStart(24, "button", 26);
76
139
  i0.ɵɵlistener("click", function ContactMethodListComponent_Conditional_6_For_3_Conditional_0_Template_button_click_24_listener() { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.onCancelEdit()); });
77
140
  i0.ɵɵtext(25, "Cancel");
78
- i0.ɵɵelementEnd()()()();
141
+ i0.ɵɵelementEnd()()();
142
+ i0.ɵɵconditionalCreate(26, ContactMethodListComponent_Conditional_6_For_3_Conditional_0_Conditional_26_Template, 9, 1, "div", 27);
143
+ i0.ɵɵelementEnd();
79
144
  } if (rf & 2) {
80
- const cm_r4 = i0.ɵɵnextContext().$implicit;
145
+ const cm_r9 = i0.ɵɵnextContext().$implicit;
81
146
  const ctx_r0 = i0.ɵɵnextContext(2);
82
147
  i0.ɵɵadvance(5);
83
148
  i0.ɵɵtwoWayProperty("ngModel", ctx_r0.EditForm.TypeID);
@@ -89,149 +154,332 @@ function ContactMethodListComponent_Conditional_6_For_3_Conditional_0_Template(r
89
154
  i0.ɵɵadvance(4);
90
155
  i0.ɵɵtwoWayProperty("ngModel", ctx_r0.EditForm.Label);
91
156
  i0.ɵɵadvance(2);
92
- i0.ɵɵproperty("id", "primary-edit-" + cm_r4.ID);
157
+ i0.ɵɵproperty("id", "primary-edit-" + cm_r9.ID);
93
158
  i0.ɵɵtwoWayProperty("ngModel", ctx_r0.EditForm.IsPrimary);
94
159
  i0.ɵɵadvance();
95
- i0.ɵɵproperty("for", "primary-edit-" + cm_r4.ID);
160
+ i0.ɵɵproperty("for", "primary-edit-" + cm_r9.ID);
96
161
  i0.ɵɵadvance(3);
97
162
  i0.ɵɵproperty("disabled", ctx_r0.Saving);
98
163
  i0.ɵɵadvance();
99
164
  i0.ɵɵconditional(ctx_r0.Saving ? 22 : -1);
165
+ i0.ɵɵadvance(4);
166
+ i0.ɵɵconditional(ctx_r0.isConsentType(ctx_r0.EditForm.TypeID) ? 26 : -1);
100
167
  } }
101
168
  function ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_9_Template(rf, ctx) { if (rf & 1) {
102
- i0.ɵɵelementStart(0, "span", 33);
103
- i0.ɵɵelement(1, "i", 38);
169
+ i0.ɵɵelementStart(0, "span", 35);
170
+ i0.ɵɵelement(1, "i", 40);
104
171
  i0.ɵɵelementEnd();
105
172
  } }
106
- function ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_11_Template(rf, ctx) { if (rf & 1) {
107
- const _r6 = i0.ɵɵgetCurrentView();
108
- i0.ɵɵelementStart(0, "button", 39);
109
- i0.ɵɵlistener("click", function ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_11_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r6); const cm_r4 = i0.ɵɵnextContext(2).$implicit; const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.onSetPrimary(cm_r4)); });
110
- i0.ɵɵelement(1, "i", 40);
173
+ function ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_10_For_2_Template(rf, ctx) { if (rf & 1) {
174
+ i0.ɵɵelementStart(0, "span", 42);
175
+ i0.ɵɵelement(1, "i");
176
+ i0.ɵɵelementStart(2, "span", 45);
177
+ i0.ɵɵtext(3);
178
+ i0.ɵɵelementEnd();
179
+ i0.ɵɵtext(4);
180
+ i0.ɵɵelementEnd();
181
+ } if (rf & 2) {
182
+ const c_r12 = ctx.$implicit;
183
+ const ctx_r0 = i0.ɵɵnextContext(5);
184
+ i0.ɵɵproperty("ngClass", ctx_r0.getConsentBadgeClass(c_r12.ConsentStatus));
185
+ i0.ɵɵadvance();
186
+ i0.ɵɵclassMap(ctx_r0.getConsentIcon(c_r12.ConsentStatus));
187
+ i0.ɵɵadvance(2);
188
+ i0.ɵɵtextInterpolate(ctx_r0.getConsentBadgeText(c_r12));
189
+ i0.ɵɵadvance();
190
+ i0.ɵɵtextInterpolate1(" ", c_r12.ConsentStatus, " ");
191
+ } }
192
+ function ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_10_ForEmpty_3_Template(rf, ctx) { if (rf & 1) {
193
+ i0.ɵɵelementStart(0, "span", 43);
194
+ i0.ɵɵelement(1, "i", 46);
195
+ i0.ɵɵtext(2, " Not Specified ");
111
196
  i0.ɵɵelementEnd();
112
197
  } }
198
+ function ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_10_Conditional_4_Conditional_3_Template(rf, ctx) { if (rf & 1) {
199
+ i0.ɵɵelement(0, "mj-loading", 49);
200
+ } }
201
+ function ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_10_Conditional_4_Conditional_4_For_1_Conditional_6_Template(rf, ctx) { if (rf & 1) {
202
+ i0.ɵɵtext(0);
203
+ } if (rf & 2) {
204
+ const h_r14 = i0.ɵɵnextContext().$implicit;
205
+ i0.ɵɵtextInterpolate1(" \u00B7 ", h_r14.RequestingOrganization);
206
+ } }
207
+ function ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_10_Conditional_4_Conditional_4_For_1_Conditional_11_Template(rf, ctx) { if (rf & 1) {
208
+ i0.ɵɵtext(0);
209
+ } if (rf & 2) {
210
+ const h_r14 = i0.ɵɵnextContext().$implicit;
211
+ i0.ɵɵtextInterpolate1(" \u00B7 ", h_r14.ConsentDetails);
212
+ } }
213
+ function ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_10_Conditional_4_Conditional_4_For_1_Template(rf, ctx) { if (rf & 1) {
214
+ i0.ɵɵelementStart(0, "div", 50)(1, "span");
215
+ i0.ɵɵtext(2);
216
+ i0.ɵɵpipe(3, "date");
217
+ i0.ɵɵelementEnd();
218
+ i0.ɵɵelementStart(4, "span", 53);
219
+ i0.ɵɵtext(5);
220
+ i0.ɵɵconditionalCreate(6, ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_10_Conditional_4_Conditional_4_For_1_Conditional_6_Template, 1, 1);
221
+ i0.ɵɵelementEnd();
222
+ i0.ɵɵelementStart(7, "span");
223
+ i0.ɵɵtext(8);
224
+ i0.ɵɵelementEnd();
225
+ i0.ɵɵelementStart(9, "span", 54);
226
+ i0.ɵɵtext(10);
227
+ i0.ɵɵconditionalCreate(11, ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_10_Conditional_4_Conditional_4_For_1_Conditional_11_Template, 1, 1);
228
+ i0.ɵɵelementEnd()();
229
+ } if (rf & 2) {
230
+ const h_r14 = ctx.$implicit;
231
+ i0.ɵɵadvance(2);
232
+ i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(3, 6, h_r14.ConsentStatusAt, "mediumDate"));
233
+ i0.ɵɵadvance(3);
234
+ i0.ɵɵtextInterpolate(h_r14.Purpose);
235
+ i0.ɵɵadvance();
236
+ i0.ɵɵconditional(h_r14.RequestingOrganization ? 6 : -1);
237
+ i0.ɵɵadvance(2);
238
+ i0.ɵɵtextInterpolate(h_r14.NewConsentStatus);
239
+ i0.ɵɵadvance(2);
240
+ i0.ɵɵtextInterpolate(h_r14.ConsentSource);
241
+ i0.ɵɵadvance();
242
+ i0.ɵɵconditional(h_r14.ConsentDetails ? 11 : -1);
243
+ } }
244
+ function ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_10_Conditional_4_Conditional_4_ForEmpty_2_Template(rf, ctx) { if (rf & 1) {
245
+ i0.ɵɵelementStart(0, "div", 51);
246
+ i0.ɵɵtext(1, "No consent recorded yet");
247
+ i0.ɵɵelementEnd();
248
+ } }
249
+ function ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_10_Conditional_4_Conditional_4_Template(rf, ctx) { if (rf & 1) {
250
+ i0.ɵɵrepeaterCreate(0, ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_10_Conditional_4_Conditional_4_For_1_Template, 12, 9, "div", 50, _forTrack0, false, ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_10_Conditional_4_Conditional_4_ForEmpty_2_Template, 2, 0, "div", 51);
251
+ i0.ɵɵelementStart(3, "div", 52);
252
+ i0.ɵɵtext(4, "Newest first; the top row for each purpose is its current status");
253
+ i0.ɵɵelementEnd();
254
+ } if (rf & 2) {
255
+ const ctx_r0 = i0.ɵɵnextContext(6);
256
+ i0.ɵɵrepeater(ctx_r0.ConsentHistory);
257
+ } }
258
+ function ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_10_Conditional_4_Template(rf, ctx) { if (rf & 1) {
259
+ const _r13 = i0.ɵɵgetCurrentView();
260
+ i0.ɵɵelementStart(0, "div", 47);
261
+ i0.ɵɵlistener("mouseenter", function ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_10_Conditional_4_Template_div_mouseenter_0_listener() { i0.ɵɵrestoreView(_r13); const cm_r9 = i0.ɵɵnextContext(3).$implicit; const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.onShowConsentHistory(cm_r9)); })("mouseleave", function ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_10_Conditional_4_Template_div_mouseleave_0_listener() { i0.ɵɵrestoreView(_r13); const ctx_r0 = i0.ɵɵnextContext(5); return i0.ɵɵresetView(ctx_r0.onHideConsentHistory()); });
262
+ i0.ɵɵelementStart(1, "div", 48);
263
+ i0.ɵɵtext(2);
264
+ i0.ɵɵelementEnd();
265
+ i0.ɵɵconditionalCreate(3, ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_10_Conditional_4_Conditional_3_Template, 1, 0, "mj-loading", 49)(4, ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_10_Conditional_4_Conditional_4_Template, 5, 1);
266
+ i0.ɵɵelementEnd();
267
+ } if (rf & 2) {
268
+ const cm_r9 = i0.ɵɵnextContext(3).$implicit;
269
+ const ctx_r0 = i0.ɵɵnextContext(2);
270
+ i0.ɵɵadvance(2);
271
+ i0.ɵɵtextInterpolate1("Consent history \u00B7 ", cm_r9.Value);
272
+ i0.ɵɵadvance();
273
+ i0.ɵɵconditional(ctx_r0.ConsentHistoryLoading ? 3 : 4);
274
+ } }
275
+ function ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_10_Template(rf, ctx) { if (rf & 1) {
276
+ const _r11 = i0.ɵɵgetCurrentView();
277
+ i0.ɵɵelementStart(0, "span", 41);
278
+ i0.ɵɵlistener("mouseenter", function ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_10_Template_span_mouseenter_0_listener() { i0.ɵɵrestoreView(_r11); const cm_r9 = i0.ɵɵnextContext(2).$implicit; const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.onShowConsentHistory(cm_r9)); })("mouseleave", function ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_10_Template_span_mouseleave_0_listener() { i0.ɵɵrestoreView(_r11); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.onHideConsentHistory()); });
279
+ i0.ɵɵrepeaterCreate(1, ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_10_For_2_Template, 5, 5, "span", 42, _forTrack0, false, ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_10_ForEmpty_3_Template, 3, 0, "span", 43);
280
+ i0.ɵɵelementEnd();
281
+ i0.ɵɵconditionalCreate(4, ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_10_Conditional_4_Template, 5, 2, "div", 44);
282
+ } if (rf & 2) {
283
+ const cm_r9 = i0.ɵɵnextContext(2).$implicit;
284
+ const ctx_r0 = i0.ɵɵnextContext(2);
285
+ i0.ɵɵadvance();
286
+ i0.ɵɵrepeater(ctx_r0.getConsents(cm_r9));
287
+ i0.ɵɵadvance(3);
288
+ i0.ɵɵconditional(ctx_r0.ConsentHistoryFor === cm_r9.ID ? 4 : -1);
289
+ } }
113
290
  function ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_12_Template(rf, ctx) { if (rf & 1) {
114
- const _r7 = i0.ɵɵgetCurrentView();
115
- i0.ɵɵelementStart(0, "button", 41);
116
- i0.ɵɵlistener("click", function ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_12_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r7); const cm_r4 = i0.ɵɵnextContext(2).$implicit; const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.onOpenLink(cm_r4.Value)); });
117
- i0.ɵɵelement(1, "i", 42);
291
+ const _r15 = i0.ɵɵgetCurrentView();
292
+ i0.ɵɵelementStart(0, "button", 55);
293
+ i0.ɵɵlistener("click", function ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_12_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r15); const cm_r9 = i0.ɵɵnextContext(2).$implicit; const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.onSetPrimary(cm_r9)); });
294
+ i0.ɵɵelement(1, "i", 56);
118
295
  i0.ɵɵelementEnd();
119
296
  } }
120
297
  function ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_13_Template(rf, ctx) { if (rf & 1) {
121
- const _r8 = i0.ɵɵgetCurrentView();
122
- i0.ɵɵelementStart(0, "button", 43);
123
- i0.ɵɵlistener("click", function ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_13_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r8); const cm_r4 = i0.ɵɵnextContext(2).$implicit; const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.onCopyValue(cm_r4.Value)); });
124
- i0.ɵɵelement(1, "i", 44);
298
+ const _r16 = i0.ɵɵgetCurrentView();
299
+ i0.ɵɵelementStart(0, "button", 57);
300
+ i0.ɵɵlistener("click", function ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_13_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r16); const cm_r9 = i0.ɵɵnextContext(2).$implicit; const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.onOpenLink(cm_r9.Value)); });
301
+ i0.ɵɵelement(1, "i", 58);
125
302
  i0.ɵɵelementEnd();
126
303
  } }
127
304
  function ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_14_Template(rf, ctx) { if (rf & 1) {
128
- const _r9 = i0.ɵɵgetCurrentView();
129
- i0.ɵɵelementStart(0, "button", 45);
130
- i0.ɵɵlistener("click", function ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_14_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r9); const cm_r4 = i0.ɵɵnextContext(2).$implicit; const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.onEdit(cm_r4)); });
131
- i0.ɵɵelement(1, "i", 46);
305
+ const _r17 = i0.ɵɵgetCurrentView();
306
+ i0.ɵɵelementStart(0, "button", 59);
307
+ i0.ɵɵlistener("click", function ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_14_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r17); const cm_r9 = i0.ɵɵnextContext(2).$implicit; const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.onCopyValue(cm_r9.Value)); });
308
+ i0.ɵɵelement(1, "i", 60);
309
+ i0.ɵɵelementEnd();
310
+ } }
311
+ function ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_15_Template(rf, ctx) { if (rf & 1) {
312
+ const _r18 = i0.ɵɵgetCurrentView();
313
+ i0.ɵɵelementStart(0, "button", 61);
314
+ i0.ɵɵlistener("click", function ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_15_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r18); const cm_r9 = i0.ɵɵnextContext(2).$implicit; const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.onEdit(cm_r9)); });
315
+ i0.ɵɵelement(1, "i", 62);
132
316
  i0.ɵɵelementEnd();
133
- i0.ɵɵelementStart(2, "button", 47);
134
- i0.ɵɵlistener("click", function ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_14_Template_button_click_2_listener() { i0.ɵɵrestoreView(_r9); const cm_r4 = i0.ɵɵnextContext(2).$implicit; const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.onDelete(cm_r4)); });
135
- i0.ɵɵelement(3, "i", 48);
317
+ i0.ɵɵelementStart(2, "button", 63);
318
+ i0.ɵɵlistener("click", function ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_15_Template_button_click_2_listener() { i0.ɵɵrestoreView(_r18); const cm_r9 = i0.ɵɵnextContext(2).$implicit; const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.onDelete(cm_r9)); });
319
+ i0.ɵɵelement(3, "i", 64);
136
320
  i0.ɵɵelementEnd();
137
321
  } }
138
322
  function ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Template(rf, ctx) { if (rf & 1) {
139
- const _r5 = i0.ɵɵgetCurrentView();
140
- i0.ɵɵelementStart(0, "div", 27)(1, "div", 28);
323
+ const _r10 = i0.ɵɵgetCurrentView();
324
+ i0.ɵɵelementStart(0, "div", 29)(1, "div", 30);
141
325
  i0.ɵɵelement(2, "i");
142
326
  i0.ɵɵelementEnd();
143
- i0.ɵɵelementStart(3, "div", 29)(4, "div", 30);
144
- i0.ɵɵlistener("click", function ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Template_div_click_4_listener() { i0.ɵɵrestoreView(_r5); const cm_r4 = i0.ɵɵnextContext().$implicit; const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.onCopyValue(cm_r4.Value)); });
327
+ i0.ɵɵelementStart(3, "div", 31)(4, "div", 32);
328
+ i0.ɵɵlistener("click", function ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Template_div_click_4_listener() { i0.ɵɵrestoreView(_r10); const cm_r9 = i0.ɵɵnextContext().$implicit; const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.onCopyValue(cm_r9.Value)); });
145
329
  i0.ɵɵtext(5);
146
330
  i0.ɵɵelementEnd();
147
- i0.ɵɵelementStart(6, "div", 31);
331
+ i0.ɵɵelementStart(6, "div", 33);
148
332
  i0.ɵɵtext(7);
149
333
  i0.ɵɵelementEnd()();
150
- i0.ɵɵelementStart(8, "div", 32);
151
- i0.ɵɵconditionalCreate(9, ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_9_Template, 2, 0, "span", 33);
334
+ i0.ɵɵelementStart(8, "div", 34);
335
+ i0.ɵɵconditionalCreate(9, ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_9_Template, 2, 0, "span", 35);
336
+ i0.ɵɵconditionalCreate(10, ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_10_Template, 5, 2);
152
337
  i0.ɵɵelementEnd();
153
- i0.ɵɵelementStart(10, "div", 34);
154
- i0.ɵɵconditionalCreate(11, ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_11_Template, 2, 0, "button", 35);
155
- i0.ɵɵconditionalCreate(12, ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_12_Template, 2, 0, "button", 36)(13, ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_13_Template, 2, 0, "button", 37);
156
- i0.ɵɵconditionalCreate(14, ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_14_Template, 4, 0);
338
+ i0.ɵɵelementStart(11, "div", 36);
339
+ i0.ɵɵconditionalCreate(12, ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_12_Template, 2, 0, "button", 37);
340
+ i0.ɵɵconditionalCreate(13, ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_13_Template, 2, 0, "button", 38)(14, ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_14_Template, 2, 0, "button", 39);
341
+ i0.ɵɵconditionalCreate(15, ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Conditional_15_Template, 4, 0);
157
342
  i0.ɵɵelementEnd()();
158
343
  } if (rf & 2) {
159
- const cm_r4 = i0.ɵɵnextContext().$implicit;
344
+ const cm_r9 = i0.ɵɵnextContext().$implicit;
160
345
  const ctx_r0 = i0.ɵɵnextContext(2);
161
- i0.ɵɵclassProp("primary", cm_r4.IsPrimary);
346
+ i0.ɵɵclassProp("primary", cm_r9.IsPrimary);
162
347
  i0.ɵɵadvance();
163
- i0.ɵɵproperty("ngClass", ctx_r0.getIconColorClass(cm_r4.ContactTypeID));
348
+ i0.ɵɵproperty("ngClass", ctx_r0.getIconColorClass(cm_r9.ContactTypeID));
164
349
  i0.ɵɵadvance();
165
- i0.ɵɵclassMap(ctx_r0.getContactTypeIcon(cm_r4.ContactTypeID));
350
+ i0.ɵɵclassMap(ctx_r0.getContactTypeIcon(cm_r9.ContactTypeID));
166
351
  i0.ɵɵadvance(3);
167
- i0.ɵɵtextInterpolate(cm_r4.Value);
352
+ i0.ɵɵtextInterpolate(cm_r9.Value);
168
353
  i0.ɵɵadvance(2);
169
- i0.ɵɵtextInterpolate(ctx_r0.getContactMeta(cm_r4));
354
+ i0.ɵɵtextInterpolate(ctx_r0.getContactMeta(cm_r9));
170
355
  i0.ɵɵadvance(2);
171
- i0.ɵɵconditional(cm_r4.IsPrimary ? 9 : -1);
356
+ i0.ɵɵconditional(cm_r9.IsPrimary ? 9 : -1);
357
+ i0.ɵɵadvance();
358
+ i0.ɵɵconditional(ctx_r0.isConsentType(cm_r9.ContactTypeID) ? 10 : -1);
172
359
  i0.ɵɵadvance(2);
173
- i0.ɵɵconditional(ctx_r0.EditMode && !cm_r4.IsPrimary ? 11 : -1);
360
+ i0.ɵɵconditional(ctx_r0.EditMode && !cm_r9.IsPrimary ? 12 : -1);
174
361
  i0.ɵɵadvance();
175
- i0.ɵɵconditional(ctx_r0.isLinkType(cm_r4.ContactTypeID) ? 12 : 13);
362
+ i0.ɵɵconditional(ctx_r0.isLinkType(cm_r9.ContactTypeID) ? 13 : 14);
176
363
  i0.ɵɵadvance(2);
177
- i0.ɵɵconditional(ctx_r0.EditMode ? 14 : -1);
364
+ i0.ɵɵconditional(ctx_r0.EditMode ? 15 : -1);
178
365
  } }
179
366
  function ContactMethodListComponent_Conditional_6_For_3_Template(rf, ctx) { if (rf & 1) {
180
- i0.ɵɵconditionalCreate(0, ContactMethodListComponent_Conditional_6_For_3_Conditional_0_Template, 26, 9, "div", 10)(1, ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Template, 15, 11, "div", 11);
367
+ i0.ɵɵconditionalCreate(0, ContactMethodListComponent_Conditional_6_For_3_Conditional_0_Template, 27, 10, "div", 10)(1, ContactMethodListComponent_Conditional_6_For_3_Conditional_1_Template, 16, 12, "div", 11);
181
368
  } if (rf & 2) {
182
- const cm_r4 = ctx.$implicit;
369
+ const cm_r9 = ctx.$implicit;
183
370
  const ctx_r0 = i0.ɵɵnextContext(2);
184
- i0.ɵɵconditional(ctx_r0.EditingId === cm_r4.ID ? 0 : 1);
371
+ i0.ɵɵconditional(ctx_r0.EditingId === cm_r9.ID ? 0 : 1);
185
372
  } }
186
373
  function ContactMethodListComponent_Conditional_6_Conditional_4_For_6_Template(rf, ctx) { if (rf & 1) {
187
374
  i0.ɵɵelementStart(0, "option", 15);
188
375
  i0.ɵɵtext(1);
189
376
  i0.ɵɵelementEnd();
190
377
  } if (rf & 2) {
191
- const t_r11 = ctx.$implicit;
192
- i0.ɵɵproperty("value", t_r11.ID);
378
+ const t_r20 = ctx.$implicit;
379
+ i0.ɵɵproperty("value", t_r20.ID);
193
380
  i0.ɵɵadvance();
194
- i0.ɵɵtextInterpolate(t_r11.Name);
381
+ i0.ɵɵtextInterpolate(t_r20.Name);
195
382
  } }
196
383
  function ContactMethodListComponent_Conditional_6_Conditional_4_Conditional_21_Template(rf, ctx) { if (rf & 1) {
197
384
  i0.ɵɵelement(0, "i", 25);
198
385
  } }
386
+ function ContactMethodListComponent_Conditional_6_Conditional_4_Conditional_25_For_6_Template(rf, ctx) { if (rf & 1) {
387
+ i0.ɵɵelementStart(0, "option", 15);
388
+ i0.ɵɵtext(1);
389
+ i0.ɵɵelementEnd();
390
+ } if (rf & 2) {
391
+ const s_r22 = ctx.$implicit;
392
+ i0.ɵɵproperty("value", s_r22);
393
+ i0.ɵɵadvance();
394
+ i0.ɵɵtextInterpolate(s_r22);
395
+ } }
396
+ function ContactMethodListComponent_Conditional_6_Conditional_4_Conditional_25_For_8_For_5_Template(rf, ctx) { if (rf & 1) {
397
+ i0.ɵɵelementStart(0, "option", 15);
398
+ i0.ɵɵtext(1);
399
+ i0.ɵɵelementEnd();
400
+ } if (rf & 2) {
401
+ const s_r25 = ctx.$implicit;
402
+ i0.ɵɵproperty("value", s_r25);
403
+ i0.ɵɵadvance();
404
+ i0.ɵɵtextInterpolate(s_r25);
405
+ } }
406
+ function ContactMethodListComponent_Conditional_6_Conditional_4_Conditional_25_For_8_Template(rf, ctx) { if (rf & 1) {
407
+ const _r23 = i0.ɵɵgetCurrentView();
408
+ i0.ɵɵelementStart(0, "div", 28)(1, "label");
409
+ i0.ɵɵtext(2);
410
+ i0.ɵɵelementEnd();
411
+ i0.ɵɵelementStart(3, "select", 14);
412
+ i0.ɵɵtwoWayListener("ngModelChange", function ContactMethodListComponent_Conditional_6_Conditional_4_Conditional_25_For_8_Template_select_ngModelChange_3_listener($event) { const p_r24 = i0.ɵɵrestoreView(_r23).$implicit; const ctx_r0 = i0.ɵɵnextContext(4); i0.ɵɵtwoWayBindingSet(ctx_r0.AddForm.Consents[p_r24.ID], $event) || (ctx_r0.AddForm.Consents[p_r24.ID] = $event); return i0.ɵɵresetView($event); });
413
+ i0.ɵɵrepeaterCreate(4, ContactMethodListComponent_Conditional_6_Conditional_4_Conditional_25_For_8_For_5_Template, 2, 2, "option", 15, i0.ɵɵrepeaterTrackByIdentity);
414
+ i0.ɵɵelementEnd()();
415
+ } if (rf & 2) {
416
+ const p_r24 = ctx.$implicit;
417
+ const ctx_r0 = i0.ɵɵnextContext(4);
418
+ i0.ɵɵadvance(2);
419
+ i0.ɵɵtextInterpolate(p_r24.Name);
420
+ i0.ɵɵadvance();
421
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r0.AddForm.Consents[p_r24.ID]);
422
+ i0.ɵɵadvance();
423
+ i0.ɵɵrepeater(ctx_r0.ConsentStatuses);
424
+ } }
425
+ function ContactMethodListComponent_Conditional_6_Conditional_4_Conditional_25_Template(rf, ctx) { if (rf & 1) {
426
+ const _r21 = i0.ɵɵgetCurrentView();
427
+ i0.ɵɵelementStart(0, "div", 27)(1, "div", 28)(2, "label");
428
+ i0.ɵɵtext(3, "General");
429
+ i0.ɵɵelementEnd();
430
+ i0.ɵɵelementStart(4, "select", 14);
431
+ i0.ɵɵtwoWayListener("ngModelChange", function ContactMethodListComponent_Conditional_6_Conditional_4_Conditional_25_Template_select_ngModelChange_4_listener($event) { i0.ɵɵrestoreView(_r21); const ctx_r0 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r0.AddForm.Consents[ctx_r0.GeneralKey], $event) || (ctx_r0.AddForm.Consents[ctx_r0.GeneralKey] = $event); return i0.ɵɵresetView($event); });
432
+ i0.ɵɵrepeaterCreate(5, ContactMethodListComponent_Conditional_6_Conditional_4_Conditional_25_For_6_Template, 2, 2, "option", 15, i0.ɵɵrepeaterTrackByIdentity);
433
+ i0.ɵɵelementEnd()();
434
+ i0.ɵɵrepeaterCreate(7, ContactMethodListComponent_Conditional_6_Conditional_4_Conditional_25_For_8_Template, 6, 2, "div", 28, _forTrack0);
435
+ i0.ɵɵelementEnd();
436
+ } if (rf & 2) {
437
+ const ctx_r0 = i0.ɵɵnextContext(3);
438
+ i0.ɵɵadvance(4);
439
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r0.AddForm.Consents[ctx_r0.GeneralKey]);
440
+ i0.ɵɵadvance();
441
+ i0.ɵɵrepeater(ctx_r0.ConsentStatuses);
442
+ i0.ɵɵadvance(2);
443
+ i0.ɵɵrepeater(ctx_r0.ConsentPurposes);
444
+ } }
199
445
  function ContactMethodListComponent_Conditional_6_Conditional_4_Template(rf, ctx) { if (rf & 1) {
200
- const _r10 = i0.ɵɵgetCurrentView();
446
+ const _r19 = i0.ɵɵgetCurrentView();
201
447
  i0.ɵɵelementStart(0, "div", 8)(1, "div", 13)(2, "label");
202
448
  i0.ɵɵtext(3, "Type");
203
449
  i0.ɵɵelementEnd();
204
450
  i0.ɵɵelementStart(4, "select", 14);
205
- i0.ɵɵtwoWayListener("ngModelChange", function ContactMethodListComponent_Conditional_6_Conditional_4_Template_select_ngModelChange_4_listener($event) { i0.ɵɵrestoreView(_r10); const ctx_r0 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r0.AddForm.TypeID, $event) || (ctx_r0.AddForm.TypeID = $event); return i0.ɵɵresetView($event); });
451
+ i0.ɵɵtwoWayListener("ngModelChange", function ContactMethodListComponent_Conditional_6_Conditional_4_Template_select_ngModelChange_4_listener($event) { i0.ɵɵrestoreView(_r19); const ctx_r0 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r0.AddForm.TypeID, $event) || (ctx_r0.AddForm.TypeID = $event); return i0.ɵɵresetView($event); });
206
452
  i0.ɵɵrepeaterCreate(5, ContactMethodListComponent_Conditional_6_Conditional_4_For_6_Template, 2, 2, "option", 15, _forTrack0);
207
453
  i0.ɵɵelementEnd()();
208
454
  i0.ɵɵelementStart(7, "div", 16)(8, "label");
209
455
  i0.ɵɵtext(9, "Value");
210
456
  i0.ɵɵelementEnd();
211
457
  i0.ɵɵelementStart(10, "input", 17);
212
- i0.ɵɵtwoWayListener("ngModelChange", function ContactMethodListComponent_Conditional_6_Conditional_4_Template_input_ngModelChange_10_listener($event) { i0.ɵɵrestoreView(_r10); const ctx_r0 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r0.AddForm.Value, $event) || (ctx_r0.AddForm.Value = $event); return i0.ɵɵresetView($event); });
458
+ i0.ɵɵtwoWayListener("ngModelChange", function ContactMethodListComponent_Conditional_6_Conditional_4_Template_input_ngModelChange_10_listener($event) { i0.ɵɵrestoreView(_r19); const ctx_r0 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r0.AddForm.Value, $event) || (ctx_r0.AddForm.Value = $event); return i0.ɵɵresetView($event); });
213
459
  i0.ɵɵelementEnd()();
214
460
  i0.ɵɵelementStart(11, "div", 18)(12, "label");
215
461
  i0.ɵɵtext(13, "Label");
216
462
  i0.ɵɵelementEnd();
217
- i0.ɵɵelementStart(14, "input", 49);
218
- i0.ɵɵtwoWayListener("ngModelChange", function ContactMethodListComponent_Conditional_6_Conditional_4_Template_input_ngModelChange_14_listener($event) { i0.ɵɵrestoreView(_r10); const ctx_r0 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r0.AddForm.Label, $event) || (ctx_r0.AddForm.Label = $event); return i0.ɵɵresetView($event); });
463
+ i0.ɵɵelementStart(14, "input", 65);
464
+ i0.ɵɵtwoWayListener("ngModelChange", function ContactMethodListComponent_Conditional_6_Conditional_4_Template_input_ngModelChange_14_listener($event) { i0.ɵɵrestoreView(_r19); const ctx_r0 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r0.AddForm.Label, $event) || (ctx_r0.AddForm.Label = $event); return i0.ɵɵresetView($event); });
219
465
  i0.ɵɵelementEnd()();
220
- i0.ɵɵelementStart(15, "div", 20)(16, "input", 50);
221
- i0.ɵɵtwoWayListener("ngModelChange", function ContactMethodListComponent_Conditional_6_Conditional_4_Template_input_ngModelChange_16_listener($event) { i0.ɵɵrestoreView(_r10); const ctx_r0 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r0.AddForm.IsPrimary, $event) || (ctx_r0.AddForm.IsPrimary = $event); return i0.ɵɵresetView($event); });
466
+ i0.ɵɵelementStart(15, "div", 20)(16, "input", 66);
467
+ i0.ɵɵtwoWayListener("ngModelChange", function ContactMethodListComponent_Conditional_6_Conditional_4_Template_input_ngModelChange_16_listener($event) { i0.ɵɵrestoreView(_r19); const ctx_r0 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r0.AddForm.IsPrimary, $event) || (ctx_r0.AddForm.IsPrimary = $event); return i0.ɵɵresetView($event); });
222
468
  i0.ɵɵelementEnd();
223
- i0.ɵɵelementStart(17, "label", 51);
469
+ i0.ɵɵelementStart(17, "label", 67);
224
470
  i0.ɵɵtext(18, "Primary");
225
471
  i0.ɵɵelementEnd()();
226
472
  i0.ɵɵelementStart(19, "div", 23)(20, "button", 24);
227
- i0.ɵɵlistener("click", function ContactMethodListComponent_Conditional_6_Conditional_4_Template_button_click_20_listener() { i0.ɵɵrestoreView(_r10); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.onSaveAdd()); });
473
+ i0.ɵɵlistener("click", function ContactMethodListComponent_Conditional_6_Conditional_4_Template_button_click_20_listener() { i0.ɵɵrestoreView(_r19); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.onSaveAdd()); });
228
474
  i0.ɵɵconditionalCreate(21, ContactMethodListComponent_Conditional_6_Conditional_4_Conditional_21_Template, 1, 0, "i", 25);
229
475
  i0.ɵɵtext(22, " Add ");
230
476
  i0.ɵɵelementEnd();
231
477
  i0.ɵɵelementStart(23, "button", 26);
232
- i0.ɵɵlistener("click", function ContactMethodListComponent_Conditional_6_Conditional_4_Template_button_click_23_listener() { i0.ɵɵrestoreView(_r10); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.onCancelAdd()); });
478
+ i0.ɵɵlistener("click", function ContactMethodListComponent_Conditional_6_Conditional_4_Template_button_click_23_listener() { i0.ɵɵrestoreView(_r19); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.onCancelAdd()); });
233
479
  i0.ɵɵtext(24, "Cancel");
234
- i0.ɵɵelementEnd()()();
480
+ i0.ɵɵelementEnd()();
481
+ i0.ɵɵconditionalCreate(25, ContactMethodListComponent_Conditional_6_Conditional_4_Conditional_25_Template, 9, 1, "div", 27);
482
+ i0.ɵɵelementEnd();
235
483
  } if (rf & 2) {
236
484
  const ctx_r0 = i0.ɵɵnextContext(2);
237
485
  i0.ɵɵadvance(4);
@@ -249,12 +497,14 @@ function ContactMethodListComponent_Conditional_6_Conditional_4_Template(rf, ctx
249
497
  i0.ɵɵproperty("disabled", ctx_r0.Saving);
250
498
  i0.ɵɵadvance();
251
499
  i0.ɵɵconditional(ctx_r0.Saving ? 21 : -1);
500
+ i0.ɵɵadvance(4);
501
+ i0.ɵɵconditional(ctx_r0.isConsentType(ctx_r0.AddForm.TypeID) ? 25 : -1);
252
502
  } }
253
503
  function ContactMethodListComponent_Conditional_6_Conditional_5_Template(rf, ctx) { if (rf & 1) {
254
- const _r12 = i0.ɵɵgetCurrentView();
255
- i0.ɵɵelementStart(0, "div", 9)(1, "button", 52);
256
- i0.ɵɵlistener("click", function ContactMethodListComponent_Conditional_6_Conditional_5_Template_button_click_1_listener() { i0.ɵɵrestoreView(_r12); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.onShowAdd()); });
257
- i0.ɵɵelement(2, "i", 53);
504
+ const _r26 = i0.ɵɵgetCurrentView();
505
+ i0.ɵɵelementStart(0, "div", 9)(1, "button", 68);
506
+ i0.ɵɵlistener("click", function ContactMethodListComponent_Conditional_6_Conditional_5_Template_button_click_1_listener() { i0.ɵɵrestoreView(_r26); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.onShowAdd()); });
507
+ i0.ɵɵelement(2, "i", 69);
258
508
  i0.ɵɵtext(3, " Add Contact ");
259
509
  i0.ɵɵelementEnd()();
260
510
  } }
@@ -262,7 +512,7 @@ function ContactMethodListComponent_Conditional_6_Template(rf, ctx) { if (rf & 1
262
512
  i0.ɵɵelementStart(0, "div", 4);
263
513
  i0.ɵɵconditionalCreate(1, ContactMethodListComponent_Conditional_6_Conditional_1_Template, 3, 0, "div", 7);
264
514
  i0.ɵɵrepeaterCreate(2, ContactMethodListComponent_Conditional_6_For_3_Template, 2, 1, null, null, _forTrack0);
265
- i0.ɵɵconditionalCreate(4, ContactMethodListComponent_Conditional_6_Conditional_4_Template, 25, 7, "div", 8);
515
+ i0.ɵɵconditionalCreate(4, ContactMethodListComponent_Conditional_6_Conditional_4_Template, 26, 8, "div", 8);
266
516
  i0.ɵɵconditionalCreate(5, ContactMethodListComponent_Conditional_6_Conditional_5_Template, 4, 0, "div", 9);
267
517
  i0.ɵɵelementEnd();
268
518
  } if (rf & 2) {
@@ -276,9 +526,15 @@ function ContactMethodListComponent_Conditional_6_Template(rf, ctx) { if (rf & 1
276
526
  i0.ɵɵadvance();
277
527
  i0.ɵɵconditional(!ctx_r0.ShowAddForm && ctx_r0.EditingId === null && ctx_r0.EditMode ? 5 : -1);
278
528
  } }
529
+ /** The form key for a method's general consent: the row with no purpose, which answers for anything. */
530
+ export const GENERAL_CONSENT_KEY = 'general';
531
+ /** True when a metadata provider also serves views, as every MJ provider does. */
532
+ function isRunViewProvider(p) {
533
+ return typeof p.RunView === 'function';
534
+ }
279
535
  /**
280
536
  * Displays and manages contact methods (email, phone, social, etc.) for a
281
- * Person or Organization record.
537
+ * Person or Organization record, with each method's consents.
282
538
  *
283
539
  * Contact methods are loaded from the `MJ_BizApps_Common: Contact Methods`
284
540
  * entity, filtered by either {@link PersonID}, {@link OrganizationID}, or
@@ -286,6 +542,10 @@ function ContactMethodListComponent_Conditional_6_Template(rf, ctx) { if (rf & 1
286
542
  * The component provides inline add, edit, delete, set-primary, copy-to-clipboard,
287
543
  * and open-link functionality.
288
544
  *
545
+ * Consent hangs off each method as `MJ_BizApps_Common: Contact Consents` rows, one per purpose
546
+ * and optional organization. Every channel type (email, phone) shows a badge per consent, with
547
+ * the method's consent history on hover, and the edit row offers a dropdown per active purpose.
548
+ *
289
549
  * Primary management is scoped per contact type -- setting a contact as primary
290
550
  * only demotes other primaries of the **same** type.
291
551
  *
@@ -306,6 +566,20 @@ export class ContactMethodListComponent {
306
566
  * Copy and open-link actions remain available regardless of this setting.
307
567
  */
308
568
  EditMode = false;
569
+ /**
570
+ * The metadata provider to read and write through. Defaults to the global provider, which is
571
+ * right for a single-server Explorer; a host on several providers passes its own.
572
+ */
573
+ Provider;
574
+ /** The provider this component reads and writes with. */
575
+ get ProviderToUse() {
576
+ return this.Provider ?? Metadata.Provider;
577
+ }
578
+ /** The same provider for RunView, when it serves views; otherwise RunView's own default. */
579
+ get runViewToUse() {
580
+ const p = this.ProviderToUse;
581
+ return isRunViewProvider(p) ? p : null;
582
+ }
309
583
  /** Emitted after any mutation (save, delete, set-primary) so the parent can refresh derived data. */
310
584
  DataChanged = new EventEmitter();
311
585
  _collection;
@@ -367,6 +641,14 @@ export class ContactMethodListComponent {
367
641
  * Loaded from `MJ_BizApps_Common: Contact Types`, sorted by `DisplayRank ASC`.
368
642
  */
369
643
  ContactTypes = [];
644
+ /** The active consent purposes, by display rank: one dropdown each on the add and edit rows. */
645
+ ConsentPurposes = [];
646
+ /** The consent choices offered per purpose, in the order the CHECK constraint lists them. */
647
+ ConsentStatuses = ContactMethodConsentEntity.Statuses;
648
+ /** The form key of the general (any purpose) consent, for the template. */
649
+ GeneralKey = GENERAL_CONSENT_KEY;
650
+ /** Each loaded method's consent rows (every purpose and organization), keyed by contact method ID. */
651
+ consentsByMethod = new Map();
370
652
  /**
371
653
  * The ID of the contact method currently being edited, or `null` when
372
654
  * not in edit mode.
@@ -397,6 +679,14 @@ export class ContactMethodListComponent {
397
679
  * Reset to defaults each time the add form is opened.
398
680
  */
399
681
  AddForm = this.createEmptyForm();
682
+ /** The contact method whose consent history is open under its badges, or `null`. */
683
+ ConsentHistoryFor = null;
684
+ /** The history lines shown for {@link ConsentHistoryFor}, newest first, across the method's consents. */
685
+ ConsentHistory = [];
686
+ /** True while the history for {@link ConsentHistoryFor} is being read. */
687
+ ConsentHistoryLoading = false;
688
+ /** History already read this session, by contact method ID; dropped for a row when it is saved. */
689
+ consentHistoryCache = new Map();
400
690
  /** Maps lowercase contact type names to CSS icon-color classes. */
401
691
  iconColorMap = {
402
692
  'email': 'icon-email',
@@ -414,10 +704,10 @@ export class ContactMethodListComponent {
414
704
  linkTypeNames = new Set(['linkedin', 'twitter', 'twitter / x', 'website']);
415
705
  /** Creates a blank {@link ContactFormData} with empty defaults. */
416
706
  createEmptyForm() {
417
- return { TypeID: '', Value: '', Label: '', IsPrimary: false };
707
+ return { TypeID: '', Value: '', Label: '', IsPrimary: false, Consents: {} };
418
708
  }
419
709
  /**
420
- * Loads contact methods and contact types from the server or collection.
710
+ * Loads contact methods, contact types, consent purposes and the methods' consents.
421
711
  * Resets editing state before loading.
422
712
  */
423
713
  async loadData() {
@@ -426,63 +716,100 @@ export class ContactMethodListComponent {
426
716
  this.ShowAddForm = false;
427
717
  this.cdr.detectChanges();
428
718
  try {
429
- const rv = new RunView();
430
- // Always ensure contact types are loaded
431
- if (this.ContactTypes.length === 0) {
432
- const typesResult = await rv.RunView({
433
- EntityName: 'MJ_BizApps_Common: Contact Types',
434
- ExtraFilter: 'IsActive=1',
435
- OrderBy: 'DisplayRank ASC',
436
- ResultType: 'entity_object'
437
- });
438
- if (typesResult.Success && typesResult.Results) {
439
- this.ContactTypes = typesResult.Results;
440
- }
441
- }
719
+ await this.loadLookups();
442
720
  if (this._collection) {
443
721
  if (!this._collection.IsLoaded) {
444
722
  await this._collection.Load();
445
723
  }
446
724
  this.ContactMethods = [...this._collection.Items];
447
- this.sortContactMethods();
448
- if (this.ContactTypes.length > 0 && !this.AddForm.TypeID) {
449
- this.AddForm.TypeID = this.ContactTypes[0].ID;
450
- }
451
- return;
452
- }
453
- // Build filter for standalone mode
454
- let filter = '';
455
- if (this._personID) {
456
- filter = `PersonID='${this._personID}'`;
457
- }
458
- else if (this._organizationID) {
459
- filter = `OrganizationID='${this._organizationID}'`;
460
725
  }
461
726
  else {
462
- return;
727
+ this.ContactMethods = await this.loadStandaloneMethods();
463
728
  }
464
- const methodsResult = await rv.RunView({
465
- EntityName: 'MJ_BizApps_Common: Contact Methods',
466
- ExtraFilter: filter,
467
- ResultType: 'entity_object'
468
- });
469
- this.ContactMethods = methodsResult.Success
470
- ? methodsResult.Results
471
- : [];
472
729
  this.sortContactMethods();
473
- // Set default type for add form
474
- if (this.ContactTypes.length > 0) {
730
+ await this.loadConsents();
731
+ if (this.ContactTypes.length > 0 && !this.AddForm.TypeID) {
475
732
  this.AddForm.TypeID = this.ContactTypes[0].ID;
476
733
  }
477
734
  }
478
735
  catch (err) {
479
- console.error('ContactMethodList: Error loading data', err);
736
+ LogError(`ContactMethodList: Error loading data: ${String(err)}`);
480
737
  }
481
738
  finally {
482
739
  this.Loading = false;
483
740
  this.cdr.detectChanges();
484
741
  }
485
742
  }
743
+ /** Reads contact types and consent purposes once, in one round trip. */
744
+ async loadLookups() {
745
+ if (this.ContactTypes.length > 0 && this.ConsentPurposes.length > 0) {
746
+ return;
747
+ }
748
+ const rv = new RunView(this.runViewToUse);
749
+ const [types, purposes] = await rv.RunViews([
750
+ {
751
+ EntityName: 'MJ_BizApps_Common: Contact Types',
752
+ ExtraFilter: 'IsActive=1',
753
+ OrderBy: 'DisplayRank ASC',
754
+ ResultType: 'entity_object'
755
+ },
756
+ {
757
+ EntityName: 'MJ_BizApps_Common: Consent Purposes',
758
+ ExtraFilter: 'IsActive=1',
759
+ OrderBy: 'Sequence ASC',
760
+ ResultType: 'entity_object'
761
+ }
762
+ ]);
763
+ if (types.Success) {
764
+ this.ContactTypes = types.Results;
765
+ }
766
+ if (purposes.Success) {
767
+ this.ConsentPurposes = purposes.Results;
768
+ }
769
+ }
770
+ /** Reads the person's or organization's contact methods when no collection was bound. */
771
+ async loadStandaloneMethods() {
772
+ let filter = '';
773
+ if (this._personID) {
774
+ filter = `PersonID='${EscapeSQLString(this._personID)}'`;
775
+ }
776
+ else if (this._organizationID) {
777
+ filter = `OrganizationID='${EscapeSQLString(this._organizationID)}'`;
778
+ }
779
+ else {
780
+ return [];
781
+ }
782
+ const rv = new RunView(this.runViewToUse);
783
+ const result = await rv.RunView({
784
+ EntityName: 'MJ_BizApps_Common: Contact Methods',
785
+ ExtraFilter: filter,
786
+ ResultType: 'entity_object'
787
+ });
788
+ return result.Success ? result.Results : [];
789
+ }
790
+ /** Reads every consent row of the loaded (saved) methods in one query and groups them by method. */
791
+ async loadConsents() {
792
+ this.consentsByMethod.clear();
793
+ const ids = this.ContactMethods.filter((cm) => cm.IsSaved).map((cm) => `'${EscapeSQLString(cm.ID)}'`);
794
+ if (ids.length === 0) {
795
+ return;
796
+ }
797
+ const rv = new RunView(this.runViewToUse);
798
+ const result = await rv.RunView({
799
+ EntityName: 'MJ_BizApps_Common: Contact Method Consents',
800
+ ExtraFilter: `ContactMethodID IN (${ids.join(',')})`,
801
+ ResultType: 'entity_object'
802
+ });
803
+ if (!result.Success) {
804
+ LogError(`ContactMethodList: Error loading consents: ${result.ErrorMessage}`);
805
+ return;
806
+ }
807
+ for (const consent of result.Results) {
808
+ const list = this.consentsByMethod.get(consent.ContactMethodID) ?? [];
809
+ list.push(consent);
810
+ this.consentsByMethod.set(consent.ContactMethodID, list);
811
+ }
812
+ }
486
813
  sortContactMethods() {
487
814
  this.ContactMethods.sort((a, b) => {
488
815
  if (a.IsPrimary && !b.IsPrimary)
@@ -574,6 +901,135 @@ export class ContactMethodListComponent {
574
901
  return false;
575
902
  return this.linkTypeNames.has(ct.Name.toLowerCase());
576
903
  }
904
+ /**
905
+ * Whether a contact type carries consent: it maps to one of MJ's communication channels
906
+ * (Email, Phone, SMS). LinkedIn, Website and the like do not, so they show no badges.
907
+ *
908
+ * @param typeID - The ContactType record ID to check
909
+ */
910
+ isConsentType(typeID) {
911
+ const ct = this.ContactTypes.find(t => t.ID === typeID);
912
+ return !!ct?.CommunicationBaseMessageTypeID;
913
+ }
914
+ /** The consent rows a method has, in purpose order, general and installation-wide rows first. */
915
+ getConsents(cm) {
916
+ return [...this.consentRowsFor(cm)].sort((a, b) => {
917
+ const rank = this.getPurposeRank(a.ConsentPurposeID) - this.getPurposeRank(b.ConsentPurposeID);
918
+ if (rank !== 0)
919
+ return rank;
920
+ return (a.RequestingOrganizationID ? 1 : 0) - (b.RequestingOrganizationID ? 1 : 0);
921
+ });
922
+ }
923
+ /**
924
+ * Where a method's consents are read from. Once the method's own `Consents` collection holds
925
+ * rows, it is the source: inside a Person form an edit stays there, unsaved, until the form is
926
+ * saved, and the badges must show it rather than what was loaded when the list opened.
927
+ * Otherwise, the rows loaded with the list.
928
+ */
929
+ consentRowsFor(cm) {
930
+ if (cm.Consents.IsLoaded || cm.Consents.Items.length > 0) {
931
+ return cm.Consents.Items;
932
+ }
933
+ return this.consentsByMethod.get(cm.ID) ?? [];
934
+ }
935
+ /** Returns the Sequence for a consent purpose; the general row (no purpose) sorts first. */
936
+ getPurposeRank(purposeID) {
937
+ if (!purposeID)
938
+ return -1;
939
+ const p = this.ConsentPurposes.find(x => UUIDsEqual(x.ID, purposeID));
940
+ return p?.Sequence ?? 999;
941
+ }
942
+ /**
943
+ * A purpose's name, or General for the row with no purpose. Read from the purpose lookup, not
944
+ * the consent's own denormalized name, which an unsaved row does not have yet.
945
+ */
946
+ purposeName(purposeID) {
947
+ if (!purposeID)
948
+ return 'General';
949
+ return this.ConsentPurposes.find(x => UUIDsEqual(x.ID, purposeID))?.Name ?? 'Unknown purpose';
950
+ }
951
+ /** The badge text for a consent row: its purpose (or General), and the requesting organization when there is one. */
952
+ getConsentBadgeText(consent) {
953
+ const purpose = this.purposeName(consent.ConsentPurposeID);
954
+ return consent.RequestingOrganization ? `${purpose} · ${consent.RequestingOrganization}` : purpose;
955
+ }
956
+ /** The badge colour class for a consent status. */
957
+ getConsentBadgeClass(status) {
958
+ switch (status) {
959
+ case 'Opted In': return 'consent-in';
960
+ case 'Opted Out': return 'consent-out';
961
+ default: return 'consent-unknown';
962
+ }
963
+ }
964
+ /** The Font Awesome icon for a consent status. */
965
+ getConsentIcon(status) {
966
+ switch (status) {
967
+ case 'Opted In': return 'fa-solid fa-check';
968
+ case 'Opted Out': return 'fa-solid fa-ban';
969
+ default: return 'fa-regular fa-circle-question';
970
+ }
971
+ }
972
+ /**
973
+ * Opens the consent history under a row's badges, reading it on first hover and reusing it
974
+ * afterwards until that row is saved again.
975
+ *
976
+ * @param cm - The contact method whose badges are being hovered
977
+ */
978
+ async onShowConsentHistory(cm) {
979
+ this.ConsentHistoryFor = cm.ID;
980
+ const cached = this.consentHistoryCache.get(cm.ID);
981
+ if (cached) {
982
+ this.ConsentHistory = cached;
983
+ this.cdr.detectChanges();
984
+ return;
985
+ }
986
+ this.ConsentHistory = [];
987
+ this.ConsentHistoryLoading = true;
988
+ this.cdr.detectChanges();
989
+ const lines = await this.loadConsentHistory(cm);
990
+ this.consentHistoryCache.set(cm.ID, lines);
991
+ if (this.ConsentHistoryFor === cm.ID) {
992
+ this.ConsentHistory = lines;
993
+ }
994
+ this.ConsentHistoryLoading = false;
995
+ this.cdr.detectChanges();
996
+ }
997
+ /** Closes the consent history. */
998
+ onHideConsentHistory() {
999
+ this.ConsentHistoryFor = null;
1000
+ this.cdr.detectChanges();
1001
+ }
1002
+ /** Reads the history of every saved consent a method has, newest change first, labelled with its purpose. */
1003
+ async loadConsentHistory(cm) {
1004
+ const consents = this.consentRowsFor(cm).filter((c) => c.IsSaved);
1005
+ if (consents.length === 0) {
1006
+ return [];
1007
+ }
1008
+ const ids = consents.map((c) => `'${EscapeSQLString(c.ID)}'`).join(',');
1009
+ const rv = new RunView(this.runViewToUse);
1010
+ const result = await rv.RunView({
1011
+ EntityName: 'MJ_BizApps_Common: Contact Method Consent Histories',
1012
+ ExtraFilter: `ContactMethodConsentID IN (${ids})`,
1013
+ OrderBy: 'ConsentStatusAt DESC',
1014
+ ResultType: 'entity_object'
1015
+ });
1016
+ if (!result.Success) {
1017
+ LogError(`ContactMethodList: Error loading consent history: ${result.ErrorMessage}`);
1018
+ return [];
1019
+ }
1020
+ return result.Results.map((h) => {
1021
+ const consent = consents.find((c) => UUIDsEqual(c.ID, h.ContactMethodConsentID));
1022
+ return {
1023
+ ID: h.ID,
1024
+ Purpose: this.purposeName(consent?.ConsentPurposeID ?? null),
1025
+ RequestingOrganization: consent?.RequestingOrganization ?? null,
1026
+ ConsentStatusAt: h.ConsentStatusAt,
1027
+ NewConsentStatus: h.NewConsentStatus,
1028
+ ConsentSource: h.ConsentSource,
1029
+ ConsentDetails: h.ConsentDetails
1030
+ };
1031
+ });
1032
+ }
577
1033
  /**
578
1034
  * Copies the given string value to the system clipboard.
579
1035
  *
@@ -618,6 +1074,10 @@ export class ContactMethodListComponent {
618
1074
  if (this.ContactTypes.length > 0) {
619
1075
  this.AddForm.TypeID = this.ContactTypes[0].ID;
620
1076
  }
1077
+ this.AddForm.Consents[GENERAL_CONSENT_KEY] = ContactMethodConsentEntity.UnspecifiedStatus;
1078
+ for (const p of this.ConsentPurposes) {
1079
+ this.AddForm.Consents[p.ID] = ContactMethodConsentEntity.UnspecifiedStatus;
1080
+ }
621
1081
  this.ShowAddForm = true;
622
1082
  this.cdr.detectChanges();
623
1083
  }
@@ -629,7 +1089,7 @@ export class ContactMethodListComponent {
629
1089
  this.cdr.detectChanges();
630
1090
  }
631
1091
  /**
632
- * Persists the new contact method from the add form.
1092
+ * Persists the new contact method from the add form, with any consents chosen for it.
633
1093
  *
634
1094
  * When the "Primary" flag is set, other primaries of the same contact
635
1095
  * type are demoted first. The contact list is reloaded after saving.
@@ -640,44 +1100,41 @@ export class ContactMethodListComponent {
640
1100
  this.Saving = true;
641
1101
  this.cdr.detectChanges();
642
1102
  try {
643
- if (this._collection) {
644
- const cm = await this._collection.Create();
645
- cm.ContactTypeID = this.AddForm.TypeID;
646
- cm.Value = this.AddForm.Value;
647
- cm.Label = this.AddForm.Label || null;
648
- cm.IsPrimary = this.AddForm.IsPrimary;
649
- if (this.AddForm.IsPrimary) {
650
- await this.clearPrimariesForType(this.AddForm.TypeID);
1103
+ const cm = this._collection
1104
+ ? await this._collection.Create()
1105
+ : await this.ProviderToUse.GetEntityObject('MJ_BizApps_Common: Contact Methods');
1106
+ if (!this._collection) {
1107
+ cm.NewRecord();
1108
+ if (this._personID) {
1109
+ cm.PersonID = this._personID;
1110
+ }
1111
+ else if (this._organizationID) {
1112
+ cm.OrganizationID = this._organizationID;
651
1113
  }
652
- this.ContactMethods = [...this._collection.Items];
653
- this.sortContactMethods();
654
- this.ShowAddForm = false;
655
- this.DataChanged.emit();
656
- return;
657
1114
  }
658
- const md = new Metadata();
659
- const cm = await md.GetEntityObject('MJ_BizApps_Common: Contact Methods');
660
- cm.NewRecord();
661
1115
  cm.ContactTypeID = this.AddForm.TypeID;
662
1116
  cm.Value = this.AddForm.Value;
663
1117
  cm.Label = this.AddForm.Label || null;
664
1118
  cm.IsPrimary = this.AddForm.IsPrimary;
665
- if (this._personID) {
666
- cm.PersonID = this._personID;
667
- }
668
- else if (this._organizationID) {
669
- cm.OrganizationID = this._organizationID;
670
- }
671
- // If setting primary, clear other primaries of same type
1119
+ await this.applyConsentsFromForm(cm, this.AddForm);
672
1120
  if (this.AddForm.IsPrimary) {
673
1121
  await this.clearPrimariesForType(this.AddForm.TypeID);
674
1122
  }
675
- await cm.Save();
1123
+ if (this._collection) {
1124
+ this.ContactMethods = [...this._collection.Items];
1125
+ this.sortContactMethods();
1126
+ this.ShowAddForm = false;
1127
+ this.DataChanged.emit();
1128
+ return;
1129
+ }
1130
+ if (!(await cm.Save())) {
1131
+ LogError(`ContactMethodList: Error adding contact: ${cm.LatestResult?.CompleteMessage ?? 'unknown error'}`);
1132
+ }
676
1133
  await this.loadData();
677
1134
  this.DataChanged.emit();
678
1135
  }
679
1136
  catch (err) {
680
- console.error('ContactMethodList: Error adding contact', err);
1137
+ LogError(`ContactMethodList: Error adding contact: ${String(err)}`);
681
1138
  }
682
1139
  finally {
683
1140
  this.Saving = false;
@@ -686,18 +1143,26 @@ export class ContactMethodListComponent {
686
1143
  }
687
1144
  /**
688
1145
  * Opens the inline edit form for an existing contact method, populating
689
- * the form fields from the current entity data.
1146
+ * the form fields from the current entity data and its installation-wide consents.
690
1147
  *
691
1148
  * Closes the add form if it is currently open.
692
1149
  *
693
1150
  * @param cm - The contact method entity to edit
694
1151
  */
695
1152
  onEdit(cm) {
1153
+ const consents = {};
1154
+ const unspecified = ContactMethodConsentEntity.UnspecifiedStatus;
1155
+ consents[GENERAL_CONSENT_KEY] = this.findUnscopedConsent(cm, null)?.ConsentStatus ?? unspecified;
1156
+ for (const p of this.ConsentPurposes) {
1157
+ const row = this.findUnscopedConsent(cm, p.ID);
1158
+ consents[p.ID] = row?.ConsentStatus ?? unspecified;
1159
+ }
696
1160
  this.EditForm = {
697
1161
  TypeID: cm.ContactTypeID,
698
1162
  Value: cm.Value,
699
1163
  Label: cm.Label || '',
700
- IsPrimary: cm.IsPrimary
1164
+ IsPrimary: cm.IsPrimary,
1165
+ Consents: consents
701
1166
  };
702
1167
  this.EditingId = cm.ID;
703
1168
  this.ShowAddForm = false;
@@ -711,7 +1176,7 @@ export class ContactMethodListComponent {
711
1176
  this.cdr.detectChanges();
712
1177
  }
713
1178
  /**
714
- * Persists the edited contact method from the edit form.
1179
+ * Persists the edited contact method from the edit form, with its consents.
715
1180
  *
716
1181
  * When the "Primary" flag is newly set, other primaries of the same
717
1182
  * contact type are demoted first. The contact list is reloaded after saving.
@@ -733,6 +1198,8 @@ export class ContactMethodListComponent {
733
1198
  cm.Value = this.EditForm.Value;
734
1199
  cm.Label = this.EditForm.Label || null;
735
1200
  cm.IsPrimary = this.EditForm.IsPrimary;
1201
+ await this.applyConsentsFromForm(cm, this.EditForm);
1202
+ this.consentHistoryCache.delete(cm.ID);
736
1203
  if (this._collection) {
737
1204
  this.ContactMethods = [...this._collection.Items];
738
1205
  this.sortContactMethods();
@@ -740,18 +1207,57 @@ export class ContactMethodListComponent {
740
1207
  this.DataChanged.emit();
741
1208
  return;
742
1209
  }
743
- await cm.Save();
1210
+ if (!(await cm.Save())) {
1211
+ LogError(`ContactMethodList: Error saving contact: ${cm.LatestResult?.CompleteMessage ?? 'unknown error'}`);
1212
+ }
744
1213
  await this.loadData();
745
1214
  this.DataChanged.emit();
746
1215
  }
747
1216
  catch (err) {
748
- console.error('ContactMethodList: Error saving contact', err);
1217
+ LogError(`ContactMethodList: Error saving contact: ${String(err)}`);
749
1218
  }
750
1219
  finally {
751
1220
  this.Saving = false;
752
1221
  this.cdr.detectChanges();
753
1222
  }
754
1223
  }
1224
+ /** The method's installation-wide consent row for a purpose (null = the general row), including an unsaved edit, or null. */
1225
+ findUnscopedConsent(cm, purposeID) {
1226
+ return this.consentRowsFor(cm).find((r) => r.RequestingOrganizationID == null && UUIDsEqual(r.ConsentPurposeID, purposeID)) ?? null;
1227
+ }
1228
+ /**
1229
+ * Writes the form's per-purpose choices onto the method's `Consents` collection, so they save
1230
+ * with the method: an existing installation-wide row is updated when its status changed, and
1231
+ * a new row is created when a purpose was given a status for the first time. The consent
1232
+ * entity's own Save adds the history row for each change.
1233
+ */
1234
+ async applyConsentsFromForm(cm, form) {
1235
+ if (!this.isConsentType(form.TypeID)) {
1236
+ return;
1237
+ }
1238
+ if (cm.IsSaved && !cm.Consents.IsLoaded) {
1239
+ await cm.Consents.Load();
1240
+ }
1241
+ const keys = [
1242
+ { key: GENERAL_CONSENT_KEY, purposeID: null },
1243
+ ...this.ConsentPurposes.map((p) => ({ key: p.ID, purposeID: p.ID })),
1244
+ ];
1245
+ for (const { key, purposeID } of keys) {
1246
+ const wanted = form.Consents[key] ?? ContactMethodConsentEntity.UnspecifiedStatus;
1247
+ const existing = cm.Consents.Items.find((r) => r.RequestingOrganizationID == null && UUIDsEqual(r.ConsentPurposeID, purposeID));
1248
+ if (existing) {
1249
+ if (existing.ConsentStatus !== wanted) {
1250
+ existing.ConsentStatus = wanted;
1251
+ }
1252
+ }
1253
+ else if (wanted !== ContactMethodConsentEntity.UnspecifiedStatus) {
1254
+ const row = await cm.Consents.Create();
1255
+ row.ConsentPurposeID = purposeID;
1256
+ row.RequestingOrganizationID = null;
1257
+ row.ConsentStatus = wanted;
1258
+ }
1259
+ }
1260
+ }
755
1261
  /**
756
1262
  * Promotes the given contact method to primary for its contact type,
757
1263
  * demoting all other primaries of the same type.
@@ -773,12 +1279,14 @@ export class ContactMethodListComponent {
773
1279
  this.DataChanged.emit();
774
1280
  return;
775
1281
  }
776
- await cm.Save();
1282
+ if (!(await cm.Save())) {
1283
+ LogError(`ContactMethodList: Error setting primary: ${cm.LatestResult?.CompleteMessage ?? 'unknown error'}`);
1284
+ }
777
1285
  await this.loadData();
778
1286
  this.DataChanged.emit();
779
1287
  }
780
1288
  catch (err) {
781
- console.error('ContactMethodList: Error setting primary', err);
1289
+ LogError(`ContactMethodList: Error setting primary: ${String(err)}`);
782
1290
  }
783
1291
  finally {
784
1292
  this.Saving = false;
@@ -803,12 +1311,14 @@ export class ContactMethodListComponent {
803
1311
  this.DataChanged.emit();
804
1312
  return;
805
1313
  }
806
- await cm.Delete();
1314
+ if (!(await cm.Delete())) {
1315
+ LogError(`ContactMethodList: Error deleting contact: ${cm.LatestResult?.CompleteMessage ?? 'unknown error'}`);
1316
+ }
807
1317
  await this.loadData();
808
1318
  this.DataChanged.emit();
809
1319
  }
810
1320
  catch (err) {
811
- console.error('ContactMethodList: Error deleting contact', err);
1321
+ LogError(`ContactMethodList: Error deleting contact: ${String(err)}`);
812
1322
  }
813
1323
  finally {
814
1324
  this.Saving = false;
@@ -826,7 +1336,7 @@ export class ContactMethodListComponent {
826
1336
  }
827
1337
  }
828
1338
  static ɵfac = function ContactMethodListComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ContactMethodListComponent)(); };
829
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ContactMethodListComponent, selectors: [["bizapps-contact-method-list"]], inputs: { EditMode: "EditMode", Collection: "Collection", PersonID: "PersonID", OrganizationID: "OrganizationID" }, outputs: { DataChanged: "DataChanged" }, decls: 7, vars: 2, consts: [[1, "section-header"], [1, "section-label"], [1, "fa-solid", "fa-address-card"], [1, "count"], [1, "cm-flat-list"], [1, "loading-row"], [1, "fa-solid", "fa-spinner"], [1, "empty-state"], [1, "cm-flat-add-form"], [1, "cm-flat-footer"], [1, "cm-flat-edit-row"], [1, "cm-flat-row", 3, "primary"], [1, "form-row"], [1, "form-field", "type-field"], [3, "ngModelChange", "ngModel"], [3, "value"], [1, "form-field", "flex-1"], ["type", "text", 3, "ngModelChange", "ngModel", "placeholder"], [1, "form-field", "label-field"], ["type", "text", "placeholder", "e.g., Work", 3, "ngModelChange", "ngModel"], [1, "checkbox-field"], ["type", "checkbox", 3, "ngModelChange", "id", "ngModel"], [3, "for"], [1, "form-actions"], [1, "btn", "btn-primary", "btn-sm", 3, "click", "disabled"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "btn", "btn-cancel", "btn-sm", 3, "click"], [1, "cm-flat-row"], [1, "cm-flat-icon", 3, "ngClass"], [1, "cm-flat-content"], [1, "cm-flat-value", 3, "click"], [1, "cm-flat-meta"], [1, "cm-flat-badges"], [1, "badge", "badge-primary"], [1, "cm-flat-actions"], ["title", "Set Primary", 1, "btn-ghost"], ["title", "Open", 1, "btn-ghost"], ["title", "Copy", 1, "btn-ghost"], [1, "fa-solid", "fa-star"], ["title", "Set Primary", 1, "btn-ghost", 3, "click"], [1, "fa-regular", "fa-star"], ["title", "Open", 1, "btn-ghost", 3, "click"], [1, "fa-solid", "fa-external-link"], ["title", "Copy", 1, "btn-ghost", 3, "click"], [1, "fa-solid", "fa-copy"], ["title", "Edit", 1, "btn-ghost", 3, "click"], [1, "fa-solid", "fa-pen"], ["title", "Remove", 1, "btn-ghost", "danger", 3, "click"], [1, "fa-solid", "fa-trash"], ["type", "text", "placeholder", "e.g., Direct Line", 3, "ngModelChange", "ngModel"], ["type", "checkbox", "id", "primary-add", 3, "ngModelChange", "ngModel"], ["for", "primary-add"], [1, "btn", "btn-outline", "full-width", 3, "click"], [1, "fa-solid", "fa-plus"]], template: function ContactMethodListComponent_Template(rf, ctx) { if (rf & 1) {
1339
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ContactMethodListComponent, selectors: [["bizapps-contact-method-list"]], inputs: { EditMode: "EditMode", Provider: "Provider", Collection: "Collection", PersonID: "PersonID", OrganizationID: "OrganizationID" }, outputs: { DataChanged: "DataChanged" }, decls: 7, vars: 2, consts: [[1, "section-header"], [1, "section-label"], [1, "fa-solid", "fa-address-card"], [1, "count"], [1, "cm-flat-list"], [1, "loading-row"], [1, "fa-solid", "fa-spinner"], [1, "empty-state"], [1, "cm-flat-add-form"], [1, "cm-flat-footer"], [1, "cm-flat-edit-row"], [1, "cm-flat-row", 3, "primary"], [1, "form-row"], [1, "form-field", "type-field"], [3, "ngModelChange", "ngModel"], [3, "value"], [1, "form-field", "flex-1"], ["type", "text", 3, "ngModelChange", "ngModel", "placeholder"], [1, "form-field", "label-field"], ["type", "text", "placeholder", "e.g., Work", 3, "ngModelChange", "ngModel"], [1, "checkbox-field"], ["type", "checkbox", 3, "ngModelChange", "id", "ngModel"], [3, "for"], [1, "form-actions"], [1, "btn", "btn-primary", "btn-sm", 3, "click", "disabled"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "btn", "btn-cancel", "btn-sm", 3, "click"], [1, "form-row", "consent-row"], [1, "form-field", "consent-field"], [1, "cm-flat-row"], [1, "cm-flat-icon", 3, "ngClass"], [1, "cm-flat-content"], [1, "cm-flat-value", 3, "click"], [1, "cm-flat-meta"], [1, "cm-flat-badges"], [1, "badge", "badge-primary"], [1, "cm-flat-actions"], ["title", "Set Primary", 1, "btn-ghost"], ["title", "Open", 1, "btn-ghost"], ["title", "Copy", 1, "btn-ghost"], [1, "fa-solid", "fa-star"], [1, "consent-badges", 3, "mouseenter", "mouseleave"], [1, "badge", "badge-consent", 3, "ngClass"], [1, "badge", "badge-consent", "consent-unknown"], [1, "consent-history"], [1, "consent-purpose"], [1, "fa-regular", "fa-circle-question"], [1, "consent-history", 3, "mouseenter", "mouseleave"], [1, "consent-history-title"], ["Text", "Loading history...", "Size", "small"], [1, "consent-history-row"], [1, "consent-history-empty"], [1, "consent-history-note"], [1, "consent-history-purpose"], [1, "consent-history-source"], ["title", "Set Primary", 1, "btn-ghost", 3, "click"], [1, "fa-regular", "fa-star"], ["title", "Open", 1, "btn-ghost", 3, "click"], [1, "fa-solid", "fa-external-link"], ["title", "Copy", 1, "btn-ghost", 3, "click"], [1, "fa-solid", "fa-copy"], ["title", "Edit", 1, "btn-ghost", 3, "click"], [1, "fa-solid", "fa-pen"], ["title", "Remove", 1, "btn-ghost", "danger", 3, "click"], [1, "fa-solid", "fa-trash"], ["type", "text", "placeholder", "e.g., Direct Line", 3, "ngModelChange", "ngModel"], ["type", "checkbox", "id", "primary-add", 3, "ngModelChange", "ngModel"], ["for", "primary-add"], [1, "btn", "btn-outline", "full-width", 3, "click"], [1, "fa-solid", "fa-plus"]], template: function ContactMethodListComponent_Template(rf, ctx) { if (rf & 1) {
830
1340
  i0.ɵɵelementStart(0, "div", 0)(1, "span", 1);
831
1341
  i0.ɵɵelement(2, "i", 2);
832
1342
  i0.ɵɵtext(3, " Contact Methods ");
@@ -838,13 +1348,15 @@ export class ContactMethodListComponent {
838
1348
  i0.ɵɵconditional(!ctx.Loading && ctx.ContactMethods.length > 0 ? 4 : -1);
839
1349
  i0.ɵɵadvance();
840
1350
  i0.ɵɵconditional(ctx.Loading ? 5 : 6);
841
- } }, dependencies: [CommonModule, i1.NgClass, FormsModule, i2.NgSelectOption, i2.ɵNgSelectMultipleOption, i2.DefaultValueAccessor, i2.CheckboxControlValueAccessor, i2.SelectControlValueAccessor, i2.NgControlStatus, i2.NgModel], styles: ["\n\n\n\n\n\n[_nghost-%COMP%] {\n display: block;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;\n color: var(--mj-text-primary);\n}\n\n.section-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 16px;\n}\n\n.section-label[_ngcontent-%COMP%] {\n font-size: 15px;\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.section-label[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.count[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\n font-weight: 400;\n}\n\n\n\n.cm-flat-list[_ngcontent-%COMP%] {\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n overflow: hidden;\n}\n\n\n\n.cm-flat-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n padding: 10px 16px;\n border-bottom: 1px solid var(--mj-bg-surface-sunken);\n gap: 12px;\n transition: background 0.1s;\n}\n\n.cm-flat-row[_ngcontent-%COMP%]:last-child {\n border-bottom: none;\n}\n\n.cm-flat-row[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.cm-flat-row.primary[_ngcontent-%COMP%] {\n background: var(--mj-status-success-bg);\n}\n\n\n\n.cm-flat-icon[_ngcontent-%COMP%] {\n width: 36px;\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 8px;\n font-size: 15px;\n flex-shrink: 0;\n}\n\n.cm-flat-icon.icon-email[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary-hover);\n}\n\n.cm-flat-icon.icon-phone[_ngcontent-%COMP%] {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n}\n\n.cm-flat-icon.icon-mobile[_ngcontent-%COMP%] {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n}\n\n.cm-flat-icon.icon-linkedin[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.cm-flat-icon.icon-twitter[_ngcontent-%COMP%] {\n background: var(--mj-border-default);\n color: var(--mj-text-primary);\n}\n\n.cm-flat-icon.icon-web[_ngcontent-%COMP%] {\n background: var(--mj-status-warning-bg);\n color: var(--mj-status-warning-text);\n}\n\n.cm-flat-icon.icon-fax[_ngcontent-%COMP%] {\n background: var(--mj-status-info-bg);\n color: var(--mj-status-info-text);\n}\n\n.cm-flat-icon.icon-default[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n}\n\n\n\n.cm-flat-content[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.cm-flat-value[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--mj-text-primary);\n cursor: pointer;\n}\n\n.cm-flat-value[_ngcontent-%COMP%]:hover {\n color: var(--mj-brand-primary);\n}\n\n.cm-flat-meta[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\n margin-top: 1px;\n}\n\n\n\n.cm-flat-badges[_ngcontent-%COMP%] {\n display: flex;\n gap: 6px;\n flex-shrink: 0;\n}\n\n.badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 3px 10px;\n border-radius: 12px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n}\n\n.badge-primary[_ngcontent-%COMP%] {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n}\n\n\n\n.cm-flat-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 2px;\n flex-shrink: 0;\n opacity: 0;\n transition: opacity 0.15s;\n}\n\n.cm-flat-row[_ngcontent-%COMP%]:hover .cm-flat-actions[_ngcontent-%COMP%] {\n opacity: 1;\n}\n\n\n\n.btn-ghost[_ngcontent-%COMP%] {\n background: transparent;\n color: var(--mj-text-disabled);\n padding: 6px 8px;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n font-size: 13px;\n transition: all 0.15s ease;\n}\n\n.btn-ghost[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface-card);\n}\n\n.btn-ghost.danger[_ngcontent-%COMP%]:hover {\n color: var(--mj-status-error-text);\n background: var(--mj-status-error-bg);\n}\n\n\n\n.cm-flat-add-form[_ngcontent-%COMP%] {\n padding: 14px 16px;\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n border-top: 2px solid var(--mj-brand-primary);\n display: flex;\n gap: 10px;\n align-items: flex-end;\n flex-wrap: wrap;\n}\n\n\n\n.cm-flat-edit-row[_ngcontent-%COMP%] {\n padding: 14px 16px;\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n border-bottom: 2px solid var(--mj-brand-primary);\n}\n\n.cm-flat-edit-row[_ngcontent-%COMP%] .form-row[_ngcontent-%COMP%] {\n display: flex;\n gap: 10px;\n align-items: flex-end;\n}\n\n\n\n.btn[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 8px 16px;\n border: none;\n border-radius: 6px;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n}\n\n.btn-primary[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.btn-primary[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary-hover);\n}\n\n.btn-cancel[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n border: 1px solid var(--mj-border-default);\n}\n\n.btn-cancel[_ngcontent-%COMP%]:hover {\n background: var(--mj-border-subtle);\n}\n\n.btn-sm[_ngcontent-%COMP%] {\n padding: 7px 14px;\n}\n\n\n\n.form-field[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n}\n\n.form-field.flex-1[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n.form-field[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n display: block;\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n margin-bottom: 4px;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n}\n\n.form-field[_ngcontent-%COMP%] input[_ngcontent-%COMP%], \n.form-field[_ngcontent-%COMP%] select[_ngcontent-%COMP%] {\n width: 100%;\n padding: 8px 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n font-size: 14px;\n font-family: inherit;\n background: var(--mj-bg-surface);\n}\n\n.form-field[_ngcontent-%COMP%] input[_ngcontent-%COMP%]:focus, \n.form-field[_ngcontent-%COMP%] select[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n\n.form-field.type-field[_ngcontent-%COMP%] {\n max-width: 160px;\n}\n\n.form-field.label-field[_ngcontent-%COMP%] {\n max-width: 140px;\n}\n\n.checkbox-field[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding-top: 20px;\n}\n\n.checkbox-field[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%] {\n width: 16px;\n height: 16px;\n cursor: pointer;\n}\n\n.checkbox-field[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-text-secondary);\n cursor: pointer;\n}\n\n.form-actions[_ngcontent-%COMP%] {\n padding-top: 18px;\n display: flex;\n gap: 6px;\n}\n\n\n\n.copy-toast[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 4px 10px;\n background: var(--mj-text-primary);\n color: var(--mj-brand-on-primary);\n border-radius: 4px;\n font-size: 11px;\n margin-left: 8px;\n animation: _ngcontent-%COMP%_fadeInOut 1.5s ease-in-out;\n}\n\n@keyframes _ngcontent-%COMP%_fadeInOut {\n 0% { opacity: 0; }\n 15% { opacity: 1; }\n 70% { opacity: 1; }\n 100% { opacity: 0; }\n}\n\n\n\n.empty-state[_ngcontent-%COMP%] {\n text-align: center;\n padding: 32px 16px;\n color: var(--mj-text-muted);\n font-size: 14px;\n}\n\n.empty-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 24px;\n color: var(--mj-border-strong);\n margin-bottom: 8px;\n display: block;\n}\n\n\n\n.loading-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 24px;\n color: var(--mj-text-muted);\n font-size: 13px;\n gap: 8px;\n}\n\n.loading-row[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n animation: _ngcontent-%COMP%_spin 1s linear infinite;\n}\n\n@keyframes _ngcontent-%COMP%_spin {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n}\n\n\n\n.cm-flat-footer[_ngcontent-%COMP%] {\n padding: 12px 16px;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n}\n\n.btn-outline[_ngcontent-%COMP%] {\n background: transparent;\n border: 1px dashed var(--mj-border-strong);\n color: var(--mj-text-secondary);\n}\n\n.btn-outline[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 6%, var(--mj-bg-surface));\n}\n\n.btn-outline.full-width[_ngcontent-%COMP%] {\n width: 100%;\n justify-content: center;\n}"] });
1351
+ } }, dependencies: [CommonModule, i1.NgClass, FormsModule, i2.NgSelectOption, i2.ɵNgSelectMultipleOption, i2.DefaultValueAccessor, i2.CheckboxControlValueAccessor, i2.SelectControlValueAccessor, i2.NgControlStatus, i2.NgModel, SharedGenericModule, i3.LoadingComponent, i1.DatePipe], styles: ["\n\n\n\n\n\n[_nghost-%COMP%] {\n display: block;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;\n color: var(--mj-text-primary);\n}\n\n.section-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 16px;\n}\n\n.section-label[_ngcontent-%COMP%] {\n font-size: 15px;\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.section-label[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.count[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\n font-weight: 400;\n}\n\n\n\n.cm-flat-list[_ngcontent-%COMP%] {\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n overflow: hidden;\n}\n\n\n\n.cm-flat-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n padding: 10px 16px;\n border-bottom: 1px solid var(--mj-bg-surface-sunken);\n gap: 12px;\n transition: background 0.1s;\n}\n\n.cm-flat-row[_ngcontent-%COMP%]:last-child {\n border-bottom: none;\n}\n\n.cm-flat-row[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.cm-flat-row.primary[_ngcontent-%COMP%] {\n background: var(--mj-status-success-bg);\n}\n\n\n\n.cm-flat-icon[_ngcontent-%COMP%] {\n width: 36px;\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 8px;\n font-size: 15px;\n flex-shrink: 0;\n}\n\n.cm-flat-icon.icon-email[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary-hover);\n}\n\n.cm-flat-icon.icon-phone[_ngcontent-%COMP%] {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n}\n\n.cm-flat-icon.icon-mobile[_ngcontent-%COMP%] {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n}\n\n.cm-flat-icon.icon-linkedin[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.cm-flat-icon.icon-twitter[_ngcontent-%COMP%] {\n background: var(--mj-border-default);\n color: var(--mj-text-primary);\n}\n\n.cm-flat-icon.icon-web[_ngcontent-%COMP%] {\n background: var(--mj-status-warning-bg);\n color: var(--mj-status-warning-text);\n}\n\n.cm-flat-icon.icon-fax[_ngcontent-%COMP%] {\n background: var(--mj-status-info-bg);\n color: var(--mj-status-info-text);\n}\n\n.cm-flat-icon.icon-default[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n}\n\n\n\n.cm-flat-content[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.cm-flat-value[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--mj-text-primary);\n cursor: pointer;\n}\n\n.cm-flat-value[_ngcontent-%COMP%]:hover {\n color: var(--mj-brand-primary);\n}\n\n.cm-flat-meta[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\n margin-top: 1px;\n}\n\n\n\n.cm-flat-badges[_ngcontent-%COMP%] {\n display: flex;\n gap: 6px;\n flex-shrink: 0;\n}\n\n.badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 3px 10px;\n border-radius: 12px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n}\n\n.badge-primary[_ngcontent-%COMP%] {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n}\n\n\n\n.cm-flat-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 2px;\n flex-shrink: 0;\n opacity: 0;\n transition: opacity 0.15s;\n}\n\n.cm-flat-row[_ngcontent-%COMP%]:hover .cm-flat-actions[_ngcontent-%COMP%] {\n opacity: 1;\n}\n\n\n\n.btn-ghost[_ngcontent-%COMP%] {\n background: transparent;\n color: var(--mj-text-disabled);\n padding: 6px 8px;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n font-size: 13px;\n transition: all 0.15s ease;\n}\n\n.btn-ghost[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface-card);\n}\n\n.btn-ghost.danger[_ngcontent-%COMP%]:hover {\n color: var(--mj-status-error-text);\n background: var(--mj-status-error-bg);\n}\n\n\n\n.cm-flat-add-form[_ngcontent-%COMP%] {\n padding: 14px 16px;\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n border-top: 2px solid var(--mj-brand-primary);\n display: flex;\n gap: 10px;\n align-items: flex-end;\n flex-wrap: wrap;\n}\n\n\n\n.cm-flat-edit-row[_ngcontent-%COMP%] {\n padding: 14px 16px;\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n border-bottom: 2px solid var(--mj-brand-primary);\n}\n\n.cm-flat-edit-row[_ngcontent-%COMP%] .form-row[_ngcontent-%COMP%] {\n display: flex;\n gap: 10px;\n align-items: flex-end;\n}\n\n\n\n.btn[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 8px 16px;\n border: none;\n border-radius: 6px;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n}\n\n.btn-primary[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.btn-primary[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary-hover);\n}\n\n.btn-cancel[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n border: 1px solid var(--mj-border-default);\n}\n\n.btn-cancel[_ngcontent-%COMP%]:hover {\n background: var(--mj-border-subtle);\n}\n\n.btn-sm[_ngcontent-%COMP%] {\n padding: 7px 14px;\n}\n\n\n\n.form-field[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n}\n\n.form-field.flex-1[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n.form-field[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n display: block;\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n margin-bottom: 4px;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n}\n\n.form-field[_ngcontent-%COMP%] input[_ngcontent-%COMP%], \n.form-field[_ngcontent-%COMP%] select[_ngcontent-%COMP%] {\n width: 100%;\n padding: 8px 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n font-size: 14px;\n font-family: inherit;\n background: var(--mj-bg-surface);\n}\n\n.form-field[_ngcontent-%COMP%] input[_ngcontent-%COMP%]:focus, \n.form-field[_ngcontent-%COMP%] select[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n\n.form-field.type-field[_ngcontent-%COMP%] {\n max-width: 160px;\n}\n\n.form-field.label-field[_ngcontent-%COMP%] {\n max-width: 140px;\n}\n\n.checkbox-field[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding-top: 20px;\n}\n\n.checkbox-field[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%] {\n width: 16px;\n height: 16px;\n cursor: pointer;\n}\n\n.checkbox-field[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-text-secondary);\n cursor: pointer;\n}\n\n.form-actions[_ngcontent-%COMP%] {\n padding-top: 18px;\n display: flex;\n gap: 6px;\n}\n\n\n\n.copy-toast[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 4px 10px;\n background: var(--mj-text-primary);\n color: var(--mj-brand-on-primary);\n border-radius: 4px;\n font-size: 11px;\n margin-left: 8px;\n animation: _ngcontent-%COMP%_fadeInOut 1.5s ease-in-out;\n}\n\n@keyframes _ngcontent-%COMP%_fadeInOut {\n 0% { opacity: 0; }\n 15% { opacity: 1; }\n 70% { opacity: 1; }\n 100% { opacity: 0; }\n}\n\n\n\n.empty-state[_ngcontent-%COMP%] {\n text-align: center;\n padding: 32px 16px;\n color: var(--mj-text-muted);\n font-size: 14px;\n}\n\n.empty-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 24px;\n color: var(--mj-border-strong);\n margin-bottom: 8px;\n display: block;\n}\n\n\n\n.loading-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 24px;\n color: var(--mj-text-muted);\n font-size: 13px;\n gap: 8px;\n}\n\n.loading-row[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n animation: _ngcontent-%COMP%_spin 1s linear infinite;\n}\n\n@keyframes _ngcontent-%COMP%_spin {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n}\n\n\n\n.cm-flat-footer[_ngcontent-%COMP%] {\n padding: 12px 16px;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n}\n\n.btn-outline[_ngcontent-%COMP%] {\n background: transparent;\n border: 1px dashed var(--mj-border-strong);\n color: var(--mj-text-secondary);\n}\n\n.btn-outline[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 6%, var(--mj-bg-surface));\n}\n\n.btn-outline.full-width[_ngcontent-%COMP%] {\n width: 100%;\n justify-content: center;\n}\n\n\n\n.badge-consent[_ngcontent-%COMP%] {\n cursor: default;\n text-transform: none;\n letter-spacing: 0;\n}\n\n.badge-consent.consent-in[_ngcontent-%COMP%] {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n}\n\n.badge-consent.consent-out[_ngcontent-%COMP%] {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n}\n\n.badge-consent.consent-unknown[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n border: 1px solid var(--mj-border-subtle);\n}\n\n\n\n.cm-flat-badges[_ngcontent-%COMP%] {\n position: relative;\n}\n\n.consent-history[_ngcontent-%COMP%] {\n position: absolute;\n top: 100%;\n right: 0;\n z-index: 20;\n min-width: 300px;\n padding: 10px 12px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n box-shadow: 0 6px 18px color-mix(in srgb, var(--mj-text-primary) 14%, transparent);\n font-size: 12px;\n color: var(--mj-text-primary);\n}\n\n.consent-history-title[_ngcontent-%COMP%] {\n font-weight: 600;\n margin-bottom: 6px;\n color: var(--mj-text-primary);\n}\n\n.consent-history-row[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 90px 90px 1fr;\n gap: 8px;\n padding: 3px 0;\n border-top: 1px solid var(--mj-border-subtle);\n}\n\n.consent-history-row[_ngcontent-%COMP%]:first-of-type {\n border-top: none;\n}\n\n.consent-history-row.current[_ngcontent-%COMP%] {\n font-weight: 600;\n}\n\n.consent-history-source[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n}\n\n.consent-history-empty[_ngcontent-%COMP%], \n.consent-history-note[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-size: 11px;\n margin-top: 6px;\n}\n\n\n\n.form-field.consent-field[_ngcontent-%COMP%] select[_ngcontent-%COMP%] {\n min-width: 130px;\n}\n\n\n\n.consent-badges[_ngcontent-%COMP%] {\n display: inline-flex;\n flex-wrap: wrap;\n gap: 6px;\n justify-content: flex-end;\n}\n\n.badge-consent[_ngcontent-%COMP%] .consent-purpose[_ngcontent-%COMP%] {\n font-weight: 500;\n opacity: 0.8;\n}\n\n.badge-consent[_ngcontent-%COMP%] .consent-purpose[_ngcontent-%COMP%]::after {\n content: '\u00B7';\n margin: 0 2px 0 4px;\n}\n\n.consent-history-row[_ngcontent-%COMP%] {\n grid-template-columns: 90px 1fr 90px 1fr;\n}\n\n.consent-history-purpose[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n}\n\n\n\n.cm-flat-add-form[_ngcontent-%COMP%], \n.cm-flat-edit-row[_ngcontent-%COMP%] .form-row[_ngcontent-%COMP%] {\n flex-wrap: wrap;\n}\n\n.form-row.consent-row[_ngcontent-%COMP%] {\n flex-basis: 100%;\n display: flex;\n flex-wrap: wrap;\n gap: 12px;\n margin-top: 8px;\n padding-top: 8px;\n border-top: 1px solid var(--mj-border-subtle);\n}"] });
842
1352
  }
843
1353
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ContactMethodListComponent, [{
844
1354
  type: Component,
845
- args: [{ standalone: true, imports: [CommonModule, FormsModule], selector: 'bizapps-contact-method-list', template: "<!-- ContactMethodList - Flat List with Icons Design (Option B) -->\n\n<div class=\"section-header\">\n <span class=\"section-label\">\n <i class=\"fa-solid fa-address-card\"></i>\n Contact Methods\n @if (!Loading && ContactMethods.length > 0) {\n <span class=\"count\">({{ ContactMethods.length }})</span>\n }\n </span>\n</div>\n\n@if (Loading) {\n <div class=\"cm-flat-list\">\n <div class=\"loading-row\">\n <i class=\"fa-solid fa-spinner\"></i> Loading contacts...\n </div>\n </div>\n} @else {\n <div class=\"cm-flat-list\">\n @if (ContactMethods.length === 0 && !ShowAddForm) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-address-card\"></i>\n No contact methods yet\n </div>\n }\n\n @for (cm of ContactMethods; track cm.ID) {\n <!-- Edit mode for this row -->\n @if (EditingId === cm.ID) {\n <div class=\"cm-flat-edit-row\">\n <div class=\"form-row\">\n <div class=\"form-field type-field\">\n <label>Type</label>\n <select [(ngModel)]=\"EditForm.TypeID\">\n @for (t of ContactTypes; track t.ID) {\n <option [value]=\"t.ID\">{{ t.Name }}</option>\n }\n </select>\n </div>\n <div class=\"form-field flex-1\">\n <label>Value</label>\n <input type=\"text\" [(ngModel)]=\"EditForm.Value\" [placeholder]=\"getPlaceholder(EditForm.TypeID)\">\n </div>\n <div class=\"form-field label-field\">\n <label>Label</label>\n <input type=\"text\" [(ngModel)]=\"EditForm.Label\" placeholder=\"e.g., Work\">\n </div>\n <div class=\"checkbox-field\">\n <input type=\"checkbox\" [id]=\"'primary-edit-' + cm.ID\" [(ngModel)]=\"EditForm.IsPrimary\">\n <label [for]=\"'primary-edit-' + cm.ID\">Primary</label>\n </div>\n <div class=\"form-actions\">\n <button class=\"btn btn-primary btn-sm\" (click)=\"onSaveEdit()\" [disabled]=\"Saving\">\n @if (Saving) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n }\n Save\n </button>\n <button class=\"btn btn-cancel btn-sm\" (click)=\"onCancelEdit()\">Cancel</button>\n </div>\n </div>\n </div>\n } @else {\n <!-- Display row -->\n <div class=\"cm-flat-row\" [class.primary]=\"cm.IsPrimary\">\n <div class=\"cm-flat-icon\" [ngClass]=\"getIconColorClass(cm.ContactTypeID)\">\n <i [class]=\"getContactTypeIcon(cm.ContactTypeID)\"></i>\n </div>\n <div class=\"cm-flat-content\">\n <div class=\"cm-flat-value\" (click)=\"onCopyValue(cm.Value)\">{{ cm.Value }}</div>\n <div class=\"cm-flat-meta\">{{ getContactMeta(cm) }}</div>\n </div>\n <div class=\"cm-flat-badges\">\n @if (cm.IsPrimary) {\n <span class=\"badge badge-primary\"><i class=\"fa-solid fa-star\"></i></span>\n }\n </div>\n <div class=\"cm-flat-actions\">\n @if (EditMode && !cm.IsPrimary) {\n <button class=\"btn-ghost\" title=\"Set Primary\" (click)=\"onSetPrimary(cm)\">\n <i class=\"fa-regular fa-star\"></i>\n </button>\n }\n @if (isLinkType(cm.ContactTypeID)) {\n <button class=\"btn-ghost\" title=\"Open\" (click)=\"onOpenLink(cm.Value)\">\n <i class=\"fa-solid fa-external-link\"></i>\n </button>\n } @else {\n <button class=\"btn-ghost\" title=\"Copy\" (click)=\"onCopyValue(cm.Value)\">\n <i class=\"fa-solid fa-copy\"></i>\n </button>\n }\n @if (EditMode) {\n <button class=\"btn-ghost\" title=\"Edit\" (click)=\"onEdit(cm)\">\n <i class=\"fa-solid fa-pen\"></i>\n </button>\n <button class=\"btn-ghost danger\" title=\"Remove\" (click)=\"onDelete(cm)\">\n <i class=\"fa-solid fa-trash\"></i>\n </button>\n }\n </div>\n </div>\n }\n }\n\n <!-- Add form -->\n @if (ShowAddForm) {\n <div class=\"cm-flat-add-form\">\n <div class=\"form-field type-field\">\n <label>Type</label>\n <select [(ngModel)]=\"AddForm.TypeID\">\n @for (t of ContactTypes; track t.ID) {\n <option [value]=\"t.ID\">{{ t.Name }}</option>\n }\n </select>\n </div>\n <div class=\"form-field flex-1\">\n <label>Value</label>\n <input type=\"text\" [(ngModel)]=\"AddForm.Value\" [placeholder]=\"getPlaceholder(AddForm.TypeID)\">\n </div>\n <div class=\"form-field label-field\">\n <label>Label</label>\n <input type=\"text\" [(ngModel)]=\"AddForm.Label\" placeholder=\"e.g., Direct Line\">\n </div>\n <div class=\"checkbox-field\">\n <input type=\"checkbox\" id=\"primary-add\" [(ngModel)]=\"AddForm.IsPrimary\">\n <label for=\"primary-add\">Primary</label>\n </div>\n <div class=\"form-actions\">\n <button class=\"btn btn-primary btn-sm\" (click)=\"onSaveAdd()\" [disabled]=\"Saving\">\n @if (Saving) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n }\n Add\n </button>\n <button class=\"btn btn-cancel btn-sm\" (click)=\"onCancelAdd()\">Cancel</button>\n </div>\n </div>\n }\n\n <!-- Add button footer -->\n @if (!ShowAddForm && EditingId === null && EditMode) {\n <div class=\"cm-flat-footer\">\n <button class=\"btn btn-outline full-width\" (click)=\"onShowAdd()\">\n <i class=\"fa-solid fa-plus\"></i>\n Add Contact\n </button>\n </div>\n }\n </div>\n}\n", styles: ["/* ============================================\n ContactMethodList - Flat List with Icons Design\n Pixel-perfect match to Option B mockup\n ============================================ */\n\n:host {\n display: block;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;\n color: var(--mj-text-primary);\n}\n\n.section-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 16px;\n}\n\n.section-label {\n font-size: 15px;\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.section-label i {\n color: var(--mj-brand-primary);\n}\n\n.count {\n font-size: 12px;\n color: var(--mj-text-muted);\n font-weight: 400;\n}\n\n/* Flat list container */\n.cm-flat-list {\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n overflow: hidden;\n}\n\n/* Row */\n.cm-flat-row {\n display: flex;\n align-items: center;\n padding: 10px 16px;\n border-bottom: 1px solid var(--mj-bg-surface-sunken);\n gap: 12px;\n transition: background 0.1s;\n}\n\n.cm-flat-row:last-child {\n border-bottom: none;\n}\n\n.cm-flat-row:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.cm-flat-row.primary {\n background: var(--mj-status-success-bg);\n}\n\n/* Icon */\n.cm-flat-icon {\n width: 36px;\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 8px;\n font-size: 15px;\n flex-shrink: 0;\n}\n\n.cm-flat-icon.icon-email {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary-hover);\n}\n\n.cm-flat-icon.icon-phone {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n}\n\n.cm-flat-icon.icon-mobile {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n}\n\n.cm-flat-icon.icon-linkedin {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.cm-flat-icon.icon-twitter {\n background: var(--mj-border-default);\n color: var(--mj-text-primary);\n}\n\n.cm-flat-icon.icon-web {\n background: var(--mj-status-warning-bg);\n color: var(--mj-status-warning-text);\n}\n\n.cm-flat-icon.icon-fax {\n background: var(--mj-status-info-bg);\n color: var(--mj-status-info-text);\n}\n\n.cm-flat-icon.icon-default {\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n}\n\n/* Content */\n.cm-flat-content {\n flex: 1;\n min-width: 0;\n}\n\n.cm-flat-value {\n font-size: 14px;\n color: var(--mj-text-primary);\n cursor: pointer;\n}\n\n.cm-flat-value:hover {\n color: var(--mj-brand-primary);\n}\n\n.cm-flat-meta {\n font-size: 12px;\n color: var(--mj-text-muted);\n margin-top: 1px;\n}\n\n/* Badges */\n.cm-flat-badges {\n display: flex;\n gap: 6px;\n flex-shrink: 0;\n}\n\n.badge {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 3px 10px;\n border-radius: 12px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n}\n\n.badge-primary {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n}\n\n/* Actions */\n.cm-flat-actions {\n display: flex;\n gap: 2px;\n flex-shrink: 0;\n opacity: 0;\n transition: opacity 0.15s;\n}\n\n.cm-flat-row:hover .cm-flat-actions {\n opacity: 1;\n}\n\n/* Ghost buttons */\n.btn-ghost {\n background: transparent;\n color: var(--mj-text-disabled);\n padding: 6px 8px;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n font-size: 13px;\n transition: all 0.15s ease;\n}\n\n.btn-ghost:hover {\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface-card);\n}\n\n.btn-ghost.danger:hover {\n color: var(--mj-status-error-text);\n background: var(--mj-status-error-bg);\n}\n\n/* Add form */\n.cm-flat-add-form {\n padding: 14px 16px;\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n border-top: 2px solid var(--mj-brand-primary);\n display: flex;\n gap: 10px;\n align-items: flex-end;\n flex-wrap: wrap;\n}\n\n/* Edit inline row */\n.cm-flat-edit-row {\n padding: 14px 16px;\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n border-bottom: 2px solid var(--mj-brand-primary);\n}\n\n.cm-flat-edit-row .form-row {\n display: flex;\n gap: 10px;\n align-items: flex-end;\n}\n\n/* Buttons */\n.btn {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 8px 16px;\n border: none;\n border-radius: 6px;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n}\n\n.btn-primary {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.btn-primary:hover {\n background: var(--mj-brand-primary-hover);\n}\n\n.btn-cancel {\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n border: 1px solid var(--mj-border-default);\n}\n\n.btn-cancel:hover {\n background: var(--mj-border-subtle);\n}\n\n.btn-sm {\n padding: 7px 14px;\n}\n\n/* Form fields */\n.form-field {\n display: flex;\n flex-direction: column;\n}\n\n.form-field.flex-1 {\n flex: 1;\n}\n\n.form-field label {\n display: block;\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n margin-bottom: 4px;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n}\n\n.form-field input,\n.form-field select {\n width: 100%;\n padding: 8px 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n font-size: 14px;\n font-family: inherit;\n background: var(--mj-bg-surface);\n}\n\n.form-field input:focus,\n.form-field select:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n\n.form-field.type-field {\n max-width: 160px;\n}\n\n.form-field.label-field {\n max-width: 140px;\n}\n\n.checkbox-field {\n display: flex;\n align-items: center;\n gap: 8px;\n padding-top: 20px;\n}\n\n.checkbox-field input[type=\"checkbox\"] {\n width: 16px;\n height: 16px;\n cursor: pointer;\n}\n\n.checkbox-field label {\n font-size: 13px;\n color: var(--mj-text-secondary);\n cursor: pointer;\n}\n\n.form-actions {\n padding-top: 18px;\n display: flex;\n gap: 6px;\n}\n\n/* Copy toast */\n.copy-toast {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 4px 10px;\n background: var(--mj-text-primary);\n color: var(--mj-brand-on-primary);\n border-radius: 4px;\n font-size: 11px;\n margin-left: 8px;\n animation: fadeInOut 1.5s ease-in-out;\n}\n\n@keyframes fadeInOut {\n 0% { opacity: 0; }\n 15% { opacity: 1; }\n 70% { opacity: 1; }\n 100% { opacity: 0; }\n}\n\n/* Empty state */\n.empty-state {\n text-align: center;\n padding: 32px 16px;\n color: var(--mj-text-muted);\n font-size: 14px;\n}\n\n.empty-state i {\n font-size: 24px;\n color: var(--mj-border-strong);\n margin-bottom: 8px;\n display: block;\n}\n\n/* Loading */\n.loading-row {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 24px;\n color: var(--mj-text-muted);\n font-size: 13px;\n gap: 8px;\n}\n\n.loading-row i {\n animation: spin 1s linear infinite;\n}\n\n@keyframes spin {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n}\n\n/* Footer add button area */\n.cm-flat-footer {\n padding: 12px 16px;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n}\n\n.btn-outline {\n background: transparent;\n border: 1px dashed var(--mj-border-strong);\n color: var(--mj-text-secondary);\n}\n\n.btn-outline:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 6%, var(--mj-bg-surface));\n}\n\n.btn-outline.full-width {\n width: 100%;\n justify-content: center;\n}\n"] }]
1355
+ args: [{ standalone: true, imports: [CommonModule, FormsModule, SharedGenericModule], selector: 'bizapps-contact-method-list', template: "<!-- ContactMethodList - Flat List with Icons Design (Option B) -->\n\n<div class=\"section-header\">\n <span class=\"section-label\">\n <i class=\"fa-solid fa-address-card\"></i>\n Contact Methods\n @if (!Loading && ContactMethods.length > 0) {\n <span class=\"count\">({{ ContactMethods.length }})</span>\n }\n </span>\n</div>\n\n@if (Loading) {\n <div class=\"cm-flat-list\">\n <div class=\"loading-row\">\n <i class=\"fa-solid fa-spinner\"></i> Loading contacts...\n </div>\n </div>\n} @else {\n <div class=\"cm-flat-list\">\n @if (ContactMethods.length === 0 && !ShowAddForm) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-address-card\"></i>\n No contact methods yet\n </div>\n }\n\n @for (cm of ContactMethods; track cm.ID) {\n <!-- Edit mode for this row -->\n @if (EditingId === cm.ID) {\n <div class=\"cm-flat-edit-row\">\n <div class=\"form-row\">\n <div class=\"form-field type-field\">\n <label>Type</label>\n <select [(ngModel)]=\"EditForm.TypeID\">\n @for (t of ContactTypes; track t.ID) {\n <option [value]=\"t.ID\">{{ t.Name }}</option>\n }\n </select>\n </div>\n <div class=\"form-field flex-1\">\n <label>Value</label>\n <input type=\"text\" [(ngModel)]=\"EditForm.Value\" [placeholder]=\"getPlaceholder(EditForm.TypeID)\">\n </div>\n <div class=\"form-field label-field\">\n <label>Label</label>\n <input type=\"text\" [(ngModel)]=\"EditForm.Label\" placeholder=\"e.g., Work\">\n </div>\n <div class=\"checkbox-field\">\n <input type=\"checkbox\" [id]=\"'primary-edit-' + cm.ID\" [(ngModel)]=\"EditForm.IsPrimary\">\n <label [for]=\"'primary-edit-' + cm.ID\">Primary</label>\n </div>\n <div class=\"form-actions\">\n <button class=\"btn btn-primary btn-sm\" (click)=\"onSaveEdit()\" [disabled]=\"Saving\">\n @if (Saving) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n }\n Save\n </button>\n <button class=\"btn btn-cancel btn-sm\" (click)=\"onCancelEdit()\">Cancel</button>\n </div>\n </div>\n @if (isConsentType(EditForm.TypeID)) {\n <div class=\"form-row consent-row\">\n <div class=\"form-field consent-field\">\n <label>General</label>\n <select [(ngModel)]=\"EditForm.Consents[GeneralKey]\">\n @for (s of ConsentStatuses; track s) {\n <option [value]=\"s\">{{ s }}</option>\n }\n </select>\n </div>\n @for (p of ConsentPurposes; track p.ID) {\n <div class=\"form-field consent-field\">\n <label>{{ p.Name }}</label>\n <select [(ngModel)]=\"EditForm.Consents[p.ID]\">\n @for (s of ConsentStatuses; track s) {\n <option [value]=\"s\">{{ s }}</option>\n }\n </select>\n </div>\n }\n </div>\n }\n </div>\n } @else {\n <!-- Display row -->\n <div class=\"cm-flat-row\" [class.primary]=\"cm.IsPrimary\">\n <div class=\"cm-flat-icon\" [ngClass]=\"getIconColorClass(cm.ContactTypeID)\">\n <i [class]=\"getContactTypeIcon(cm.ContactTypeID)\"></i>\n </div>\n <div class=\"cm-flat-content\">\n <div class=\"cm-flat-value\" (click)=\"onCopyValue(cm.Value)\">{{ cm.Value }}</div>\n <div class=\"cm-flat-meta\">{{ getContactMeta(cm) }}</div>\n </div>\n <div class=\"cm-flat-badges\">\n @if (cm.IsPrimary) {\n <span class=\"badge badge-primary\"><i class=\"fa-solid fa-star\"></i></span>\n }\n @if (isConsentType(cm.ContactTypeID)) {\n <span class=\"consent-badges\" (mouseenter)=\"onShowConsentHistory(cm)\" (mouseleave)=\"onHideConsentHistory()\">\n @for (c of getConsents(cm); track c.ID) {\n <span class=\"badge badge-consent\" [ngClass]=\"getConsentBadgeClass(c.ConsentStatus)\">\n <i [class]=\"getConsentIcon(c.ConsentStatus)\"></i>\n <span class=\"consent-purpose\">{{ getConsentBadgeText(c) }}</span>\n {{ c.ConsentStatus }}\n </span>\n } @empty {\n <span class=\"badge badge-consent consent-unknown\">\n <i class=\"fa-regular fa-circle-question\"></i>\n Not Specified\n </span>\n }\n </span>\n @if (ConsentHistoryFor === cm.ID) {\n <div class=\"consent-history\" (mouseenter)=\"onShowConsentHistory(cm)\" (mouseleave)=\"onHideConsentHistory()\">\n <div class=\"consent-history-title\">Consent history \u00B7 {{ cm.Value }}</div>\n @if (ConsentHistoryLoading) {\n <mj-loading Text=\"Loading history...\" Size=\"small\"></mj-loading>\n } @else {\n @for (h of ConsentHistory; track h.ID) {\n <div class=\"consent-history-row\">\n <span>{{ h.ConsentStatusAt | date:'mediumDate' }}</span>\n <span class=\"consent-history-purpose\">{{ h.Purpose }}@if (h.RequestingOrganization) { \u00B7 {{ h.RequestingOrganization }}}</span>\n <span>{{ h.NewConsentStatus }}</span>\n <span class=\"consent-history-source\">{{ h.ConsentSource }}@if (h.ConsentDetails) { \u00B7 {{ h.ConsentDetails }}}</span>\n </div>\n } @empty {\n <div class=\"consent-history-empty\">No consent recorded yet</div>\n }\n <div class=\"consent-history-note\">Newest first; the top row for each purpose is its current status</div>\n }\n </div>\n }\n }\n </div>\n <div class=\"cm-flat-actions\">\n @if (EditMode && !cm.IsPrimary) {\n <button class=\"btn-ghost\" title=\"Set Primary\" (click)=\"onSetPrimary(cm)\">\n <i class=\"fa-regular fa-star\"></i>\n </button>\n }\n @if (isLinkType(cm.ContactTypeID)) {\n <button class=\"btn-ghost\" title=\"Open\" (click)=\"onOpenLink(cm.Value)\">\n <i class=\"fa-solid fa-external-link\"></i>\n </button>\n } @else {\n <button class=\"btn-ghost\" title=\"Copy\" (click)=\"onCopyValue(cm.Value)\">\n <i class=\"fa-solid fa-copy\"></i>\n </button>\n }\n @if (EditMode) {\n <button class=\"btn-ghost\" title=\"Edit\" (click)=\"onEdit(cm)\">\n <i class=\"fa-solid fa-pen\"></i>\n </button>\n <button class=\"btn-ghost danger\" title=\"Remove\" (click)=\"onDelete(cm)\">\n <i class=\"fa-solid fa-trash\"></i>\n </button>\n }\n </div>\n </div>\n }\n }\n\n <!-- Add form -->\n @if (ShowAddForm) {\n <div class=\"cm-flat-add-form\">\n <div class=\"form-field type-field\">\n <label>Type</label>\n <select [(ngModel)]=\"AddForm.TypeID\">\n @for (t of ContactTypes; track t.ID) {\n <option [value]=\"t.ID\">{{ t.Name }}</option>\n }\n </select>\n </div>\n <div class=\"form-field flex-1\">\n <label>Value</label>\n <input type=\"text\" [(ngModel)]=\"AddForm.Value\" [placeholder]=\"getPlaceholder(AddForm.TypeID)\">\n </div>\n <div class=\"form-field label-field\">\n <label>Label</label>\n <input type=\"text\" [(ngModel)]=\"AddForm.Label\" placeholder=\"e.g., Direct Line\">\n </div>\n <div class=\"checkbox-field\">\n <input type=\"checkbox\" id=\"primary-add\" [(ngModel)]=\"AddForm.IsPrimary\">\n <label for=\"primary-add\">Primary</label>\n </div>\n <div class=\"form-actions\">\n <button class=\"btn btn-primary btn-sm\" (click)=\"onSaveAdd()\" [disabled]=\"Saving\">\n @if (Saving) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n }\n Add\n </button>\n <button class=\"btn btn-cancel btn-sm\" (click)=\"onCancelAdd()\">Cancel</button>\n </div>\n @if (isConsentType(AddForm.TypeID)) {\n <div class=\"form-row consent-row\">\n <div class=\"form-field consent-field\">\n <label>General</label>\n <select [(ngModel)]=\"AddForm.Consents[GeneralKey]\">\n @for (s of ConsentStatuses; track s) {\n <option [value]=\"s\">{{ s }}</option>\n }\n </select>\n </div>\n @for (p of ConsentPurposes; track p.ID) {\n <div class=\"form-field consent-field\">\n <label>{{ p.Name }}</label>\n <select [(ngModel)]=\"AddForm.Consents[p.ID]\">\n @for (s of ConsentStatuses; track s) {\n <option [value]=\"s\">{{ s }}</option>\n }\n </select>\n </div>\n }\n </div>\n }\n </div>\n }\n\n <!-- Add button footer -->\n @if (!ShowAddForm && EditingId === null && EditMode) {\n <div class=\"cm-flat-footer\">\n <button class=\"btn btn-outline full-width\" (click)=\"onShowAdd()\">\n <i class=\"fa-solid fa-plus\"></i>\n Add Contact\n </button>\n </div>\n }\n </div>\n}\n", styles: ["/* ============================================\n ContactMethodList - Flat List with Icons Design\n Pixel-perfect match to Option B mockup\n ============================================ */\n\n:host {\n display: block;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;\n color: var(--mj-text-primary);\n}\n\n.section-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 16px;\n}\n\n.section-label {\n font-size: 15px;\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.section-label i {\n color: var(--mj-brand-primary);\n}\n\n.count {\n font-size: 12px;\n color: var(--mj-text-muted);\n font-weight: 400;\n}\n\n/* Flat list container */\n.cm-flat-list {\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n overflow: hidden;\n}\n\n/* Row */\n.cm-flat-row {\n display: flex;\n align-items: center;\n padding: 10px 16px;\n border-bottom: 1px solid var(--mj-bg-surface-sunken);\n gap: 12px;\n transition: background 0.1s;\n}\n\n.cm-flat-row:last-child {\n border-bottom: none;\n}\n\n.cm-flat-row:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.cm-flat-row.primary {\n background: var(--mj-status-success-bg);\n}\n\n/* Icon */\n.cm-flat-icon {\n width: 36px;\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 8px;\n font-size: 15px;\n flex-shrink: 0;\n}\n\n.cm-flat-icon.icon-email {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary-hover);\n}\n\n.cm-flat-icon.icon-phone {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n}\n\n.cm-flat-icon.icon-mobile {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n}\n\n.cm-flat-icon.icon-linkedin {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.cm-flat-icon.icon-twitter {\n background: var(--mj-border-default);\n color: var(--mj-text-primary);\n}\n\n.cm-flat-icon.icon-web {\n background: var(--mj-status-warning-bg);\n color: var(--mj-status-warning-text);\n}\n\n.cm-flat-icon.icon-fax {\n background: var(--mj-status-info-bg);\n color: var(--mj-status-info-text);\n}\n\n.cm-flat-icon.icon-default {\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n}\n\n/* Content */\n.cm-flat-content {\n flex: 1;\n min-width: 0;\n}\n\n.cm-flat-value {\n font-size: 14px;\n color: var(--mj-text-primary);\n cursor: pointer;\n}\n\n.cm-flat-value:hover {\n color: var(--mj-brand-primary);\n}\n\n.cm-flat-meta {\n font-size: 12px;\n color: var(--mj-text-muted);\n margin-top: 1px;\n}\n\n/* Badges */\n.cm-flat-badges {\n display: flex;\n gap: 6px;\n flex-shrink: 0;\n}\n\n.badge {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 3px 10px;\n border-radius: 12px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n}\n\n.badge-primary {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n}\n\n/* Actions */\n.cm-flat-actions {\n display: flex;\n gap: 2px;\n flex-shrink: 0;\n opacity: 0;\n transition: opacity 0.15s;\n}\n\n.cm-flat-row:hover .cm-flat-actions {\n opacity: 1;\n}\n\n/* Ghost buttons */\n.btn-ghost {\n background: transparent;\n color: var(--mj-text-disabled);\n padding: 6px 8px;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n font-size: 13px;\n transition: all 0.15s ease;\n}\n\n.btn-ghost:hover {\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface-card);\n}\n\n.btn-ghost.danger:hover {\n color: var(--mj-status-error-text);\n background: var(--mj-status-error-bg);\n}\n\n/* Add form */\n.cm-flat-add-form {\n padding: 14px 16px;\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n border-top: 2px solid var(--mj-brand-primary);\n display: flex;\n gap: 10px;\n align-items: flex-end;\n flex-wrap: wrap;\n}\n\n/* Edit inline row */\n.cm-flat-edit-row {\n padding: 14px 16px;\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n border-bottom: 2px solid var(--mj-brand-primary);\n}\n\n.cm-flat-edit-row .form-row {\n display: flex;\n gap: 10px;\n align-items: flex-end;\n}\n\n/* Buttons */\n.btn {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 8px 16px;\n border: none;\n border-radius: 6px;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n}\n\n.btn-primary {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.btn-primary:hover {\n background: var(--mj-brand-primary-hover);\n}\n\n.btn-cancel {\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n border: 1px solid var(--mj-border-default);\n}\n\n.btn-cancel:hover {\n background: var(--mj-border-subtle);\n}\n\n.btn-sm {\n padding: 7px 14px;\n}\n\n/* Form fields */\n.form-field {\n display: flex;\n flex-direction: column;\n}\n\n.form-field.flex-1 {\n flex: 1;\n}\n\n.form-field label {\n display: block;\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n margin-bottom: 4px;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n}\n\n.form-field input,\n.form-field select {\n width: 100%;\n padding: 8px 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n font-size: 14px;\n font-family: inherit;\n background: var(--mj-bg-surface);\n}\n\n.form-field input:focus,\n.form-field select:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n\n.form-field.type-field {\n max-width: 160px;\n}\n\n.form-field.label-field {\n max-width: 140px;\n}\n\n.checkbox-field {\n display: flex;\n align-items: center;\n gap: 8px;\n padding-top: 20px;\n}\n\n.checkbox-field input[type=\"checkbox\"] {\n width: 16px;\n height: 16px;\n cursor: pointer;\n}\n\n.checkbox-field label {\n font-size: 13px;\n color: var(--mj-text-secondary);\n cursor: pointer;\n}\n\n.form-actions {\n padding-top: 18px;\n display: flex;\n gap: 6px;\n}\n\n/* Copy toast */\n.copy-toast {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 4px 10px;\n background: var(--mj-text-primary);\n color: var(--mj-brand-on-primary);\n border-radius: 4px;\n font-size: 11px;\n margin-left: 8px;\n animation: fadeInOut 1.5s ease-in-out;\n}\n\n@keyframes fadeInOut {\n 0% { opacity: 0; }\n 15% { opacity: 1; }\n 70% { opacity: 1; }\n 100% { opacity: 0; }\n}\n\n/* Empty state */\n.empty-state {\n text-align: center;\n padding: 32px 16px;\n color: var(--mj-text-muted);\n font-size: 14px;\n}\n\n.empty-state i {\n font-size: 24px;\n color: var(--mj-border-strong);\n margin-bottom: 8px;\n display: block;\n}\n\n/* Loading */\n.loading-row {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 24px;\n color: var(--mj-text-muted);\n font-size: 13px;\n gap: 8px;\n}\n\n.loading-row i {\n animation: spin 1s linear infinite;\n}\n\n@keyframes spin {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n}\n\n/* Footer add button area */\n.cm-flat-footer {\n padding: 12px 16px;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n}\n\n.btn-outline {\n background: transparent;\n border: 1px dashed var(--mj-border-strong);\n color: var(--mj-text-secondary);\n}\n\n.btn-outline:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 6%, var(--mj-bg-surface));\n}\n\n.btn-outline.full-width {\n width: 100%;\n justify-content: center;\n}\n\n/* Consent badge: one per contact method whose type maps to a channel */\n.badge-consent {\n cursor: default;\n text-transform: none;\n letter-spacing: 0;\n}\n\n.badge-consent.consent-in {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n}\n\n.badge-consent.consent-out {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n}\n\n.badge-consent.consent-unknown {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n border: 1px solid var(--mj-border-subtle);\n}\n\n/* Consent history: shown while hovering a badge, newest change first */\n.cm-flat-badges {\n position: relative;\n}\n\n.consent-history {\n position: absolute;\n top: 100%;\n right: 0;\n z-index: 20;\n min-width: 300px;\n padding: 10px 12px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n box-shadow: 0 6px 18px color-mix(in srgb, var(--mj-text-primary) 14%, transparent);\n font-size: 12px;\n color: var(--mj-text-primary);\n}\n\n.consent-history-title {\n font-weight: 600;\n margin-bottom: 6px;\n color: var(--mj-text-primary);\n}\n\n.consent-history-row {\n display: grid;\n grid-template-columns: 90px 90px 1fr;\n gap: 8px;\n padding: 3px 0;\n border-top: 1px solid var(--mj-border-subtle);\n}\n\n.consent-history-row:first-of-type {\n border-top: none;\n}\n\n.consent-history-row.current {\n font-weight: 600;\n}\n\n.consent-history-source {\n color: var(--mj-text-secondary);\n}\n\n.consent-history-empty,\n.consent-history-note {\n color: var(--mj-text-muted);\n font-size: 11px;\n margin-top: 6px;\n}\n\n/* Consent dropdown on the add and edit rows */\n.form-field.consent-field select {\n min-width: 130px;\n}\n\n/* A method's consents: one badge per purpose (and organization), hover for history */\n.consent-badges {\n display: inline-flex;\n flex-wrap: wrap;\n gap: 6px;\n justify-content: flex-end;\n}\n\n.badge-consent .consent-purpose {\n font-weight: 500;\n opacity: 0.8;\n}\n\n.badge-consent .consent-purpose::after {\n content: '\u00B7';\n margin: 0 2px 0 4px;\n}\n\n.consent-history-row {\n grid-template-columns: 90px 1fr 90px 1fr;\n}\n\n.consent-history-purpose {\n color: var(--mj-text-secondary);\n}\n\n/* One dropdown per purpose under the add and edit rows */\n.cm-flat-add-form,\n.cm-flat-edit-row .form-row {\n flex-wrap: wrap;\n}\n\n.form-row.consent-row {\n flex-basis: 100%;\n display: flex;\n flex-wrap: wrap;\n gap: 12px;\n margin-top: 8px;\n padding-top: 8px;\n border-top: 1px solid var(--mj-border-subtle);\n}\n"] }]
846
1356
  }], null, { EditMode: [{
847
1357
  type: Input
1358
+ }], Provider: [{
1359
+ type: Input
848
1360
  }], DataChanged: [{
849
1361
  type: Output
850
1362
  }], Collection: [{
@@ -854,5 +1366,5 @@ export class ContactMethodListComponent {
854
1366
  }], OrganizationID: [{
855
1367
  type: Input
856
1368
  }] }); })();
857
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ContactMethodListComponent, { className: "ContactMethodListComponent", filePath: "lib/components/contact-method-list/contact-method-list.component.ts", lineNumber: 62 }); })();
1369
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ContactMethodListComponent, { className: "ContactMethodListComponent", filePath: "lib/components/contact-method-list/contact-method-list.component.ts", lineNumber: 102 }); })();
858
1370
  //# sourceMappingURL=contact-method-list.component.js.map