Skip to content

Commit

Permalink
fix(datepicker): fixed viewed date if min max is set
Browse files Browse the repository at this point in the history
if no date is selected and min or max dates are excluding current month
show minimal or maximal provided date

fixes #3123 fixes #2711
  • Loading branch information
valorkin committed Nov 28, 2017
1 parent d9822f0 commit f3522ef
Showing 1 changed file with 83 additions and 55 deletions.
138 changes: 83 additions & 55 deletions src/datepicker/reducer/bs-datepicker.reducer.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,24 @@
// tslint:disable:max-file-line-count
import {
BsDatepickerState,
initialDatepickerState
} from './bs-datepicker.state';
import { BsDatepickerState, initialDatepickerState } from './bs-datepicker.state';
import { Action } from '../../mini-ngrx/index';
import { BsDatepickerActions } from './bs-datepicker.actions';
import { calcDaysCalendar } from '../engine/calc-days-calendar';
import { formatDaysCalendar } from '../engine/format-days-calendar';
import { flagDaysCalendar } from '../engine/flag-days-calendar';
import { shiftDate, setDate } from '../../bs-moment/utils/date-setters';
import { setDate, shiftDate } from '../../bs-moment/utils/date-setters';
import { canSwitchMode } from '../engine/view-mode';
import { formatMonthsCalendar } from '../engine/format-months-calendar';
import { flagMonthsCalendar } from '../engine/flag-months-calendar';
import {
formatYearsCalendar,
yearsPerCalendar
} from '../engine/format-years-calendar';
import { formatYearsCalendar, yearsPerCalendar } from '../engine/format-years-calendar';
import { flagYearsCalendar } from '../engine/flag-years-calendar';
import {
BsViewNavigationEvent,
DatepickerFormatOptions
} from '../models/index';
import { isArray, isDateValid } from '../../bs-moment/utils/type-checks';
import { BsViewNavigationEvent, DatepickerFormatOptions } from '../models/index';
import { isArray } from '../../bs-moment/utils/type-checks';
import { startOf } from '../../bs-moment/utils/start-end-of';
import { getLocale } from '../../bs-moment/locale/locales.service';
import { isAfter, isBefore } from '../../bs-moment/utils/date-compare';

