import { Injectable } from '@angular/core' ; import { CalendarDay , InCalendarPicker } from './interfaces/calendar-entities' ; import { CalendarPeriodRelativityEnum } from './enums/calendar-period-relativity.enum' ; import { DateRange } from './interfaces/date-range' ; import * as momentNs from 'moment' ; const moment = momentNs ; @ Injectable ( ) export class CalendarManagerService { constructor ( ) { } private locale = 'en' ; private previouslySelectedYear = moment ( ) ; setLocale ( locale ) { moment . locale ( locale ) ; this . locale = locale ; } generateCalendarForMonth ( startDate , currentMonth , selectedDates , dateRange ) { const monthStart = moment ( startDate ) . startOf ( 'month' ) . locale ( this . locale ) ; const isStartOfChosenMonthTheFirstDayOfTable = ( monthStart . weekday ( ) === 0 ) ; const dateIterator = monthStart . clone ( ) ; const calendar = [ ] ; let tableRow = [ ] ; let newDate ; if ( ! isStartOfChosenMonthTheFirstDayOfTable ) { let daysToGoBack = dateIterator . weekday ( ) ; daysToGoBack = ( daysToGoBack === 0 ) ? 1 : daysToGoBack ; dateIterator . subtract ( daysToGoBack , 'days' ) ; } while ( calendar . length < 6 ) { newDate = { displayDate : dateIterator . format ( 'D' ) , momentObj : dateIterator . clone ( ) , relativityToCurrentMonth : this . determineDateRelativityToCurrentMonth ( dateIterator , currentMonth ) , isDisabled : this . determineIfDateIsDisabled ( dateIterator , dateRange . minDate , dateRange . maxDate ) , isSelected : this . getSelectedItemIndex ( dateIterator , selectedDates ) > - 1 } ; if ( tableRow . length <= 6 ) { tableRow . push ( newDate ) ; } else { calendar . push ( tableRow ) ; tableRow = [ newDate ] ; } dateIterator . add ( 1 , 'day' ) ; } return calendar ; } generateMonthPickerCollection ( currentYear , dateRange ) { const months = this . getMonths ( ) ; return months . map ( ( monthName , index ) => { const date = moment ( ) . year ( currentYear ) . month ( index ) ; return { displayName : monthName , momentObj : date , isDisabled : this . determineIfDateIsDisabled ( date , dateRange . minDate , dateRange . maxDate ) } ; } ) ; } generateYearPickerCollection ( start , margin = 19 , dateRange ) { const yearsList = this . getYearList ( start , margin ) ; return yearsList . map ( ( year ) => { const date = moment ( ) . year ( year ) ; return { displayName : year . toString ( ) , momentObj : date , isDisabled : this . determineIfDateIsDisabled ( date , dateRange . minDate , dateRange . maxDate ) } ; } ) ; } getWeekdays ( short = true ) { return short ? moment . weekdaysShort ( true ) : moment . weekdays ( true ) ; } getMonths ( short = true ) { return short ? moment . monthsShort ( ) : moment . months ( ) ; } getYearList ( start , margin = 19 ) { let yearIterator ; let endYear ; if ( start ) { this . previouslySelectedYear = start . clone ( ) ; } if ( margin < 0 ) { endYear = moment ( this . previouslySelectedYear ) . add ( margin , 'years' ) ; yearIterator = moment ( endYear ) . add ( margin , 'years' ) ; } else { yearIterator = moment ( this . previouslySelectedYear ) ; endYear = moment ( yearIterator ) . add ( margin , 'years' ) ; } const yearList = [ ] ; while ( yearIterator . isSameOrBefore ( endYear ) ) { yearList . push ( yearIterator . clone ( ) . year ( ) ) ; yearIterator . add ( 1 , 'year' ) ; } this . previouslySelectedYear = yearIterator . subtract ( 1 , 'year' ) . clone ( ) ; return yearList ; } findADateFromCalendar ( date , calendarTable ) { const dateToFind = moment ( date ) ; const flatCalendarTable = calendarTable . reduce ( ( acc , val ) => acc . concat ( val ) , [ ] ) ; return flatCalendarTable . find ( ( calendarDay ) => { return calendarDay . momentObj . isSame ( dateToFind , 'day' ) ; } ) ; } getSelectedItemIndex ( date , selectedDates ) { return selectedDates . findIndex ( ( selectedDate ) => { return moment ( selectedDate ) . isSame ( date , 'day' ) ; } ) ; } determineIfDateIsDisabled ( currentDate , minDate , maxDate ) { const isAfterMaxDate = maxDate && moment ( currentDate ) . isAfter ( maxDate , 'day' ) ; const isBeforeMinDate = minDate && moment ( currentDate ) . isBefore ( minDate , 'day' ) ; return < boolean > ( isAfterMaxDate || isBeforeMinDate ) ; } determineDateRelativityToCurrentMonth ( date , currentMonth ) { const startOfCurrentMonth = moment ( currentMonth ) . startOf ( 'month' ) ; const endOfCurrentMonth = moment ( currentMonth ) . endOf ( 'month' ) ; if ( moment ( date ) . isBefore ( startOfCurrentMonth ) ) { return CalendarPeriodRelativityEnum . Before ; } if ( moment ( date ) . isAfter ( endOfCurrentMonth ) ) { return CalendarPeriodRelativityEnum . After ; } return CalendarPeriodRelativityEnum . Current ; } sortDatesAsc ( dates ) { return dates . sort ( ( date1 , date2 ) => { if ( moment ( date1 ) . isAfter ( date2 ) ) { return 1 ; } else { return - 1 ; } } ) ; } }