239 lines
7.4 KiB
JavaScript
239 lines
7.4 KiB
JavaScript
/** @format */
|
|
/**
|
|
* External dependencies
|
|
*/
|
|
import moment from 'moment';
|
|
import { find } from 'lodash';
|
|
import { __ } from '@wordpress/i18n';
|
|
|
|
/**
|
|
* Internal dependencies
|
|
*/
|
|
import { presetValues } from 'components/date-picker/preset-periods';
|
|
import { compareValues } from 'components/date-picker/compare-periods';
|
|
|
|
/**
|
|
* DateValue Object
|
|
*
|
|
* @typedef {Object} DateValue - Describes the date range supplied by the date picker.
|
|
* @property {string} label - The translated value of the period.
|
|
* @property {string} range - The human readable value of a date range.
|
|
* @property {moment.Moment} start - Start of the date range.
|
|
* @property {moment.Moment} end - End of the date range.
|
|
*/
|
|
|
|
export const isoDateFormat = 'YYYY-MM-DD';
|
|
|
|
/**
|
|
* Convert a string to Moment object
|
|
*
|
|
* @param {string} format - localized date string format
|
|
* @param {string} str - date string
|
|
* @return {Moment|null} - Moment object representing given string
|
|
*/
|
|
export function toMoment( format, str ) {
|
|
if ( moment.isMoment( str ) ) {
|
|
return str.isValid() ? str : null;
|
|
}
|
|
if ( 'string' === typeof str ) {
|
|
const date = moment( str, [ isoDateFormat, format ], true );
|
|
return date.isValid ? date : null;
|
|
}
|
|
throw new Error( 'toMoment requires a string to be passed as an argument' );
|
|
}
|
|
|
|
/**
|
|
* Given two dates, derive a string representation
|
|
*
|
|
* @param {Moment} start - start date
|
|
* @param {Moment} end - end date
|
|
* @return {string} - text value for the supplied date range
|
|
*/
|
|
function getRangeLabel( start, end ) {
|
|
const isSameDay = start.isSame( end, 'day' );
|
|
const isSameYear = start.year() === end.year();
|
|
const isSameMonth = isSameYear && start.month() === end.month();
|
|
const fullDateFormat = __( 'MMM D, YYYY', 'woo-dash' );
|
|
const monthDayFormat = __( 'MMM D', 'woo-dash' );
|
|
|
|
if ( isSameDay ) {
|
|
return start.format( fullDateFormat );
|
|
} else if ( isSameMonth ) {
|
|
const startDate = start.date();
|
|
return start.format( fullDateFormat ).replace( startDate, `${ startDate } - ${ end.date() }` );
|
|
} else if ( isSameYear ) {
|
|
return `${ start.format( monthDayFormat ) } - ${ end.format( fullDateFormat ) }`;
|
|
}
|
|
return `${ start.format( fullDateFormat ) } - ${ end.format( fullDateFormat ) }`;
|
|
}
|
|
|
|
/**
|
|
* Get a DateValue object for a period prior to the current period.
|
|
*
|
|
* @param {string} period - the chosen period
|
|
* @param {string} compare - `previous_period` or `previous_year`
|
|
* @return {DateValue} - DateValue data about the selected period
|
|
*/
|
|
function getLastPeriod( period, compare ) {
|
|
const primaryStart = moment()
|
|
.startOf( period )
|
|
.subtract( 1, period );
|
|
const primaryEnd = primaryStart.clone().endOf( period );
|
|
let secondaryStart;
|
|
let secondaryEnd;
|
|
|
|
if ( 'previous_period' === compare ) {
|
|
if ( 'year' === period ) {
|
|
// Subtract two entire periods for years to take into account leap year
|
|
secondaryStart = moment()
|
|
.startOf( period )
|
|
.subtract( 2, period );
|
|
secondaryEnd = secondaryStart.clone().endOf( period );
|
|
} else {
|
|
// Otherwise, use days in primary period to figure out how far to go back
|
|
const daysDiff = primaryEnd.diff( primaryStart, 'days' );
|
|
secondaryEnd = primaryStart.clone().subtract( 1, 'days' );
|
|
secondaryStart = secondaryEnd.clone().subtract( daysDiff, 'days' );
|
|
}
|
|
} else {
|
|
secondaryStart =
|
|
'week' === period
|
|
? primaryStart
|
|
.clone()
|
|
.subtract( 1, 'years' )
|
|
.week( primaryStart.week() )
|
|
.startOf( 'week' )
|
|
: primaryStart.clone().subtract( 1, 'years' );
|
|
secondaryEnd = secondaryStart.clone().endOf( period );
|
|
}
|
|
return {
|
|
primaryStart,
|
|
primaryEnd,
|
|
secondaryStart,
|
|
secondaryEnd,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Get a DateValue object for a curent period. The period begins on the first day of the period,
|
|
* and ends on the current day.
|
|
*
|
|
* @param {string} period - the chosen period
|
|
* @param {string} compare - `previous_period` or `previous_year`
|
|
* @return {DateValue} - DateValue data about the selected period
|
|
*/
|
|
function getCurrentPeriod( period, compare ) {
|
|
const primaryStart = moment().startOf( period );
|
|
const primaryEnd = moment();
|
|
const daysSoFar = primaryEnd.diff( primaryStart, 'days' );
|
|
let secondaryStart;
|
|
let secondaryEnd;
|
|
|
|
if ( 'previous_period' === compare ) {
|
|
secondaryStart = primaryStart.clone().subtract( 1, period );
|
|
secondaryEnd = primaryEnd.clone().subtract( 1, period );
|
|
} else {
|
|
secondaryStart =
|
|
'week' === period
|
|
? primaryStart
|
|
.clone()
|
|
.subtract( 1, 'years' )
|
|
.week( primaryStart.week() )
|
|
.startOf( 'week' )
|
|
: primaryStart.clone().subtract( 1, 'years' );
|
|
secondaryEnd = secondaryStart.clone().add( daysSoFar, 'days' );
|
|
}
|
|
return {
|
|
primaryStart,
|
|
primaryEnd,
|
|
secondaryStart,
|
|
secondaryEnd,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Get a DateValue object for a period described by a period, compare value, and start/end
|
|
* dates, for custom dates.
|
|
*
|
|
* @param {string} period - the chosen period
|
|
* @param {string} compare - `previous_period` or `previous_year`
|
|
* @param {Moment} [start] - start date if custom period
|
|
* @param {Moment} [end] - end date if custom period
|
|
* @return {DateValue} - DateValue data about the selected period
|
|
*/
|
|
function getDateValue( period, compare, start, end ) {
|
|
switch ( period ) {
|
|
case 'today':
|
|
return getCurrentPeriod( 'day', compare );
|
|
case 'yesterday':
|
|
return getLastPeriod( 'day', compare );
|
|
case 'week':
|
|
return getCurrentPeriod( 'week', compare );
|
|
case 'last_week':
|
|
return getLastPeriod( 'week', compare );
|
|
case 'month':
|
|
return getCurrentPeriod( 'month', compare );
|
|
case 'last_month':
|
|
return getLastPeriod( 'month', compare );
|
|
case 'quarter':
|
|
return getCurrentPeriod( 'quarter', compare );
|
|
case 'last_quarter':
|
|
return getLastPeriod( 'quarter', compare );
|
|
case 'year':
|
|
return getCurrentPeriod( 'year', compare );
|
|
case 'last_year':
|
|
return getLastPeriod( 'year', compare );
|
|
case 'custom':
|
|
const difference = end.diff( start, 'days' );
|
|
if ( 'previous_period' === compare ) {
|
|
const secondaryEnd = start.clone().subtract( 1, 'days' );
|
|
const secondaryStart = secondaryEnd.clone().subtract( difference, 'days' );
|
|
return {
|
|
primaryStart: start,
|
|
primaryEnd: end,
|
|
secondaryStart,
|
|
secondaryEnd,
|
|
};
|
|
}
|
|
return {
|
|
primaryStart: start,
|
|
primaryEnd: end,
|
|
secondaryStart: start.clone().subtract( 1, 'years' ),
|
|
secondaryEnd: end.clone().subtract( 1, 'years' ),
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get Date Value Objects for a primary and secondary date range
|
|
*
|
|
* @param {string} period - Indicates period, 'last_week', 'quarter', or 'custom'
|
|
* @param {string} compare - Indicates the period to compare against, 'previous_period', previous_year'
|
|
* @param {moment.Moment} [start] - If the period supplied is "custom", this is the start date
|
|
* @param {moment.Moment} [end] - If the period supplied is "custom", this is the end date
|
|
* @return {{primary: DateValue, secondary: DateValue}} - Primary and secondary DateValue objects
|
|
*/
|
|
export const getCurrentDates = ( { period, compare, start, end } ) => {
|
|
const { primaryStart, primaryEnd, secondaryStart, secondaryEnd } = getDateValue(
|
|
period,
|
|
compare,
|
|
start,
|
|
end
|
|
);
|
|
|
|
return {
|
|
primary: {
|
|
label: find( presetValues, item => item.value === period ).label,
|
|
range: getRangeLabel( primaryStart, primaryEnd ),
|
|
start: primaryStart,
|
|
end: primaryEnd,
|
|
},
|
|
secondary: {
|
|
label: find( compareValues, item => item.value === compare ).label,
|
|
range: getRangeLabel( secondaryStart, secondaryEnd ),
|
|
start: secondaryStart,
|
|
end: secondaryEnd,
|
|
},
|
|
};
|
|
};
|