import moment from 'moment' export interface Timeframe { id?: number display: string value?: number | 'custom' | 'All' | undefined timeValue: string | moment.unitOfTime.StartOf type: | 'historical' | 'trailing' | 'current' | 'quarterly' | 'previous' | string quarter?: number year?: string compareDisplay?: string disabled?: boolean customClass?: string custom?: string aggregation?: string } export interface TimeframeOption { timeframes: Timeframe[] type: Timeframe['type'] disabledTimeframeOptions?: string[] year?: string callout: ( type: string, startDate: string, endDate: string, options: any, ) => void useTimeframeAggregations?: boolean customAggregations?: any getAggregation?: (options: any) => any isTimePeriodExtensionEnabled?: boolean } export const newHistoricalTimeframes: Timeframe[] = [ { id: 1, display: '24HRS', value: 24, timeValue: 'hours', type: 'trailing', }, { id: 2, display: '7D', value: 7, timeValue: 'day', type: 'trailing', }, { id: 3, display: '30D', value: 30, timeValue: 'day', type: 'trailing', }, { id: 4, display: '3M', value: 3, timeValue: 'month', type: 'trailing', }, { id: 5, display: '6M', value: 6, timeValue: 'month', type: 'trailing', }, { id: 6, display: '12M', value: 12, timeValue: 'month', type: 'trailing', }, ] export const historicalTimeframes: Timeframe[] = [ { id: 1, display: '1D', value: 1, timeValue: 'day', type: 'historical', }, { id: 2, display: '1W', value: 1, timeValue: 'week', type: 'historical', }, { id: 3, display: '30D', value: 30, timeValue: 'day', type: 'historical', }, { id: 4, display: '3M', value: 3, timeValue: 'month', type: 'historical', }, { id: 5, display: '6M', value: 6, timeValue: 'month', type: 'historical', }, { id: 6, display: '1Y', value: 1, timeValue: 'year', type: 'historical', }, ] export const initialTimeframe: Timeframe = { id: 0, type: 'historical', display: '30D', value: 30, timeValue: 'day', } const getHistoricalDate = ( timeframe: Timeframe, date: 'startDate' | 'endDate' | 'compareStartDate' | 'compareEndDate', ): string => { if (timeframe?.value === 'custom') { const dates = date === 'startDate' || date === 'endDate' ? timeframe?.display?.split(' - ') : timeframe?.compareDisplay?.split(' - ') // Used compare display to pull comparison start date and end date if (!dates || dates.length < 2) { return moment().format() } const [startDate, endDate] = dates if (date === 'startDate' || date === 'compareStartDate') { return moment(startDate).startOf('day').format() } else { const endOfDayDate = moment(endDate).endOf('day') const now = moment() return now.isBefore(endOfDayDate) ? now.format() : endOfDayDate.format() } } else if (timeframe?.value === 'All') { if (date === 'startDate') { return moment('2017-01-01').format() } else { return moment().endOf('day').format() } } else { if (date === 'startDate') { return timeframe.timeValue === 'hours' ? moment() .subtract(timeframe?.value as number, timeframe.timeValue) .format() : moment() .subtract( timeframe?.value as number, timeframe.timeValue as moment.unitOfTime.DurationConstructor, ) .startOf('day') .format() } else { return timeframe.timeValue === 'hours' ? moment().format() : moment().endOf('day').subtract(1, 'days').format() } } } const getCurrentDate = ( timeframe: Timeframe, date: 'startDate' | 'endDate', ): string => { if (date === 'startDate') { return moment() .startOf(timeframe.timeValue as moment.unitOfTime.StartOf) .format() } else { return moment() .endOf(timeframe.timeValue as moment.unitOfTime.StartOf) .format() // because 'current' dates always are from a beginning to end time period, and the component updates with those values, then on init we also need to start with the "end" timeframe as well } } const getQuarterlyDate = ( timeframe: Timeframe, date: 'startDate' | 'endDate', ): string => { let startDate let endDate if (timeframe.quarter && timeframe.year) { const year = parseInt(timeframe.year) startDate = moment() .year(year) .quarter(timeframe.quarter) .startOf('quarter') endDate = moment().year(year).quarter(timeframe.quarter).endOf('quarter') } else if (timeframe.year) { const year = parseInt(timeframe.year) startDate = moment().year(year).startOf('year') endDate = moment().year(year).endOf('year') } else { startDate = moment().startOf('year') endDate = moment().endOf('year') } if (date === 'startDate') { return startDate.format() } else { return endDate.format() } } const getPreviousDate = ( timeframe: Timeframe, date: 'startDate' | 'endDate', ): string => { if (date === 'startDate') { return moment() .subtract(1, timeframe.timeValue as moment.unitOfTime.DurationConstructor) .startOf(timeframe.timeValue as moment.unitOfTime.StartOf) .format() } else { return moment() .subtract(1, timeframe.timeValue as moment.unitOfTime.DurationConstructor) .endOf(timeframe.timeValue as moment.unitOfTime.StartOf) .format() } } export function getTimeframeDates( timeframe: Timeframe | undefined, date: 'startDate' | 'endDate' | 'compareStartDate' | 'compareEndDate', ): string { if (!timeframe) return '' let newDate: string | undefined switch (timeframe.type) { case 'historical': case 'trailing': newDate = getHistoricalDate(timeframe, date) break case 'current': newDate = getCurrentDate(timeframe, date as 'startDate' | 'endDate') break case 'quarterly': newDate = getQuarterlyDate(timeframe, date as 'startDate' | 'endDate') break case 'previous': newDate = getPreviousDate(timeframe, date as 'startDate' | 'endDate') break default: break } return newDate || '' } export function checkForCorrectTimeframe( timeframe: Timeframe | undefined, ): boolean { if (!timeframe) return false const arr = [ 'display', 'timeValue', 'type', ...(timeframe?.type === 'historical' || timeframe?.type === 'trailing' ? ['value'] : []), ] // type: 'current' and 'quarterly' timeframes don't use 'value', so exclude that key from the list return arr.every((element) => Object.keys(timeframe).includes(element)) } // Function to switch to the next available timeframe option // If currently selected timeframe option is disabled for visited page export const getNextAvailableTimeframeOption = ({ timeframes, type, disabledTimeframeOptions, year = undefined, callout, useTimeframeAggregations, customAggregations, getAggregation, isTimePeriodExtensionEnabled = false, }: TimeframeOption): void => { if (!timeframes || timeframes.length === 0) return const validOption = timeframes.filter( (option) => !disabledTimeframeOptions?.includes(option.display), )[0] if (!validOption) return const validFormattedOption: Timeframe = { id: validOption?.id || 0, type: type, display: type === 'quarterly' ? `${year}${validOption?.quarter ? ` ${validOption?.display}` : ''}` : validOption?.display, ...(type === 'quarterly' ? { year: year?.toString() } : {}), ...(type === 'quarterly' ? { quarter: validOption?.quarter } : {}), timeValue: validOption?.timeValue || 'day', value: type === 'historical' || type === 'trailing' ? validOption?.value : 0, } callout( 'UPDATE_RANGE', getTimeframeDates(validFormattedOption, 'startDate'), getTimeframeDates(validFormattedOption, 'endDate'), { ...validFormattedOption, ...(useTimeframeAggregations ? { aggregation: getAggregation?.({ ...(type === 'current' || type === 'previous' ? { timeValue: validOption?.timeValue } : { timeframe: validFormattedOption }), ...(type === 'historical' || type === 'trailing' ? { timeframe: validOption, startDate: getTimeframeDates( validFormattedOption, 'startDate', ), endDate: getTimeframeDates(validFormattedOption, 'endDate'), } : {}), customAggregations, isTimePeriodExtensionEnabled: isTimePeriodExtensionEnabled, }), } : {}), }, ) }