@spaced-out/ui-design-system
Version:
Sense UI components library
361 lines (348 loc) • 13 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.wrangleMoment = exports.makeKey = exports.isValid = exports.isStartOfRange = exports.isStartDateEndDateSame = exports.isSameOrBefore = exports.isSameOrAfter = exports.isSame = exports.isEndOfRange = exports.isBetween = exports.isBefore = exports.isAfter = exports.inDateRange = exports.getValidDates = exports.getTranslation = exports.getTimezones = exports.getSubtractedDate = exports.getMonths = exports.getMonthEndDate = exports.getFormattedDate = exports.getDaysInMonth = exports.getDateRangePickerErrors = exports.getAvailableMonths = exports.getAddedDate = exports.generateAvailableYears = exports.formatIsoDate = exports.checkRangeValidity = exports.WEEKDAYS = exports.NAVIGATION_ACTION = exports.MARKERS = void 0;
var _parseISO = _interopRequireDefault(require("date-fns/parseISO"));
var _invariant = _interopRequireDefault(require("invariant"));
var _lodash = require("lodash");
var _moment = _interopRequireDefault(require("moment"));
var _timezones = require("./timezones");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
// $FlowFixMe - strict types for date-fns
// $FlowFixMe[untyped-import]
const makeKey = value => {
try {
if (value && typeof value === 'string') {
return value.replace(/\(s\)/gi, '_s') // Replace (s) with _s (case-insensitive)
.replace(/[^\w\s']/g, '') // Remove special chars except apostrophes
.replace(/\s+/g, '_') // Spaces → underscores
.replace(/_+/g, '_') // Collapse multiple ____ into _
.replace(/^_|_$/g, ''); // Trim leading/trailing _
}
return value;
} catch {
return value;
}
};
exports.makeKey = makeKey;
const NAVIGATION_ACTION = exports.NAVIGATION_ACTION = Object.freeze({
NEXT: 'next',
PREV: 'prev'
});
const MARKERS = exports.MARKERS = Object.freeze({
DATE_RANGE_START: 'FIRST',
DATE_RANGE_END: 'SECOND'
});
const WEEKDAYS = exports.WEEKDAYS = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];
const getMonths = t => [{
key: '0',
label: getTranslation(t, 'Jan')
}, {
key: '1',
label: getTranslation(t, 'Feb')
}, {
key: '2',
label: getTranslation(t, 'Mar')
}, {
key: '3',
label: getTranslation(t, 'Apr')
}, {
key: '4',
label: getTranslation(t, 'May')
}, {
key: '5',
label: getTranslation(t, 'Jun')
}, {
key: '6',
label: getTranslation(t, 'Jul')
}, {
key: '7',
label: getTranslation(t, 'Aug')
}, {
key: '8',
label: getTranslation(t, 'Sep')
}, {
key: '9',
label: getTranslation(t, 'Oct')
}, {
key: '10',
label: getTranslation(t, 'Nov')
}, {
key: '11',
label: getTranslation(t, 'Dec')
}];
exports.getMonths = getMonths;
const getDateRangePickerErrors = t => ({
MIN_MAX_INVALID: {
type: 'MIN_MAX_INVALID',
description: getTranslation(t, 'Given minDate and maxDate are invalid.')
},
START_DATE_EARLY: {
type: 'START_DATE_EARLY',
description: getTranslation(t, 'Given startDate can not come before minDate.')
},
START_DATE_LATE: {
type: 'START_DATE_LATE',
description: getTranslation(t, 'Given startDate can not come after endDate.')
},
END_DATE_LATE: {
type: 'END_DATE_LATE',
description: getTranslation(t, 'Given endDate can not come after maxDate.')
}
});
exports.getDateRangePickerErrors = getDateRangePickerErrors;
const checkRangeValidity = (rangeStart, rangeEnd, errorBody, onError) => {
const isRangeStartValid = isValid(rangeStart);
const isRangeEndValid = isRangeStartValid && isValid(rangeEnd);
const isRangeValid = isRangeEndValid && isSameOrBefore(rangeStart, rangeEnd);
(0, _invariant.default)(isRangeValid, JSON.stringify(errorBody));
if (!isRangeValid) {
onError?.(errorBody);
}
return isRangeValid;
};
exports.checkRangeValidity = checkRangeValidity;
const wrangleMoment = date => {
if (date instanceof Date) {
return date;
} else if (!date) {
return new Date();
}
return date instanceof _moment.default ? date.toDate() : (0, _parseISO.default)(date);
};
exports.wrangleMoment = wrangleMoment;
const formatIsoDate = function (date) {
let format = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'YYYY-MM-DD';
return _moment.default.utc(date).format(format);
};
exports.formatIsoDate = formatIsoDate;
const isStartOfRange = (_ref, date) => {
let {
startDate
} = _ref;
return Boolean(startDate) && _moment.default.utc(date).isSame(_moment.default.utc(startDate), 'd');
};
exports.isStartOfRange = isStartOfRange;
const isEndOfRange = (_ref2, date) => {
let {
endDate
} = _ref2;
return Boolean(endDate) && _moment.default.utc(date).isSame(_moment.default.utc(endDate), 'd');
};
exports.isEndOfRange = isEndOfRange;
const inDateRange = (_ref3, date) => {
let {
startDate,
endDate
} = _ref3;
if (startDate && endDate) {
const momentDay = _moment.default.utc(date);
const momentStartDate = _moment.default.utc(startDate);
const momentEndDate = _moment.default.utc(endDate);
return isBetween(momentDay, momentStartDate, momentEndDate);
}
return false;
};
exports.inDateRange = inDateRange;
const isStartDateEndDateSame = _ref4 => {
let {
startDate,
endDate
} = _ref4;
if (startDate && endDate) {
return _moment.default.utc(startDate).isSame(_moment.default.utc(endDate), 'd');
}
return false;
};
exports.isStartDateEndDateSame = isStartDateEndDateSame;
const getMonthAndYear = date => {
const momentDate = date ? _moment.default.utc(date) : _moment.default.utc();
return [momentDate.month(), momentDate.year()];
};
const getDaysInMonth = date => {
const startWeek = _moment.default.utc(date).startOf('month').startOf('week');
const endWeek = _moment.default.utc(date).endOf('month').endOf('week');
const days = [],
current = startWeek;
while (isBefore(current, endWeek)) {
days.push(current.clone().format('YYYY-MM-DD'));
current.add(1, 'd');
}
const daysInChunks = (0, _lodash.chunk)(days, 7);
// if total rows in calendar are 5 add one more week to the calendar
if (daysInChunks.length === 5) {
const nextWeek = getAddedDate(endWeek, WEEKDAYS.length, 'd');
const extraDays = [];
while (isSameOrBefore(current, nextWeek)) {
extraDays.push(current.clone().format('YYYY-MM-DD'));
current.add(1, 'd');
}
daysInChunks.push(extraDays);
}
return daysInChunks;
};
exports.getDaysInMonth = getDaysInMonth;
const getAddedDate = (date, addCount, timeUnit) => formatIsoDate(_moment.default.utc(date).add(addCount, timeUnit));
exports.getAddedDate = getAddedDate;
const getSubtractedDate = (date, subtractCount, timeUnit) => formatIsoDate(_moment.default.utc(date).subtract(subtractCount, timeUnit));
exports.getSubtractedDate = getSubtractedDate;
const getMonthEndDate = date => formatIsoDate(_moment.default.utc(date).endOf('M'));
exports.getMonthEndDate = getMonthEndDate;
const getTimezones = t => Object.keys(_timezones.TIMEZONES).reduce((menuOptions, key) => {
menuOptions.push({
key,
label: getTranslation(t, _timezones.TIMEZONES[key])
});
return menuOptions;
}, []);
exports.getTimezones = getTimezones;
const generateAvailableYears = _ref5 => {
let {
marker,
minDate,
maxDate,
rangeStartMonth,
rangeEndMonth
} = _ref5;
const rangeStartYear = _moment.default.utc(rangeStartMonth).year();
const rangeEndYear = _moment.default.utc(rangeEndMonth).year();
const isWithinRange = year => marker === MARKERS.DATE_RANGE_START ? year <= rangeEndYear : year >= rangeStartYear;
return (0, _lodash.range)(_moment.default.utc(minDate).year(), _moment.default.utc(maxDate).year() + 1).filter(year => isWithinRange(year)).map(year => ({
key: year.toString(),
label: year.toString()
}));
};
exports.generateAvailableYears = generateAvailableYears;
const getAvailableMonths = _ref6 => {
let {
marker,
minDate,
maxDate,
rangeStartMonth,
rangeEndMonth,
t
} = _ref6;
const [rangeStartMonthKey, rangeStartYear] = getMonthAndYear(rangeStartMonth);
const [rangeEndMonthKey, rangeEndYear] = getMonthAndYear(rangeEndMonth);
const [minDateMonth, minDateYear] = getMonthAndYear(minDate);
const [maxDateMonth, maxDateYear] = getMonthAndYear(maxDate);
const MONTHS = getMonths(t);
return MONTHS.filter(month => {
const isSameYear = rangeStartYear === rangeEndYear;
const isFirstAndMinDateYearSame = rangeStartYear === minDateYear;
const isSecondAndMaxDateYearSame = rangeEndYear === maxDateYear;
if (marker === MARKERS.DATE_RANGE_START) {
if (isSameYear && month.key >= rangeEndMonthKey) {
return false;
} else if (isFirstAndMinDateYearSame && month.key < minDateMonth) {
return false;
} else {
return true;
}
} else {
if (isSameYear && month.key <= rangeStartMonthKey) {
return false;
} else if (isSecondAndMaxDateYearSame && month.key > maxDateMonth) {
return false;
} else {
return true;
}
}
});
};
exports.getAvailableMonths = getAvailableMonths;
const getValidDates = _ref7 => {
let {
selectedDateRange,
minDate,
maxDate,
today,
onError,
t
} = _ref7;
const {
startDate,
endDate
} = selectedDateRange;
const validMaxDate = maxDate && !(0, _lodash.isEmpty)(maxDate) ? maxDate : today;
const validMinDate = minDate && !(0, _lodash.isEmpty)(minDate) ? minDate : getSubtractedDate(today, 8, 'y');
const isRangeValid = (min, max, errorMessage) => checkRangeValidity(min, max, errorMessage, onError);
// minDate should be after maxDate
const isMinMaxRangeInvalid = !isRangeValid(validMinDate, validMaxDate, getDateRangePickerErrors(t).MIN_MAX_INVALID);
// if startDate is defined and then it should be after minDate
const isStartDateInvalid = isMinMaxRangeInvalid || (0, _lodash.isEmpty)(startDate) || !isRangeValid(validMinDate, startDate, getDateRangePickerErrors(t).START_DATE_EARLY);
if (isMinMaxRangeInvalid || isStartDateInvalid) {
return {
validDateRange: {
startDate: null,
endDate: null
},
validMinDate,
validMaxDate
};
}
// if endDate is defined then it should be before maxDate
const isEndDateInvalid = (0, _lodash.isEmpty)(endDate) || !isRangeValid(endDate, validMaxDate, getDateRangePickerErrors(t).END_DATE_LATE);
// startDate should be before endDate
const isStartEndRangeInvalid = isEndDateInvalid || !isRangeValid(startDate, endDate, getDateRangePickerErrors(t).START_DATE_LATE);
if (isEndDateInvalid || isStartEndRangeInvalid) {
return {
validDateRange: {
startDate,
endDate: null
},
validMinDate,
validMaxDate
};
}
return {
validDateRange: {
startDate: (0, _lodash.isEmpty)(startDate) ? null : startDate,
endDate: (0, _lodash.isEmpty)(endDate) ? null : endDate
},
validMinDate,
validMaxDate
};
};
// If date1 is same as date2 w.r.t the unit passed
exports.getValidDates = getValidDates;
const isSame = (date1, date2, unit) => _moment.default.utc(date1).isSame(_moment.default.utc(date2), unit);
// If date1 is before date2
exports.isSame = isSame;
const isBefore = (date1, date2) => _moment.default.utc(date1).isBefore(_moment.default.utc(date2));
// If date1 is after date2 w.r.t the unit passed
exports.isBefore = isBefore;
const isAfter = (date1, date2) => _moment.default.utc(date1).isAfter(_moment.default.utc(date2));
// If date1 is same or before date2 w.r.t the unit passed
exports.isAfter = isAfter;
const isSameOrBefore = (date1, date2, unit) => _moment.default.utc(date1).isSameOrBefore(_moment.default.utc(date2), unit);
// If date1 is same or after date2 w.r.t the unit passed
exports.isSameOrBefore = isSameOrBefore;
const isSameOrAfter = (date1, date2, unit) => _moment.default.utc(date1).isSameOrAfter(_moment.default.utc(date2), unit);
// If date is between startRange and endRange
exports.isSameOrAfter = isSameOrAfter;
const isBetween = (date, startRange, endRange) => _moment.default.utc(date).isBetween(_moment.default.utc(startRange), _moment.default.utc(endRange), null, '[]');
// If the date results in a date that exists in the calendar
exports.isBetween = isBetween;
const isValid = date => _moment.default.utc(date).isValid();
exports.isValid = isValid;
const getFormattedDate = (marker, dateRange, locale) => {
const {
startDate,
endDate
} = dateRange;
// set locale if provided
if (locale) {
_moment.default.locale(locale);
}
switch (marker) {
case MARKERS.DATE_RANGE_START:
return startDate ? _moment.default.utc(startDate).format('MMM DD, YYYY') : 'MMM DD, YYYY';
default:
return endDate ? _moment.default.utc(endDate).format('MMM DD, YYYY') : 'MMM DD, YYYY';
}
};
exports.getFormattedDate = getFormattedDate;
const getTranslation = (t, labelToTranslate) => t ? t(makeKey(labelToTranslate), labelToTranslate) : labelToTranslate;
exports.getTranslation = getTranslation;