diff --git a/src/framework/theme/components/calendar-kit/components/calendar-month-picker/calendar-month-picker.component.ts b/src/framework/theme/components/calendar-kit/components/calendar-month-picker/calendar-month-picker.component.ts index 7e6eccbb11..93ca02ce2e 100644 --- a/src/framework/theme/components/calendar-kit/components/calendar-month-picker/calendar-month-picker.component.ts +++ b/src/framework/theme/components/calendar-kit/components/calendar-month-picker/calendar-month-picker.component.ts @@ -19,6 +19,8 @@ import { NbCalendarCell, NbCalendarSize } from '../../model'; import { NbCalendarMonthCellComponent } from './calendar-month-cell.component'; import { NbDateService } from '../../services'; +export const MONTHS_IN_VIEW = 12; +export const MONTHS_IN_COLUMN = 4; @Component({ selector: 'nb-calendar-month-picker', @@ -73,8 +75,8 @@ export class NbCalendarMonthPickerComponent implements OnInit { } initMonths() { - const months: D[] = range(12).map(i => this.createMonthDateByIndex(i)); - this.months = batch(months, 4); + const months: D[] = range(MONTHS_IN_VIEW).map(i => this.createMonthDateByIndex(i)); + this.months = batch(months, MONTHS_IN_COLUMN); } onSelect(month: D) { diff --git a/src/framework/theme/components/calendar-kit/components/calendar-year-picker/calendar-year-picker.component.ts b/src/framework/theme/components/calendar-kit/components/calendar-year-picker/calendar-year-picker.component.ts index d3e98801c6..5a37ed964c 100644 --- a/src/framework/theme/components/calendar-kit/components/calendar-year-picker/calendar-year-picker.component.ts +++ b/src/framework/theme/components/calendar-kit/components/calendar-year-picker/calendar-year-picker.component.ts @@ -19,8 +19,8 @@ import { NbCalendarCell, NbCalendarSize } from '../../model'; import { NbCalendarYearCellComponent } from './calendar-year-cell.component'; import { NbDateService } from '../../services'; - -const defaultYearCount = 20; +export const YEARS_IN_VIEW = 20; +export const YEARS_IN_COLUMN = 4; @Component({ selector: 'nb-calendar-year-picker', @@ -83,9 +83,9 @@ export class NbCalendarYearPickerComponent implements OnChanges { initYears() { const selectedYear = this.dateService.getYear(this.year); - const startYear = Math.ceil(selectedYear - defaultYearCount / 2); - const years = range(defaultYearCount).map(i => this.createYearDateByIndex(i + startYear)); - this.years = batch(years, 4); + const startYear = Math.ceil(selectedYear - YEARS_IN_VIEW / 2); + const years = range(YEARS_IN_VIEW).map(i => this.createYearDateByIndex(i + startYear)); + this.years = batch(years, YEARS_IN_COLUMN); } onSelect(year) { diff --git a/src/framework/theme/components/calendar-kit/components/index.ts b/src/framework/theme/components/calendar-kit/components/index.ts index 74b84eda97..f6cf40df6f 100644 --- a/src/framework/theme/components/calendar-kit/components/index.ts +++ b/src/framework/theme/components/calendar-kit/components/index.ts @@ -6,8 +6,16 @@ export { NbCalendarHeaderComponent } from './calendar-header/calendar-header.component'; export { NbCalendarDayCellComponent } from './calendar-day-picker/calendar-day-cell.component'; -export { NbCalendarYearPickerComponent } from './calendar-year-picker/calendar-year-picker.component'; -export { NbCalendarMonthPickerComponent } from './calendar-month-picker/calendar-month-picker.component'; +export { + NbCalendarYearPickerComponent, + YEARS_IN_VIEW, + YEARS_IN_COLUMN, +} from './calendar-year-picker/calendar-year-picker.component'; +export { + NbCalendarMonthPickerComponent, + MONTHS_IN_VIEW, + MONTHS_IN_COLUMN, +} from './calendar-month-picker/calendar-month-picker.component'; export { NbCalendarDayPickerComponent } from './calendar-day-picker/calendar-day-picker.component'; export { NbCalendarNavigationComponent } from './calendar-navigation/calendar-navigation.component'; export { NbCalendarPageableNavigationComponent } from './calendar-navigation/calendar-pageable-navigation.component'; diff --git a/src/framework/theme/components/calendar/base-calendar.component.ts b/src/framework/theme/components/calendar/base-calendar.component.ts index 0a704ef1dd..851cf6533b 100644 --- a/src/framework/theme/components/calendar/base-calendar.component.ts +++ b/src/framework/theme/components/calendar/base-calendar.component.ts @@ -6,8 +6,7 @@ import { Component, EventEmitter, HostBinding, Input, OnInit, Output, Type } from '@angular/core'; -import { NbDateService, NbCalendarCell, NbCalendarSize, NbCalendarViewMode } from '../calendar-kit'; - +import { NbDateService, NbCalendarCell, NbCalendarSize, NbCalendarViewMode, YEARS_IN_VIEW } from '../calendar-kit'; /** * The basis for calendar and range calendar components. @@ -139,6 +138,6 @@ export class NbBaseCalendarComponent implements OnInit { } private changeVisibleYear(direction: number) { - this.visibleDate = this.dateService.addYear(this.visibleDate, direction * 20); + this.visibleDate = this.dateService.addYear(this.visibleDate, direction * YEARS_IN_VIEW); } } diff --git a/src/framework/theme/components/datepicker/datepicker.component.ts b/src/framework/theme/components/datepicker/datepicker.component.ts index 6998e698be..f37eb29a9f 100644 --- a/src/framework/theme/components/datepicker/datepicker.component.ts +++ b/src/framework/theme/components/datepicker/datepicker.component.ts @@ -399,6 +399,7 @@ export class NbDatepickerComponent extends NbBasePicker extends NbBasePicker extends NbBasePicker extends NbBasePicker; } +@Component({ + selector: 'nb-rangepicker-test', + template: ` + + + + + + + `, +}) +export class NbRangepickerTestComponent { + @ViewChild(NbRangepickerComponent) rangepicker: NbRangepickerComponent; + @ViewChild(NbDatepickerDirective) datepickerDirective: NbDatepickerDirective; +} + describe('nb-datepicker', () => { let fixture: ComponentFixture; let appRef: ApplicationRef; @@ -101,8 +117,7 @@ describe('nb-datepicker', () => { cell.dispatchEvent(new Event('click')); }); - it('should select date typed in to the input', () => { - datepicker.visibleDate = new Date(2018, 8, 17); + it('should start from date typed into the input', () => { input.value = 'Sep 17, 2018'; input.dispatchEvent(new Event('input')); showDatepicker(); @@ -113,6 +128,37 @@ describe('nb-datepicker', () => { expect(cell.textContent).toContain('17'); }); + it('should start from current date if input is empty', () => { + showDatepicker(); + appRef.tick(); + expect(overlay.querySelector('.day-cell.today')).toBeDefined(); + }); + + it('should start from current date if input value is invalid', () => { + input.value = 'definitely not a date'; + input.dispatchEvent(new Event('input')); + showDatepicker(); + appRef.tick(); + expect(overlay.querySelector('.day-cell.today')).toBeDefined(); + }); + + it('should update visible date if input value changed', () => { + const initialDate = new Date(2000, 0, 1); + datepicker.visibleDate = initialDate; + + const date = 17; + const month = 8; + const year = 2018; + input.value = 'Sep 17, 2018'; + input.dispatchEvent(new Event('input')); + showDatepicker(); + appRef.tick(); + + expect(datepicker.visibleDate.getDate()).toEqual(date); + expect(datepicker.visibleDate.getMonth()).toEqual(month); + expect(datepicker.visibleDate.getFullYear()).toEqual(year); + }); + it('should be valid if empty', () => { expect(datepickerDirective.validate()).toBe(null); }); @@ -125,3 +171,161 @@ describe('nb-datepicker', () => { expect(datepickerDirective.validate()).not.toBe(null); }); }); + +describe('nb-rangepicker', () => { + let fixture: ComponentFixture; + let appRef: ApplicationRef; + let rangepicker: NbRangepickerComponent; + let datepickerDirective: NbDatepickerDirective; + let overlay: HTMLElement; + let input: HTMLInputElement; + + const showRangepicker = () => { + rangepicker.show(); + appRef.tick(); + }; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ + RouterTestingModule.withRoutes([]), + NbThemeModule.forRoot(), + NbLayoutModule, + NbDatepickerModule.forRoot(), + ], + declarations: [NbRangepickerTestComponent], + }); + + fixture = TestBed.createComponent(NbRangepickerTestComponent); + appRef = TestBed.get(ApplicationRef); + + fixture.detectChanges(); + }); + + beforeEach(() => { + rangepicker = fixture.componentInstance.rangepicker; + datepickerDirective = fixture.componentInstance.datepickerDirective; + overlay = fixture.nativeElement.querySelector('nb-layout'); + input = fixture.nativeElement.querySelector('input'); + }); + + it('should render calendar', () => { + showRangepicker(); + const calendar = overlay.querySelector('nb-calendar-range'); + expect(calendar).toBeTruthy(); + }); + + it('should not render overlay on load', () => { + const datepickerContainer = overlay.querySelector('nb-datepicker-container'); + expect(datepickerContainer).toBeNull(); + }); + + it('should render overlay lazily', () => { + const datepickerContainer = overlay.querySelector('nb-datepicker-container'); + expect(datepickerContainer).toBeNull(); + showRangepicker(); + const calendar = overlay.querySelector('nb-calendar-range'); + expect(calendar).toBeTruthy(); + }); + + it('should emit rangeChange when selected start date', (done) => { + rangepicker.visibleDate = new Date(2018, 8, 17); + showRangepicker(); + + rangepicker.rangeChange.subscribe((range: NbCalendarRange) => { + expect(range.start.getFullYear()).toEqual(2018); + expect(range.start.getMonth()).toEqual(8); + expect(range.start.getDate()).toEqual(1); + expect(range.end).not.toBeDefined(); + done(); + }); + + // click on Sep 1 + const startCell = overlay.querySelectorAll('.day-cell')[6]; + (startCell as HTMLElement).click(); + + fixture.detectChanges(); + }, 5000); + + it('should emit rangeChange when selected start and end dates', (done) => { + rangepicker.visibleDate = new Date(2018, 8, 17); + showRangepicker(); + + rangepicker.rangeChange + .pipe(skip(1)) + .subscribe((range: NbCalendarRange) => { + expect(range.start.getFullYear()).toEqual(2018); + expect(range.end.getFullYear()).toEqual(2018); + expect(range.start.getMonth()).toEqual(8); + expect(range.end.getMonth()).toEqual(8); + expect(range.start.getDate()).toEqual(1); + expect(range.end.getDate()).toEqual(3); + done(); + }); + + // click on Sep 1 + const startCell = overlay.querySelectorAll('.day-cell')[6]; + (startCell as HTMLElement).click(); + // click on Sep 3 + const endCell = overlay.querySelectorAll('.day-cell')[8]; + (endCell as HTMLElement).click(); + + fixture.detectChanges(); + }, 5000); + + it('should start from date typed into the input', () => { + input.value = 'Sep 17, 2018 - Sep 19, 2018'; + input.dispatchEvent(new Event('input')); + showRangepicker(); + appRef.tick(); + + const startCell = overlay.querySelector('.day-cell.in-range.start'); + const endCell = overlay.querySelector('.day-cell.in-range.end'); + + expect(startCell.textContent).toContain('17'); + expect(endCell.textContent).toContain('19'); + }); + + it('should start from current date if input is empty', () => { + showRangepicker(); + appRef.tick(); + expect(overlay.querySelector('.day-cell.today')).toBeDefined(); + }); + + it('should start from current date if input value is invalid', () => { + input.value = 'definitely not a date'; + input.dispatchEvent(new Event('input')); + showRangepicker(); + appRef.tick(); + expect(overlay.querySelector('.day-cell.today')).toBeDefined(); + }); + + it('should set visible date to start date if input value changed', () => { + const initialDate = new Date(2000, 0, 1); + rangepicker.visibleDate = initialDate; + + const date = 17; + const month = 8; + const year = 2018; + input.value = 'Sep 17, 2018 - Sep 19, 2018'; + input.dispatchEvent(new Event('input')); + appRef.tick(); + showRangepicker(); + + expect(rangepicker.visibleDate.getDate()).toEqual(date); + expect(rangepicker.visibleDate.getMonth()).toEqual(month); + expect(rangepicker.visibleDate.getFullYear()).toEqual(year); + }); + + it('should be valid if empty', () => { + expect(datepickerDirective.validate()).toBe(null); + }); + + it('should not be valid if empty contain incorrectly formatted date', () => { + input.value = 'somecurruptedinput'; + input.dispatchEvent(new Event('input')); + showRangepicker(); + + expect(datepickerDirective.validate()).not.toBe(null); + }); +});