2019-02-05 18:12:58 +00:00
|
|
|
/**
|
|
|
|
* External dependencies
|
|
|
|
*/
|
|
|
|
import { find, get } from 'lodash';
|
|
|
|
import { flattenFilters } from '@woocommerce/navigation';
|
2022-01-20 00:20:18 +00:00
|
|
|
import { format as formatDate } from '@wordpress/date';
|
2024-05-30 04:54:00 +00:00
|
|
|
import {
|
|
|
|
containsLeapYear,
|
|
|
|
getPreviousDate,
|
|
|
|
isLeapYear,
|
|
|
|
} from '@woocommerce/date';
|
2019-02-05 18:12:58 +00:00
|
|
|
|
|
|
|
export const DEFAULT_FILTER = 'all';
|
|
|
|
|
|
|
|
export function getSelectedFilter( filters, query, selectedFilterArgs = {} ) {
|
2019-03-06 20:12:28 +00:00
|
|
|
if ( ! filters || filters.length === 0 ) {
|
2019-02-05 18:12:58 +00:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2019-03-06 20:12:28 +00:00
|
|
|
const clonedFilters = filters.slice( 0 );
|
|
|
|
const filterConfig = clonedFilters.pop();
|
2019-02-05 18:12:58 +00:00
|
|
|
|
|
|
|
if ( filterConfig.showFilters( query, selectedFilterArgs ) ) {
|
|
|
|
const allFilters = flattenFilters( filterConfig.filters );
|
2020-02-14 02:23:21 +00:00
|
|
|
const value =
|
|
|
|
query[ filterConfig.param ] ||
|
|
|
|
filterConfig.defaultValue ||
|
|
|
|
DEFAULT_FILTER;
|
2019-03-06 20:12:28 +00:00
|
|
|
return find( allFilters, { value } );
|
2019-02-05 18:12:58 +00:00
|
|
|
}
|
|
|
|
|
2019-03-06 20:12:28 +00:00
|
|
|
return getSelectedFilter( clonedFilters, query, selectedFilterArgs );
|
2019-02-05 18:12:58 +00:00
|
|
|
}
|
|
|
|
|
2019-03-06 20:12:28 +00:00
|
|
|
export function getChartMode( selectedFilter, query ) {
|
|
|
|
if ( selectedFilter && query ) {
|
2020-02-14 02:23:21 +00:00
|
|
|
const selectedFilterParam = get( selectedFilter, [
|
|
|
|
'settings',
|
|
|
|
'param',
|
|
|
|
] );
|
|
|
|
|
|
|
|
if (
|
|
|
|
! selectedFilterParam ||
|
|
|
|
Object.keys( query ).includes( selectedFilterParam )
|
|
|
|
) {
|
2019-03-06 20:12:28 +00:00
|
|
|
return get( selectedFilter, [ 'chartMode' ] );
|
|
|
|
}
|
2019-02-05 18:12:58 +00:00
|
|
|
}
|
|
|
|
|
2019-03-06 20:12:28 +00:00
|
|
|
return null;
|
2019-02-05 18:12:58 +00:00
|
|
|
}
|
2022-01-20 00:20:18 +00:00
|
|
|
|
|
|
|
export function createDateFormatter( format ) {
|
|
|
|
return ( date ) => formatDate( format, date );
|
|
|
|
}
|
2024-05-30 04:54:00 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns true if the data contains a leap year.
|
|
|
|
*
|
|
|
|
* @param {Object} data Chart interval data
|
|
|
|
* @return {boolean} True if data contains a leap year.
|
|
|
|
*/
|
|
|
|
export function dataContainsLeapYear( data ) {
|
|
|
|
if ( data?.data?.intervals?.length > 1 ) {
|
|
|
|
const start = data.data.intervals[ 0 ].date_start;
|
|
|
|
const end =
|
|
|
|
data.data.intervals[ data.data.intervals.length - 1 ].date_end;
|
|
|
|
|
|
|
|
if ( containsLeapYear( start, end ) ) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Builds chart data for the given parameters.
|
|
|
|
*
|
|
|
|
* @param {Object} primaryData Primary data
|
|
|
|
* @param {Object} secondaryData Secondary data
|
|
|
|
* @param {Object} primaryDatePicker DataPickerOptions object for primary data
|
|
|
|
* @param {Object} secondaryDatePicker DataPickerOptions object for secondary data
|
|
|
|
* @param {string} comparison Comparison type, e.x: `previous_year`
|
|
|
|
* @param {string} selectedChartKey Chart key, e.x: `orders_count`
|
|
|
|
* @param {string} currentInterval Chart interval, e.x: `day`
|
|
|
|
* @return {Object} Chart data
|
|
|
|
*/
|
|
|
|
export function buildChartData(
|
|
|
|
primaryData,
|
|
|
|
secondaryData,
|
|
|
|
primaryDatePicker,
|
|
|
|
secondaryDatePicker,
|
|
|
|
comparison,
|
|
|
|
selectedChartKey,
|
|
|
|
currentInterval
|
|
|
|
) {
|
|
|
|
const primarydataContainsLeapYear = dataContainsLeapYear( primaryData );
|
|
|
|
const secondarydataContainsLeapYear = dataContainsLeapYear( secondaryData );
|
|
|
|
const primaryDataIntervals = [ ...primaryData.data.intervals ];
|
|
|
|
const secondaryDataIntervals = [ ...secondaryData.data.intervals ];
|
|
|
|
|
|
|
|
const chartData = [];
|
|
|
|
|
|
|
|
for ( let index = 0; index < primaryDataIntervals.length; index++ ) {
|
|
|
|
const interval = primaryDataIntervals[ index ];
|
|
|
|
|
|
|
|
const primaryDateFormatted = formatDate(
|
|
|
|
'Y-m-d\\TH:i:s',
|
|
|
|
interval.date_start
|
|
|
|
);
|
|
|
|
const primaryLabel = `${ primaryDatePicker.label } (${ primaryDatePicker.range })`;
|
|
|
|
const primaryLabelDate = interval.date_start;
|
|
|
|
const primaryValue = interval.subtotals[ selectedChartKey ] || 0;
|
|
|
|
|
|
|
|
const secondaryInterval = secondaryDataIntervals[ index ];
|
|
|
|
const secondaryLabel = `${ secondaryDatePicker.label } (${ secondaryDatePicker.range })`;
|
|
|
|
|
|
|
|
const secondaryDateMoment = getPreviousDate(
|
|
|
|
interval.date_start,
|
|
|
|
primaryDatePicker.after,
|
|
|
|
secondaryDatePicker.after,
|
|
|
|
comparison,
|
|
|
|
currentInterval
|
|
|
|
);
|
|
|
|
let secondaryLabelDate = secondaryDateMoment.format(
|
|
|
|
'YYYY-MM-DD HH:mm:ss'
|
|
|
|
);
|
|
|
|
let secondaryValue =
|
|
|
|
( secondaryInterval &&
|
|
|
|
secondaryInterval.subtotals[ selectedChartKey ] ) ||
|
|
|
|
0;
|
|
|
|
|
|
|
|
if ( currentInterval === 'day' ) {
|
|
|
|
if (
|
|
|
|
primarydataContainsLeapYear &&
|
|
|
|
! secondarydataContainsLeapYear &&
|
|
|
|
secondaryDataIntervals?.[ index ]
|
|
|
|
) {
|
|
|
|
// Only fix the data if the date is in 29th Feb and secondary data is in 1st March,
|
|
|
|
// which signifies incorrect comparison.
|
|
|
|
const primaryDate = new Date( interval.date_start );
|
|
|
|
const secondaryDate = new Date(
|
|
|
|
secondaryDataIntervals[ index ].date_start
|
|
|
|
);
|
|
|
|
if (
|
|
|
|
isLeapYear( primaryDate.getFullYear() ) &&
|
|
|
|
primaryDate.getMonth() === 1 &&
|
|
|
|
primaryDate.getDate() === 29 &&
|
|
|
|
secondaryDate.getMonth() === 2 &&
|
|
|
|
secondaryDate.getDate() === 1
|
|
|
|
) {
|
|
|
|
// This is going to be displayed as "Invalid date" label from D3.js, but desirable imo since
|
|
|
|
// 29th February is not a valid date for non-leap years.
|
|
|
|
secondaryLabelDate = '-';
|
|
|
|
secondaryValue = 0;
|
|
|
|
|
|
|
|
// Move the data up by 1 day for the missing leap day
|
|
|
|
// so everything else is shifted to the right correctly.
|
|
|
|
secondaryDataIntervals.splice(
|
|
|
|
index,
|
|
|
|
0,
|
|
|
|
secondaryDataIntervals[ index ]
|
|
|
|
);
|
|
|
|
}
|
|
|
|
} else if (
|
|
|
|
! primarydataContainsLeapYear &&
|
|
|
|
secondarydataContainsLeapYear
|
|
|
|
) {
|
|
|
|
// Todo: Do something about secondary data having leap year while first does not.
|
|
|
|
// Currently, there are issues to render chart where primary data does not have the date since
|
|
|
|
// the x-axis is based on primary data.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
chartData.push( {
|
|
|
|
date: primaryDateFormatted,
|
|
|
|
primary: {
|
|
|
|
label: primaryLabel,
|
|
|
|
labelDate: primaryLabelDate,
|
|
|
|
value: primaryValue,
|
|
|
|
},
|
|
|
|
secondary: {
|
|
|
|
label: secondaryLabel,
|
|
|
|
labelDate: secondaryLabelDate,
|
|
|
|
value: secondaryValue,
|
|
|
|
},
|
|
|
|
} );
|
|
|
|
}
|
|
|
|
|
|
|
|
return chartData;
|
|
|
|
}
|