valor-software/angular2-bootstrap

View on GitHub
src/datepicker/reducer/bs-datepicker.effects.ts

Summary

Maintainability
F
3 days
Test Coverage
import { Injectable } from '@angular/core';
import 'rxjs/add/operator/filter';
import 'rxjs/add/operator/map';
import { Observable } from 'rxjs/Observable';
import { getFullYear, getMonth } from '../../chronos/utils/date-getters';
import { BsDatepickerAbstractComponent } from '../base/bs-datepicker-container';
import { BsDatepickerConfig } from '../bs-datepicker.config';
import {
  BsDatepickerViewMode,
  BsNavigationEvent,
  CalendarCellViewModel,
  CellHoverEvent,
  DatepickerRenderOptions,
  DaysCalendarViewModel,
  DayViewModel,
  MonthsCalendarViewModel,
  YearsCalendarViewModel
} from '../models/index';
import { BsDatepickerActions } from './bs-datepicker.actions';
import { BsDatepickerStore } from './bs-datepicker.store';
import { Subscription } from 'rxjs/Subscription';
import { BsLocaleService } from '../bs-locale.service';

@Injectable()
export class BsDatepickerEffects {
  viewMode: Observable<BsDatepickerViewMode>;
  daysCalendar: Observable<DaysCalendarViewModel[]>;
  monthsCalendar: Observable<MonthsCalendarViewModel[]>;
  yearsCalendar: Observable<YearsCalendarViewModel[]>;
  options: Observable<DatepickerRenderOptions>;

  private _store: BsDatepickerStore;
  private _subs: Subscription[] = [];

  constructor(private _actions: BsDatepickerActions,
              private _localeService: BsLocaleService) {}

  init(_bsDatepickerStore: BsDatepickerStore): BsDatepickerEffects {
    this._store = _bsDatepickerStore;

    return this;
  }

  /** setters */

  setValue(value: Date): void {
    this._store.dispatch(this._actions.select(value));
  }

  setRangeValue(value: Date[]): void {
    this._store.dispatch(this._actions.selectRange(value));
  }

  setMinDate(value: Date): BsDatepickerEffects {
    this._store.dispatch(this._actions.minDate(value));

    return this;
  }

  setMaxDate(value: Date): BsDatepickerEffects {
    this._store.dispatch(this._actions.maxDate(value));

    return this;
  }

  setDisabled(value: boolean): BsDatepickerEffects {
    this._store.dispatch(this._actions.isDisabled(value));

    return this;
  }

  /* Set rendering options */
  setOptions(_config: BsDatepickerConfig): BsDatepickerEffects {
    const _options = Object.assign({locale: this._localeService.currentLocale}, _config);
    this._store.dispatch(this._actions.setOptions(_options));

    return this;
  }

  /** view to mode bindings */
  setBindings(container: BsDatepickerAbstractComponent): BsDatepickerEffects {
    container.daysCalendar = this._store
      .select(state => state.flaggedMonths)
      .filter(months => !!months);

    // month calendar
    container.monthsCalendar = this._store
      .select(state => state.flaggedMonthsCalendar)
      .filter(months => !!months);

    // year calendar
    container.yearsCalendar = this._store
      .select(state => state.yearsCalendarFlagged)
      .filter(years => !!years);

    container.viewMode = this._store.select(state => state.view.mode);

    container.options = this._store
      .select(state => state.showWeekNumbers)
      .map(showWeekNumbers => ({showWeekNumbers}));

    return this;
  }

  /** event handlers */
  setEventHandlers(container: BsDatepickerAbstractComponent): BsDatepickerEffects {
    container.setViewMode = (event: BsDatepickerViewMode): void => {
      this._store.dispatch(this._actions.changeViewMode(event));
    };

    container.navigateTo = (event: BsNavigationEvent): void => {
      this._store.dispatch(this._actions.navigateStep(event.step));
    };

    container.dayHoverHandler = (event: CellHoverEvent): void => {
      const _cell = event.cell as DayViewModel;
      if (_cell.isOtherMonth || _cell.isDisabled) {
        return;
      }

      this._store.dispatch(this._actions.hoverDay(event));
      _cell.isHovered = event.isHovered;
    };

    container.monthHoverHandler = (event: CellHoverEvent): void => {
      event.cell.isHovered = event.isHovered;
    };

    container.yearHoverHandler = (event: CellHoverEvent): void => {
      event.cell.isHovered = event.isHovered;
    };

    /** select handlers */
    // container.daySelectHandler = (day: DayViewModel): void => {
    //   if (day.isOtherMonth || day.isDisabled) {
    //     return;
    //   }
    //   this._store.dispatch(this._actions.select(day.date));
    // };

    container.monthSelectHandler = (event: CalendarCellViewModel): void => {
      if (event.isDisabled) {
        return;
      }
      this._store.dispatch(
        this._actions.navigateTo({
          unit: {month: getMonth(event.date)},
          viewMode: 'day'
        })
      );
    };

    container.yearSelectHandler = (event: CalendarCellViewModel): void => {
      if (event.isDisabled) {
        return;
      }
      this._store.dispatch(
        this._actions.navigateTo({
          unit: {year: getFullYear(event.date)},
          viewMode: 'month'
        })
      );
    };

    return this;
  }

  registerDatepickerSideEffects(): BsDatepickerEffects {
    this._subs.push(
      this._store.select(state => state.view).subscribe(view => {
        this._store.dispatch(this._actions.calculate());
      })
    );

    // format calendar values on month model change
    this._subs.push(
      this._store
        .select(state => state.monthsModel)
        .filter(monthModel => !!monthModel)
        .subscribe(month => this._store.dispatch(this._actions.format()))
    );

    // flag day values
    this._subs.push(
      this._store
        .select(state => state.formattedMonths)
        .filter(month => !!month)
        .subscribe(month => this._store.dispatch(this._actions.flag()))
    );

    // flag day values
    this._subs.push(
      this._store
        .select(state => state.selectedDate)
        .filter(selectedDate => !!selectedDate)
        .subscribe(selectedDate => this._store.dispatch(this._actions.flag()))
    );

    // flag for date range picker
    this._subs.push(
      this._store
        .select(state => state.selectedRange)
        .filter(selectedRange => !!selectedRange)
        .subscribe(selectedRange => this._store.dispatch(this._actions.flag()))
    );

    // monthsCalendar
    this._subs.push(
      this._store
        .select(state => state.monthsCalendar)
        .subscribe(() => this._store.dispatch(this._actions.flag()))
    );

    // years calendar
    this._subs.push(
      this._store
        .select(state => state.yearsCalendarModel)
        .filter(state => !!state)
        .subscribe(() => this._store.dispatch(this._actions.flag()))
    );

    // on hover
    this._subs.push(
      this._store
        .select(state => state.hoveredDate)
        .filter(hoveredDate => !!hoveredDate)
        .subscribe(hoveredDate => this._store.dispatch(this._actions.flag()))
    );

    // on locale change
    this._subs.push(
      this._localeService.localeChange
        .subscribe(locale => this._store.dispatch(this._actions.setLocale(locale)))
    )

    return this;
  }

  destroy(): void {
    for (const sub of this._subs) {
      sub.unsubscribe();
    }
  }
}