]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/eg2/src/app/share/org-family-select/org-family-select.component.ts
LP2045292 Color contrast for AngularJS patron bills
[Evergreen.git] / Open-ILS / src / eg2 / src / app / share / org-family-select / org-family-select.component.ts
1 import {Component, EventEmitter, OnInit, Input, Output, ViewChildren, QueryList, forwardRef} from '@angular/core';
2 import {ControlValueAccessor, FormGroup, FormControl, NG_VALUE_ACCESSOR} from '@angular/forms';
3 import {AuthService} from '@eg/core/auth.service';
4 import {IdlObject} from '@eg/core/idl.service';
5 import {OrgService} from '@eg/core/org.service';
6 import {OrgSelectComponent} from '@eg/share/org-select/org-select.component';
7
8 export interface OrgFamily {
9   primaryOrgId: number;
10   includeAncestors?: boolean;
11   includeDescendants?: boolean;
12   orgIds?: number[];
13 }
14
15 @Component({
16     selector: 'eg-org-family-select',
17     templateUrl: 'org-family-select.component.html',
18     providers: [
19     {
20       provide: NG_VALUE_ACCESSOR,
21       useExisting: forwardRef(() => OrgFamilySelectComponent),
22       multi: true
23     }
24   ]
25 })
26 export class OrgFamilySelectComponent implements ControlValueAccessor, OnInit {
27
28     // The label for this input
29     @Input() labelText = 'Library';
30
31     // Should the Ancestors checkbox be hidden?
32     @Input() hideAncestorSelector = false;
33
34     // Should the Descendants checkbox be hidden?
35     @Input() hideDescendantSelector = false;
36
37     // Should the Ancestors checkbox be checked by default?
38     //
39     // Ignored if [hideAncestorSelector]="true"
40     @Input() ancestorSelectorChecked = false;
41
42     // Should the Descendants checkbox be checked by default?
43     //
44     // Ignored if [hideDescendantSelector]="true"
45     @Input() descendantSelectorChecked = false;
46
47     // Default org unit
48     @Input() selectedOrgId: number;
49
50     // Only show the OUs that the user has certain permissions at
51     @Input() limitPerms: string[];
52
53     @Input() domId: string;
54
55     @Output() onChange = new EventEmitter<any>();
56
57     @ViewChildren(OrgSelectComponent)  orgSelects: QueryList<OrgSelectComponent>;
58
59     // this is the most up-to-date value used for ngModel and reactive form
60     // subscriptions
61     options: OrgFamily;
62
63     orgOnChange: ($event: IdlObject) => void;
64     emitArray: () => void;
65
66     familySelectors: FormGroup;
67
68     propagateChange = (_: OrgFamily) => {};
69     propagateTouch = () => {};
70
71     constructor(
72         private auth: AuthService,
73         private org: OrgService
74     ) {
75     }
76
77     ngOnInit() {
78         if (this.selectedOrgId) {
79             this.options = {primaryOrgId: this.selectedOrgId};
80         } else if (this.auth.user()) {
81             this.options = {primaryOrgId: this.auth.user().ws_ou()};
82         }
83
84         this.familySelectors = new FormGroup({
85             'includeAncestors': new FormControl({
86                 value: this.ancestorSelectorChecked,
87                 disabled: this.disableAncestorSelector()}),
88             'includeDescendants': new FormControl({
89                 value: this.descendantSelectorChecked,
90                 disabled: this.disableDescendantSelector()}),
91         });
92
93         if (!this.domId) {
94             this.domId = 'org-family-select-' + Math.floor(Math.random() * 100000);
95         }
96
97         this.familySelectors.valueChanges.subscribe(val => {
98             this.emitArray();
99         });
100
101         this.orgOnChange = ($event: IdlObject) => {
102             this.options.primaryOrgId = $event.id();
103             this.disableAncestorSelector() ? this.includeAncestors.disable() : this.includeAncestors.enable();
104             this.disableDescendantSelector() ? this.includeDescendants.disable() : this.includeDescendants.enable();
105             this.emitArray();
106         };
107
108         this.emitArray = () => {
109             // Prepare and emit an array containing the primary org id and
110             // optionally ancestor and descendant org units, and flags that select those.
111
112             this.options.orgIds = [this.options.primaryOrgId];
113             this.options.includeAncestors = this.includeAncestors.value;
114             this.options.includeDescendants = this.includeDescendants.value;
115
116             if (this.includeAncestors.value) {
117                 this.options.orgIds = this.org.ancestors(this.options.primaryOrgId, true);
118             }
119
120             if (this.includeDescendants.value) {
121                 this.options.orgIds = this.options.orgIds.concat(
122                     this.org.descendants(this.options.primaryOrgId, true));
123             }
124
125             // Using ancestors() and descendants() can result in
126             // duplicate org ID's.  Be nice and uniqify.
127             const hash: any = {};
128             this.options.orgIds.forEach(id => hash[id] = true);
129             this.options.orgIds = Object.keys(hash).map(id => Number(id));
130
131             this.propagateChange(this.options);
132             this.onChange.emit(this.options);
133         };
134     }
135
136     writeValue(value: OrgFamily) {
137         if (value) {
138             this.selectedOrgId = value['primaryOrgId'];
139             if (this.orgSelects) {
140                 this.orgSelects.toArray()[0].applyOrgId = this.selectedOrgId;
141                 this.options = {primaryOrgId: this.selectedOrgId};
142             }
143             this.familySelectors.patchValue({
144                 'includeAncestors': value['includeAncestors'] ? value['includeAncestors'] : false,
145                 'includeDescendants': value['includeDescendants'] ? value['includeDescendants'] : false,
146             });
147         }
148     }
149
150     registerOnChange(fn) {
151         this.propagateChange = fn;
152     }
153
154     registerOnTouched(fn) {
155         this.propagateTouch = fn;
156     }
157
158     disableAncestorSelector(): boolean {
159         return this.options.primaryOrgId === this.org.root().id();
160     }
161
162     disableDescendantSelector(): boolean {
163         const contextOrg = this.org.get(this.options.primaryOrgId);
164         return contextOrg.children().length === 0;
165     }
166
167     get includeAncestors() {
168         return this.familySelectors.get('includeAncestors');
169     }
170     get includeDescendants() {
171         return this.familySelectors.get('includeDescendants');
172     }
173
174 }
175