export function bsDatepickerReducer(
state = initialDatepickerState,
action: Action
): BsDatepickerState {
export function bsDatepickerReducer(state = initialDatepickerState,
action: Action): BsDatepickerState {
switch (action.type) {
case BsDatepickerActions.CALCULATE: {
return calculateReducer(state);
Expand Down Expand Up @@ -59,7 +49,7 @@ export function bsDatepickerReducer(

const date = setDate(state.view.date, payload.unit);
const mode = payload.viewMode;
const newState = { view: { date, mode } };
const newState = {view: {date, mode}};

return Object.assign({}, state, newState);
}
Expand All @@ -70,13 +60,13 @@ export function bsDatepickerReducer(
}
const date = state.view.date;
const mode = action.payload;
const newState = { view: { date, mode } };
const newState = {view: {date, mode}};

return Object.assign({}, state, newState);
}

case BsDatepickerActions.HOVER: {
return Object.assign({}, state, { hoveredDate: action.payload });
return Object.assign({}, state, {hoveredDate: action.payload});
}

case BsDatepickerActions.SELECT: {
Expand All @@ -97,30 +87,52 @@ export function bsDatepickerReducer(

case BsDatepickerActions.SET_OPTIONS: {
const newState = action.payload;
// looks not really good
// preserve view mode
const mode = state.view.mode;
const _viewDate = newState.value && newState.value || state.view.date;
const date = getViewDate(_viewDate, newState.minDate, newState.maxDate);
newState.view = {mode, date};
// update selected value
if (newState.value) {
newState.view = state.view;
// if new value is array we work with date range
if (isArray(newState.value)) {
newState.view = {
mode: state.view.mode,
date: isDateValid(newState.value[0]) ? newState.value[0] : newState.view.date
};
newState.selectedRange = newState.value;
} else {
newState.view = {
mode: state.view.mode,
date: newState.value
};
}

// if new value is a date -> datepicker
if (newState.value instanceof Date) {
newState.selectedDate = newState.value;
}

// provided value is not supported :)
// need to report it somehow
}

// // looks not really good
// if (newState.value) {
// newState.view = state.view;
// if (isArray(newState.value)) {
// newState.view = {
// mode: state.view.mode,
// date: isDateValid(newState.value[0]) ? newState.value[0] : newState.view.date
// };
// newState.selectedRange = newState.value;
// } else {
// newState.view = {
// mode: state.view.mode,
// date: newState.value
// };
//
// newState.selectedDate = newState.value;
// }
// }

return Object.assign({}, state, newState);
}

// date range picker
case BsDatepickerActions.SELECT_RANGE: {
return Object.assign({}, state, { selectedRange: action.payload });
return Object.assign({}, state, {selectedRange: action.payload});
}

case BsDatepickerActions.SET_MIN_DATE: {
Expand Down Expand Up @@ -159,10 +171,10 @@ function calculateReducer(state: BsDatepickerState): BsDatepickerState {
viewDate,
state.monthViewOptions
);
viewDate = shiftDate(viewDate, { month: 1 });
viewDate = shiftDate(viewDate, {month: 1});
}

return Object.assign({}, state, { monthsModel });
return Object.assign({}, state, {monthsModel});
}

if (state.view.mode === 'month') {
Expand All @@ -177,10 +189,10 @@ function calculateReducer(state: BsDatepickerState): BsDatepickerState {
viewDate,
getFormatOptions(state)
);
viewDate = shiftDate(viewDate, { year: 1 });
viewDate = shiftDate(viewDate, {year: 1});
}

return Object.assign({}, state, { monthsCalendar });
return Object.assign({}, state, {monthsCalendar});
}

if (state.view.mode === 'year') {
Expand All @@ -196,25 +208,23 @@ function calculateReducer(state: BsDatepickerState): BsDatepickerState {
viewDate,
getFormatOptions(state)
);
viewDate = shiftDate(viewDate, { year: yearsPerCalendar });
viewDate = shiftDate(viewDate, {year: yearsPerCalendar});
}

return Object.assign({}, state, { yearsCalendarModel });
return Object.assign({}, state, {yearsCalendarModel});
}

return state;
}

function formatReducer(
state: BsDatepickerState,
action: Action
): BsDatepickerState {
function formatReducer(state: BsDatepickerState,
action: Action): BsDatepickerState {
if (state.view.mode === 'day') {
const formattedMonths = state.monthsModel.map((month, monthIndex) =>
formatDaysCalendar(month, getFormatOptions(state), monthIndex)
);

return Object.assign({}, state, { formattedMonths });
return Object.assign({}, state, {formattedMonths});
}

// how many calendars
Expand All @@ -235,10 +245,10 @@ function formatReducer(
viewDate,
getFormatOptions(state)
);
viewDate = shiftDate(viewDate, { year: 1 });
viewDate = shiftDate(viewDate, {year: 1});
}

return Object.assign({}, state, { monthsCalendar });
return Object.assign({}, state, {monthsCalendar});
}

if (state.view.mode === 'year') {
Expand All @@ -253,19 +263,17 @@ function formatReducer(
viewDate,
getFormatOptions(state)
);
viewDate = shiftDate(viewDate, { year: 16 });
viewDate = shiftDate(viewDate, {year: 16});
}

return Object.assign({}, state, { yearsCalendarModel });
return Object.assign({}, state, {yearsCalendarModel});
}

return state;
}

function flagReducer(
state: BsDatepickerState,
action: Action
): BsDatepickerState {
function flagReducer(state: BsDatepickerState,
action: Action): BsDatepickerState {
if (state.view.mode === 'day') {
const flaggedMonths = state.formattedMonths.map(
(formattedMonth, monthIndex) =>
Expand All @@ -281,7 +289,7 @@ function flagReducer(
})
);

return Object.assign({}, state, { flaggedMonths });
return Object.assign({}, state, {flaggedMonths});
}

if (state.view.mode === 'month') {
Expand All @@ -297,7 +305,7 @@ function flagReducer(
})
);

return Object.assign({}, state, { flaggedMonthsCalendar });
return Object.assign({}, state, {flaggedMonthsCalendar});
}

if (state.view.mode === 'year') {
Expand All @@ -313,7 +321,7 @@ function flagReducer(
})
);

return Object.assign({}, state, { yearsCalendarFlagged });
return Object.assign({}, state, {yearsCalendarFlagged});
}

return state;
Expand All @@ -333,3 +341,23 @@ function getFormatOptions(state: BsDatepickerState): DatepickerFormatOptions {
weekNumbers: state.weekNumbers
};
}

/**
* if view date is provided (bsValue|ngModel) it should be shown
* if view date is not provider:
* if minDate>currentDate (default view value), show minDate
* if maxDate<currentDate(default view value) show maxDate
*/
function getViewDate(viewDate: Date | Date[], minDate: Date, maxDate: Date) {
const _date = Array.isArray(viewDate) ? viewDate[0] : viewDate;

if (minDate && isAfter(minDate, _date, 'day')) {
return minDate;
}

if (maxDate && isBefore(maxDate, _date, 'day')) {
return maxDate;
}

return _date;
}

0 comments on commit f3522ef

Please sign in to comment.