import moment from 'moment-timezone';
import Configuration from 'common/src/app/config/Configuration';
import MonthNumber from '../data/enum/MonthNumber';
import { YYYYMMDD } from '../data/enum/dateFormats';
/**
* This util includes a set of functions which populate the date select filters on
* the weigh history page
*/
const allMonths = Object.entries(MonthNumber);
/**
* Returns all 12 month options in assending order but disables the ones the
* user cannot choose based on available months.
* @param {array.object} availableMonths Is the result of the getAvailableMonths function.
* It is an array of objects which includes year, month, month and yearcombined and utc date.
* @returns {array.object} An array of objects that can passed into the select component
* to a select with all 12 months displayed but some disabled.
*/
export const filterMonths = availableMonths => {
const justMonths = availableMonths.map(monthYear => monthYear.month);
return allMonths.map(month => ({
title: `${month[1]}`,
value: month[0].toString().padStart(2, '0'),
disabled: !justMonths.includes(parseInt(month[0], 10)),
}));
};
/**
* Returns all 12 month options, populating the select component. Allowing
* the user to select any month to filter by
* @returns {array.object} An array of objects that can passed into the select component
* to create a select with all 12 months.
* Heres an example of the structure of the option object
* @example {title: May, value: "5"}
*/
export const getAllMonths = () =>
allMonths.map(month => ({ title: `${month[1]}`, value: month[0] }));
export const loadMonthOptions = (yearSelected, userJoinDate) => {
let endDate;
if (moment(`${yearSelected}-01-01`).isSame(moment(), 'year')) {
endDate = moment();
} else if (moment(`${yearSelected}-01-01`).isSame(moment(userJoinDate), 'year')) {
endDate = moment(`${yearSelected}-01-01`).endOf('year');
} else {
endDate = moment().endOf('year');
}
if (moment(`${yearSelected}-01-01`).isSame(userJoinDate, 'year')) {
return filterMonths(getAvailableMonths(userJoinDate, endDate));
}
return filterMonths(getAvailableMonths(moment().startOf('year'), endDate));
};
/**
* Returns available years that can be selected, ordering them most recent first
* @returns {array.object} An array of objects that can passed into the select component
* which displays the years a user can filter by
* Heres an example of the structure of the option object
* @example {title: May 2018, value: "2018-05-05T00:00:00+01:00"}
*/
export const loadYearsOptions = userJoinDate => {
// Get the years a user has been a member sort by most recent and pass to select
const availableYears = getYearsSince(userJoinDate, moment().format());
const yearOptions = availableYears
.sort((a, b) => b - a)
.map(year => ({ title: year.toString(), value: year.toString() }));
return yearOptions;
};
/**
* Returns number of weeks in a given month
* @param {string} month
* @returns {number} number of weeks in a month
* @example 5
*/
export const getNumWeeksInMonth = utc =>
moment.duration(moment(utc).endOf('month') - moment(utc).startOf('month')).weeks() + 1;
/**
* Returns number of week number in month
* @param {number} week number in year (e.g 37)
* @returns {number} number of the week relative to the month
* @example 3
*/
export const findWeekNumberInMonth = week =>
moment(week).week() -
moment(week)
.startOf('month')
.week();
/**
* Returns the months between two dates
* @function
* @param {object} startDate Moment date
* @param {object} endDate Moment date
* @return {array.object} An array of objects which include year, month
* year and month combined and utc date
*/
export const getAvailableMonths = (startDate, endDate) => {
const availableMonthObject = date => ({
month: parseInt(moment(date).format('M'), 10),
year: date.format('YYYY'),
date,
});
// If equal to the first of that year just return january
const availableMonths = [];
if (startDate === endDate) {
availableMonths.push(availableMonthObject(startDate));
} else {
const formattedEndDate = moment(endDate);
const formattedStartDate = moment(startDate);
while (
formattedEndDate > formattedStartDate ||
formattedStartDate.format('M') === formattedEndDate.format('M')
) {
availableMonths.push(availableMonthObject(formattedStartDate));
formattedStartDate.add(1, 'month');
}
}
return availableMonths;
};
/**
* Returns the years that two date span over
* @function
* @param {object} startDate Moment date
* @param {object} endDate Moment date
* @return {array.number} An array of years
* @example Passing in start date of 2017 and end date of 2019 would return [2017, 2018, 2019]
*/
export const getYearsSince = (startDate, endDate) => {
const formatStartYear = parseInt(moment(startDate).format('YYYY'), 10);
const formatEndYear = parseInt(moment(endDate).format('YYYY'), 10);
const yearDiff = formatEndYear - formatStartYear;
const availableYears = [];
availableYears.push(formatStartYear);
let value = 0;
while (value < yearDiff) {
value += 1;
const year = formatStartYear + value;
availableYears.push(year);
}
return availableYears;
};
/**
* When using moment to format days which get sent off as parameters to an API it expects them
* to be in the format
**/
export const apiDayDateFormat = YYYYMMDD;
/**
* Returns true if a date or time is in the future
* Will default to market config if no format is passed in
* todo: SWO-4930 update Configuration.dateFormat to return a ISO or RFC2822 value
* @function
* @param {string} startDate Moment date
* @param {string} moment format e.g 'YYYY-MM-DD'
* @return {boolean}
*/
export const isBeforeOrAfter = (dateToCheck, format) => {
const formatRule = format || Configuration.dateFormat;
const now = moment().format(formatRule);
return moment(now).isBefore(moment(dateToCheck).format(formatRule));
};
/**
* Returns true if date is the same or before the current date
* @function
* @param {string} date Date you want to compare againist the current date
* @return {boolean}
*/
export const isPastOrCurrentDate = date =>
moment(date).isBefore(moment(), 'day') || moment(date).isSame(moment(), 'day');
/**
* Returns true if the date passed in is on the start or end date or inbetween it
* @function
* @param {string} date Date you want to check is within the date range
* @param {object} dateRange The range in which you want to check the date is within
* this must have a end & start date within
* @return {boolean}
*/
export const isWithinDateRange = (dateRange, date) => {
const { end, start } = dateRange;
const momentDate = moment(date);
return (
momentDate.isSame(start, 'd') || momentDate.isSame(end, 'd') || momentDate.isBetween(start, end)
);
};
/**
* Takes day as a number and returns text string
* @function
* @example given 4, will return "Thursday"
*/
export const getWeekName = dayNumber =>
moment()
.weekday(dayNumber)
.format('dddd');
/**
* Takes a date and returns how many days have past
* @param date
* @returns {number}
*/
export function daysSince(days) {
return moment.utc().diff(moment.utc(days), 'days');
}
/**
* Format weekday as the name of the day of the week
* e.g. 2 becomes Tuesday
*/
export const getDayName = numericWeighInDay =>
numericWeighInDay || numericWeighInDay === 0
? moment()
.weekday(numericWeighInDay)
.format('dddd')
: null;
/**
* Add ordinal to the day digit
*/
const getOrdinalNum = n =>
n + ['st', 'nd', 'rd'][(((((n < 0 ? -n : n) + 90) % 100) - 10) % 10) - 1] || `${n}th`;
/**
* Show the Ordinal date for example: 12th Mar, 3rd Jun etc etc
*
* @param theDate
* @returns {string}
*/
export const getOrdinalDate = theDate => {
const date = new Date(theDate);
const formatDay = getOrdinalNum(date.getDate());
const formatMonth = date.toLocaleDateString('en-GB', {
month: 'short',
});
return `${formatDay} ${formatMonth}`;
};
/**
* Check for showing NOW or the fromDate
*
* @param from
* @param until
* @returns {boolean|boolean}
*/
export const isNowDate = (from, until) => {
const fromDate = Date.parse(from);
const untilDate = Date.parse(until);
const nowDate = Date.now();
return nowDate >= fromDate && nowDate <= untilDate;
};