]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/eg2/src/app/share/datetime-select/datetime-select.component.ts
LP#1884787: update Angular staff client to work with momement-timezone >= 0.5.29
[Evergreen.git] / Open-ILS / src / eg2 / src / app / share / datetime-select / datetime-select.component.ts
1 import {Component, EventEmitter, Input, Output, forwardRef, ViewChild, OnInit, Optional, Self} from '@angular/core';
2 import {FormatService} from '@eg/core/format.service';
3 import {AbstractControl, ControlValueAccessor, FormControl, FormGroup, NgControl} from '@angular/forms';
4 import {NgbDatepicker, NgbTimeStruct, NgbDateStruct} from '@ng-bootstrap/ng-bootstrap';
5 import {DatetimeValidator} from '@eg/share/validators/datetime_validator.directive';
6 import * as moment from 'moment-timezone';
7
8 @Component({
9     selector: 'eg-datetime-select',
10     templateUrl: './datetime-select.component.html',
11 })
12 export class DateTimeSelectComponent implements OnInit, ControlValueAccessor {
13     @Input() domId = '';
14     @Input() fieldName: string;
15     @Input() initialIso: string;
16     @Input() required: boolean;
17     @Input() minuteStep = 15;
18     @Input() showTZ = true;
19     @Input() timezone: string = this.format.wsOrgTimezone;
20     @Input() readOnly = false;
21     @Output() onChangeAsIso: EventEmitter<string>;
22
23     dateTimeForm: FormGroup;
24
25     @ViewChild('datePicker', { static: false }) datePicker;
26
27     onChange = (_: any) => {};
28     onTouched = () => {};
29
30     constructor(
31         private format: FormatService,
32         private dtv: DatetimeValidator,
33         @Optional()
34         @Self()
35         public controlDir: NgControl, // so that the template can access validation state
36     ) {
37         if (controlDir) { controlDir.valueAccessor = this; }
38         this.onChangeAsIso = new EventEmitter<string>();
39         const startValue = moment.tz([], this.timezone);
40         this.dateTimeForm = new FormGroup({
41             'stringVersion': new FormControl(
42                 this.format.transform({value: startValue, datatype: 'timestamp', datePlusTime: true}),
43                 this.dtv.validate),
44             'date': new FormControl({
45                 year: startValue.year(),
46                 month: startValue.month() + 1,
47                 day: startValue.date() }),
48             'time': new FormControl({
49                 hour: startValue.hour(),
50                 minute: startValue.minute(),
51                 second: 0 })
52         });
53     }
54
55     ngOnInit() {
56         if (!this.timezone) {
57             this.timezone = this.format.wsOrgTimezone;
58         }
59         if (this.initialIso) {
60             this.writeValue(moment(this.initialIso).tz(this.timezone));
61         }
62         this.dateTimeForm.get('stringVersion').valueChanges.subscribe((value) => {
63             if ('VALID' === this.dateTimeForm.get('stringVersion').status) {
64                 const model = this.format.momentizeDateTimeString(value, this.timezone, false);
65                 if (model && model.isValid()) {
66                     this.onChange(model);
67                     this.onChangeAsIso.emit(model.toISOString());
68                     this.dateTimeForm.patchValue({date: {
69                         year: model.year(),
70                         month: model.month() + 1,
71                         day: model.date()}, time: {
72                         hour: model.hour(),
73                         minute: model.minute(),
74                         second: 0 }
75                     }, {emitEvent: false, onlySelf: true});
76                     this.datePicker.navigateTo({
77                         year: model.year(),
78                         month: model.month() + 1
79                     });
80                 }
81             }
82         });
83         this.dateTimeForm.get('date').valueChanges.subscribe((date) => {
84             const newDate = moment.tz([date.year, (date.month - 1), date.day,
85                 this.time.value.hour, this.time.value.minute, 0], this.timezone);
86             this.dateTimeForm.patchValue({stringVersion:
87                 this.format.transform({value: newDate, datatype: 'timestamp', datePlusTime: true})},
88                 {emitEvent: false, onlySelf: true});
89             this.onChange(newDate);
90             this.onChangeAsIso.emit(newDate.toISOString());
91         });
92
93         this.dateTimeForm.get('time').valueChanges.subscribe((time) => {
94             const newDate = moment.tz([this.date.value.year,
95                 (this.date.value.month - 1),
96                 this.date.value.day,
97                 time.hour, time.minute, 0],
98                 this.timezone);
99             this.dateTimeForm.patchValue({stringVersion:
100                 this.format.transform({
101                 value: newDate, datatype: 'timestamp', datePlusTime: true})},
102                 {emitEvent: false, onlySelf: true});
103             this.onChange(newDate);
104             this.onChangeAsIso.emit(newDate.toISOString());
105         });
106     }
107
108     setDatePicker(current: moment.Moment) {
109         const withTZ = current ? current.tz(this.timezone) : moment.tz([], this.timezone);
110         this.dateTimeForm.patchValue({date: {
111             year: withTZ.year(),
112             month: withTZ.month() + 1,
113             day: withTZ.date() }});
114     }
115
116     setTimePicker(current: moment.Moment) {
117         const withTZ = current ? current.tz(this.timezone) : moment.tz([], this.timezone);
118         this.dateTimeForm.patchValue({time: {
119             hour: withTZ.hour(),
120             minute: withTZ.minute(),
121             second: 0 }});
122     }
123
124
125     writeValue(value: moment.Moment) {
126         if (value !== undefined && value !== null) {
127             this.dateTimeForm.patchValue({
128                 stringVersion: this.format.transform({value: value, datatype: 'timestamp', datePlusTime: true})});
129             this.setDatePicker(value);
130             this.setTimePicker(value);
131         }
132     }
133
134     registerOnChange(fn: (value: moment.Moment) => any): void {
135         this.onChange = fn;
136     }
137     registerOnTouched(fn: () => any): void {
138         this.onTouched = fn;
139     }
140
141     firstError(errors: Object) {
142         return Object.values(errors)[0];
143     }
144
145     get stringVersion(): AbstractControl {
146         return this.dateTimeForm.get('stringVersion');
147     }
148
149     get date(): AbstractControl {
150         return this.dateTimeForm.get('date');
151     }
152
153     get time(): AbstractControl {
154         return this.dateTimeForm.get('time');
155     }
156
157 }
158