diff --git a/projects/swimlane/ngx-ui/CHANGELOG.md b/projects/swimlane/ngx-ui/CHANGELOG.md index 2797a3074..6dd518619 100644 --- a/projects/swimlane/ngx-ui/CHANGELOG.md +++ b/projects/swimlane/ngx-ui/CHANGELOG.md @@ -2,6 +2,11 @@ ## HEAD (unreleased) +- Enhancement (`ngx-calendar`): Should initialize with Date when `range` Input is used +- Enhancement (`ngx-calendar`): Validation for time in date range selection +- Fix (`ngx-calendar`): Possible bug when emitting date range selection and selecting AM/PM +- Fix (`ngx-calendar`): Possible bug where time could appear `0` when selecting a date range + ## 48.0.4 (2024-09-18) - Enhancement (`ngx-toggle`): Added `timeStamp` when emiting `change` diff --git a/projects/swimlane/ngx-ui/src/lib/components/calendar/calendar.component.html b/projects/swimlane/ngx-ui/src/lib/components/calendar/calendar.component.html index 8afea0c14..eccc3e041 100644 --- a/projects/swimlane/ngx-ui/src/lib/components/calendar/calendar.component.html +++ b/projects/swimlane/ngx-ui/src/lib/components/calendar/calendar.component.html @@ -163,23 +163,25 @@
@@ -208,23 +210,25 @@
diff --git a/projects/swimlane/ngx-ui/src/lib/components/calendar/calendar.component.ts b/projects/swimlane/ngx-ui/src/lib/components/calendar/calendar.component.ts index 6791199c8..3f8ea1bcb 100644 --- a/projects/swimlane/ngx-ui/src/lib/components/calendar/calendar.component.ts +++ b/projects/swimlane/ngx-ui/src/lib/components/calendar/calendar.component.ts @@ -34,6 +34,11 @@ export interface CalendarDateRange { endDate: Date | undefined; } +interface CalendarDateRangeSelection { + startDateSelection: boolean; + endDateSelection: boolean; +} + @Component({ selector: 'ngx-calendar', exportAs: 'ngxCalendar', @@ -61,7 +66,10 @@ export class CalendarComponent implements OnInit, AfterViewInit, ControlValueAcc @Input() inputFormats: Array = ['L', 'LT', 'L LT', moment.ISO_8601]; @Input() selectType: string = CalendarSelect.Single; @Input() dateLabelFormat: string = 'MMM D YYYY'; - @Input() range: CalendarDateRange = { startDate: undefined, endDate: undefined }; + @Input() range: CalendarDateRange = { + startDate: undefined, + endDate: undefined + }; @Input('minView') get minView() { @@ -114,12 +122,16 @@ export class CalendarComponent implements OnInit, AfterViewInit, ControlValueAcc monthsList = moment.monthsShort(); startYear: number; - startHour: number; - endHour: number; - startMinute: number; - endMinute: number; - startAmPmVal: string; - endAmPmVal: string; + startHour: string; + endHour: string; + startMinute: string; + endMinute: string; + startAmPmVal = 'AM'; + endAmPmVal = 'AM'; + dateRangeSelection: CalendarDateRangeSelection = { + startDateSelection: false, + endDateSelection: false + }; readonly CalendarView = CalendarView; readonly CalendarSelect = CalendarSelect; @@ -153,7 +165,6 @@ export class CalendarComponent implements OnInit, AfterViewInit, ControlValueAcc } else { this.currentView = this.minView; } - this.weeks = getMonth(this.focusDate); } @@ -177,27 +188,23 @@ export class CalendarComponent implements OnInit, AfterViewInit, ControlValueAcc * Initializes the values for initial time */ initializeTime(): void { - this.startHour = this.range.startDate - ? this.range.startDate.getHours() % 12 - : +moment('2001-01-01T00:00:00').format('hh') % 12; - this.endHour = this.range.endDate - ? this.range.endDate.getHours() % 12 - : +moment('2001-01-01T00:00:00').format('hh') % 12; - - this.startMinute = this.range.startDate - ? this.range.startDate.getMinutes() - : +moment('2001-01-01T00:00:00').format('mm'); - this.endMinute = this.range.endDate ? this.range.endDate.getMinutes() : +moment('2001-01-01T00:00:00').format('mm'); - this.startAmPmVal = this.range.startDate - ? this.range.startDate.getHours() >= 12 - ? 'PM' - : 'AM' - : moment('2001-01-01T00:00:00').format('A'); - this.endAmPmVal = this.range.endDate - ? this.range.endDate.getHours() >= 12 - ? 'PM' - : 'AM' - : moment('2001-01-01T00:00:00').format('A'); + let startDate: Date | undefined, endDate: Date | undefined; + if (!this.range.startDate) { + startDate = new Date(new Date().setHours(0, 0, 0, 0)); + } else { + startDate = this.range.startDate; + } + if (!this.range.endDate) { + endDate = new Date(new Date().setHours(0, 0, 0, 0)); + } else { + endDate = this.range.endDate; + } + this.startHour = moment(startDate).format('hh'); + this.startMinute = moment(startDate).format('mm'); + this.startAmPmVal = moment(startDate).format('a').toUpperCase(); + this.endHour = moment(endDate).format('hh'); + this.endMinute = moment(endDate).format('mm'); + this.endAmPmVal = moment(endDate).format('a').toUpperCase(); } /** @@ -324,24 +331,35 @@ export class CalendarComponent implements OnInit, AfterViewInit, ControlValueAcc if (this.range.startDate === undefined && this.range.endDate === undefined) { this.range.startDate = this.focusDate.toDate(); - this.range.startDate.setHours(this.startHour); - this.range.startDate.setMinutes(+this.startMinute); + this.range.startDate.setHours(Number(this.startHour)); + this.range.startDate.setMinutes(Number(this.startMinute)); + this.dateRangeSelection.startDateSelection = true; } else if (this.range.endDate === undefined) { if (this.focusDate.toDate() > this.range.startDate) { this.range.endDate = this.focusDate.toDate(); - this.range.endDate.setHours(this.endHour); - this.range.endDate.setMinutes(+this.endMinute); + this.range.endDate.setHours(Number(this.endHour)); + this.range.endDate.setMinutes(Number(this.endMinute)); } else { this.range.startDate = this.focusDate.toDate(); - this.range.startDate.setHours(this.startHour); - this.range.startDate.setMinutes(+this.startMinute); + this.range.startDate.setHours(Number(this.startHour)); + this.range.startDate.setMinutes(Number(this.startMinute)); + this.dateRangeSelection.startDateSelection = true; } } else { this.range.startDate = this.focusDate.toDate(); - this.range.startDate.setHours(this.startHour); - this.range.startDate.setMinutes(+this.startMinute); + this.range.startDate.setHours(Number(this.startHour)); + this.range.startDate.setMinutes(Number(this.startMinute)); + this.dateRangeSelection.endDateSelection = false; + this.range.endDate = undefined; + } + + if (this.dateRangeSelection.startDateSelection && this.dateRangeSelection.endDateSelection) { + this.dateRangeSelection.startDateSelection = false; + this.dateRangeSelection.endDateSelection = false; + this.range.startDate = undefined; this.range.endDate = undefined; } + this.onRangeSelect.emit({ startDate: this.range.startDate, endDate: this.range.endDate }); if (day.prevMonth || day.nextMonth) { @@ -375,52 +393,59 @@ export class CalendarComponent implements OnInit, AfterViewInit, ControlValueAcc } } - hourChanged(newVal: number, type: string) { - newVal = +newVal % 12; + hourChanged(newVal: string, type: string) { if (type === 'start') { if (this.range.startDate) { - if (this.startAmPmVal === 'PM') newVal = 12 + newVal; - this.range.startDate.setHours(newVal); + if (this.endAmPmVal === 'PM') { + this.range.startDate.setHours(12 + Number(newVal)); + } else { + this.range.startDate.setHours(Number(newVal)); + } } - this.startHour = newVal % 12; + this.startHour = newVal; } else { if (this.range.endDate) { - if (this.endAmPmVal === 'PM') newVal = 12 + newVal; - this.range.endDate.setHours(newVal); + if (this.endAmPmVal === 'PM') { + this.range.endDate.setHours(12 + Number(newVal)); + } else { + this.range.endDate.setHours(Number(newVal)); + } } - this.endHour = newVal % 12; + this.endHour = newVal; } this.onRangeSelect.emit({ startDate: this.range.startDate, endDate: this.range.endDate }); } - minuteChanged(newVal: number, type: string) { + minuteChanged(newVal: string, type: string) { if (type === 'start') { - if (this.range.startDate) this.range.startDate.setMinutes(newVal); + if (this.range.startDate) { + this.range.startDate.setMinutes(Number(newVal)); + } this.startMinute = newVal; } else { - if (this.range.endDate) this.range.endDate.setMinutes(newVal); + if (this.range.endDate) { + this.range.endDate.setMinutes(Number(newVal)); + } this.endMinute = newVal; } this.onRangeSelect.emit({ startDate: this.range.startDate, endDate: this.range.endDate }); } onAmPmChange(newVal, type) { if (type === 'start') { - if (this.range.startDate) { - const hourClone = this.range.startDate.getHours(); - if (newVal === 'AM' && this.startAmPmVal === 'PM') { - this.range.startDate.setHours(hourClone - 12); - } else if (newVal === 'PM' && this.startAmPmVal === 'AM') { - this.range.startDate.setHours(hourClone + 12); - } + const hourClone = this.range.startDate.getHours(); + if (hourClone >= 12 && newVal === 'AM') { + this.range.startDate.setHours(hourClone - 12); + } + if (hourClone >= 0 && hourClone < 12 && newVal === 'PM') { + this.range.startDate.setHours(hourClone + 12); } this.startAmPmVal = newVal; } else { - if (this.range.endDate) { - const hourClone = this.range.endDate.getHours(); - if (newVal === 'AM' && this.endAmPmVal === 'PM') { - this.range.endDate.setHours(hourClone - 12); - } else if (newVal === 'PM' && this.endAmPmVal === 'AM') { - this.range.endDate.setHours(hourClone + 12); - } + const hourClone = this.range.endDate.getHours(); + if (hourClone >= 12 && newVal === 'AM') { + this.range.endDate.setHours(hourClone - 12); + } + if (hourClone >= 0 && hourClone < 12 && newVal === 'PM') { + this.range.endDate.setHours(hourClone + 12); } this.endAmPmVal = newVal; } @@ -508,8 +533,6 @@ export class CalendarComponent implements OnInit, AfterViewInit, ControlValueAcc } onDayDown(event: KeyboardEvent) { - // console.log(event.code); - let stop = false; if (this.currentView === CalendarView.Date) { diff --git a/projects/swimlane/ngx-ui/src/lib/components/calendar/calender.component.spec.ts b/projects/swimlane/ngx-ui/src/lib/components/calendar/calender.component.spec.ts index c7bc91371..0ce76bb0b 100644 --- a/projects/swimlane/ngx-ui/src/lib/components/calendar/calender.component.spec.ts +++ b/projects/swimlane/ngx-ui/src/lib/components/calendar/calender.component.spec.ts @@ -330,15 +330,15 @@ describe('CalendarComponent', () => { it('should update hour correctly', () => { component.range = { startDate: new Date(), endDate: undefined }; component.startAmPmVal = 'PM'; - component.startHour = 5; - component.hourChanged(3, 'start'); - expect(component.range?.startDate?.getHours()).toBe(15); + component.startHour = '5'; + component.hourChanged('03', 'start'); + expect(component.range?.startDate?.getHours()).toBe(3); }); it('should update minute correctly', () => { component.range = { startDate: new Date(), endDate: undefined }; - component.startMinute = 30; - component.minuteChanged(45, 'start'); + component.startMinute = '30'; + component.minuteChanged('45', 'start'); expect(component.range?.startDate?.getMinutes()).toBe(45); }); @@ -359,22 +359,22 @@ describe('CalendarComponent', () => { component.range = { startDate: rangeStart, endDate: rangeEnd }; component.initializeTime(); - expect(component.startHour).toBe(10); - expect(component.startMinute).toBe(30); + expect(component.startHour).toBe('10'); + expect(component.startMinute).toBe('30'); expect(component.startAmPmVal).toBe('AM'); - expect(component.endHour).toBe(3); - expect(component.endMinute).toBe(45); + expect(component.endHour).toBe('03'); + expect(component.endMinute).toBe('45'); expect(component.endAmPmVal).toBe('PM'); }); it('should initialize time properties with default values if range start and rangeEnd are not provided', () => { component.initializeTime(); - expect(component.startHour).toBe(0); - expect(component.endHour).toBe(0); - expect(component.startMinute).toBe(0); - expect(component.endMinute).toBe(0); + expect(component.startHour).toBe('12'); + expect(component.endHour).toBe('12'); + expect(component.startMinute).toBe('00'); + expect(component.endMinute).toBe('00'); expect(component.startAmPmVal).toBe('AM'); expect(component.endAmPmVal).toBe('AM'); }); @@ -385,8 +385,8 @@ describe('CalendarComponent', () => { const day = { date: moment('2024-04-04'), nextMonth: true, prevMonth: true } as CalendarDay; component.focusDate = moment('2024-04-04'); component.range = { startDate: undefined, endDate: undefined }; - component.startHour = 10; - component.startMinute = 30; + component.startHour = '10'; + component.startMinute = '30'; component.onDaySelectRange(day); @@ -398,8 +398,8 @@ describe('CalendarComponent', () => { const day = { date: moment('2024-04-10'), nextMonth: true, prevMonth: true } as CalendarDay; component.focusDate = moment('2024-04-10'); component.range = { startDate: new Date('2024-04-04T10:30:00'), endDate: undefined }; - component.endHour = 15; - component.endMinute = 45; + component.endHour = '15'; + component.endMinute = '45'; component.onDaySelectRange(day); @@ -411,8 +411,8 @@ describe('CalendarComponent', () => { const day = { date: moment('2024-04-01'), nextMonth: true, prevMonth: true } as CalendarDay; component.focusDate = moment('2024-04-01'); component.range = { startDate: new Date('2024-04-04T10:30:00'), endDate: undefined }; - component.startHour = 8; - component.startMinute = 15; + component.startHour = '8'; + component.startMinute = '15'; component.onDaySelectRange(day); @@ -424,8 +424,8 @@ describe('CalendarComponent', () => { const day = { date: moment('2024-04-04'), nextMonth: true, prevMonth: true } as CalendarDay; component.focusDate = moment('2024-04-04'); component.range = { startDate: new Date('2024-04-01T08:15:00'), endDate: new Date('2024-04-10T15:45:00') }; - component.startHour = 12; - component.startMinute = 0; + component.startHour = '12'; + component.startMinute = '0'; component.onDaySelectRange(day);