import moment from 'moment' import { capitalize } from '../../services/HelperServiceTyped' import styles from './header_metric_group.module.scss' import { c } from '../../translations/LibraryTranslationService' import { type IconColorList, type IconStringList } from '../Icons/Icon.models' type changeObjectNewProps = { /** Icon color to display in determine change */ iconColor: IconColorList /** Icon to display in determine change */ icon: IconStringList /** This className will be added to the text */ textClassName: string } /** This function determines the change and reverse logic based on the change percentage */ export const determineChangeValue = ( changePct: number, reverse?: boolean, isNeutralColor?: boolean, ) => { let changeObject: changeObjectNewProps = { iconColor: isNeutralColor ? 'purple' : 'dark-blue', textClassName: isNeutralColor ? styles.fontPurple : styles.fontBlue, icon: 'trendEven', } if (changePct < 0) { changeObject = { textClassName: isNeutralColor ? styles.fontPurple : reverse ? styles.fontDarkGreen : styles.fontDarkRed, iconColor: isNeutralColor ? 'purple' : reverse ? 'dark-green' : 'dark-red', icon: 'trendDown', } } else if (changePct > 0) { changeObject = { textClassName: isNeutralColor ? styles.fontPurple : reverse ? styles.fontDarkRed : styles.fontDarkGreen, iconColor: isNeutralColor ? 'purple' : reverse ? 'dark-red' : 'dark-green', icon: 'trendUp', } } return changeObject } type TimeframeTypeBase = { timeValue: moment.DurationInputArg2 aggregation: string display: string } type CurrentTimeframeType = TimeframeTypeBase & { type: 'current' value?: never } type PreviousTimeframeType = TimeframeTypeBase & { type: 'previous' value?: never } type HistoricalTimeframeTypeBase = TimeframeTypeBase & { type: 'historical' | 'trailing' } type CustomHistoricalTimeframeType = HistoricalTimeframeTypeBase & { value: 'custom' compareDisplay: string } type NumberHistoricalTimeframeType = HistoricalTimeframeTypeBase & { value: number compareDisplay?: never } type HistoricalTimeframeType = | CustomHistoricalTimeframeType | NumberHistoricalTimeframeType type QuarterlyTimeframeType = TimeframeTypeBase & { type: 'quarterly' year: number quarter: number value?: never } type PeriodDisplaysParams = { // Type of Timeframe eg. current/Historical/Quarterly/Previous timeframe: TimeframeType // 1 -> current Period && 2 -> current Year column: 1 | 2 // compare with Previous Period or Previous Year compareWith?: CompareWith } export type TimeframeType = | CurrentTimeframeType | HistoricalTimeframeType | QuarterlyTimeframeType | PreviousTimeframeType export type CompareWith = 'previous_period' | 'previous_year' export const getPeriodDisplays = ({ timeframe, column, compareWith, }: PeriodDisplaysParams) => { // This logic is seperated to not impact if compareWith global filter param is not used if (compareWith === 'previous_year' && column === 2) { switch (timeframe?.type) { case 'current': case 'previous': return timeframe?.timeValue === 'day' ? c('sameDayPreviousYear') : timeframe.timeValue === 'year' ? c('previousYear') : c('sameTimeframeDisplayLastYear', { timeframeDisplay: timeframe?.display, }) case 'historical': case 'trailing': if (timeframe?.timeValue === 'day' && timeframe?.value === 1) { return c('sameDayLastYear') } else if (timeframe?.value === 'custom') { return c('comparisonPeriod') } else { return timeframe.timeValue === 'year' ? c('precedingOneYear') : c('sameTimeframeDisplayLastYear', { timeframeDisplay: `${ timeframe?.timeValue === 'month' || timeframe?.timeValue === 'hours' || timeframe?.value === 30 || timeframe?.value === 7 ? timeframe?.value : '' } ${capitalize(timeframe?.timeValue)}${ timeframe?.timeValue !== 'hours' && (timeframe?.timeValue === 'month' || timeframe?.value === 30 || timeframe?.value === 7) ? c('sForPlural') : '' }`, }) } } } switch (timeframe?.type) { case 'current': if (timeframe?.timeValue === 'day') return column === 1 ? c('today') : c('yesterday') else return column === 1 ? c('thisTimeframe', { timeframeDisplay: timeframe?.display, }) : c('lastTimeframe', { timeframeDisplay: timeframe?.display, }) case 'previous': if (timeframe?.timeValue === 'day') return column === 1 ? c('yesterday') : c('previousDay') else return column === 1 ? c('lastTimeframe', { timeframeDisplay: timeframe?.display, }) : c('previousTimeframe', { timeframeDisplay: timeframe?.display, }) case 'historical': case 'trailing': if (timeframe?.timeValue === 'day' && timeframe?.value === 1) return `${column === 1 ? c('yesterday') : c('previousDay')}` else if (timeframe?.value === 'custom') return column === 1 ? c('selectedPeriod') : c('comparisonPeriod') else return column === 1 ? c('lastTimeframe', { timeframeDisplay: `${ timeframe?.timeValue === 'month' || timeframe?.timeValue === 'hours' || timeframe?.value === 30 || timeframe?.value === 7 ? timeframe?.value : '' } ${capitalize(timeframe?.timeValue)}${ timeframe?.timeValue !== 'hours' && (timeframe?.timeValue === 'month' || timeframe?.value === 30 || timeframe?.value === 7) ? c('sForPlural') : '' }`, }) : c('previousTimeframe', { timeframeDisplay: `${ timeframe?.timeValue === 'month' || timeframe?.timeValue === 'hours' || timeframe?.value === 30 || timeframe?.value === 7 ? timeframe?.value : '' } ${capitalize(timeframe?.timeValue)}${ timeframe?.timeValue !== 'hours' && (timeframe?.timeValue === 'month' || timeframe?.value === 30 || timeframe?.value === 7) ? c('sForPlural') : '' }`, }) case 'quarterly': if (compareWith === 'previous_period' && column === 2) { if (timeframe.timeValue === 'year') { return `${moment(timeframe?.year, 'YYYY').subtract(1, 'year').format('YYYY')}` } const previousQuarter = timeframe?.quarter === 1 ? 4 : timeframe?.quarter - 1 const year = timeframe?.quarter === 1 ? timeframe?.year - 1 : timeframe?.year return c('yearAndQuarter', { year: year, quarter: previousQuarter, }) } else if (timeframe?.timeValue === 'quarter') { const quarter = moment(timeframe?.year, 'YYYY') .quarter(timeframe?.quarter) .subtract(4, 'Q') return column === 1 ? `${timeframe?.display}` : c('yearAndQuarter', { year: quarter.format('YYYY'), quarter: quarter.format('Q'), }) } else { return column === 1 ? `${timeframe?.display}` : `${moment(timeframe?.year, 'YYYY').subtract(1, 'year').format('YYYY')}` } } } export const getPreviousPeriodRange = ( timeframe: TimeframeType, startDate: string, endDate: string, compareWith?: string, ): string | null => { if (!timeframe || !startDate || !endDate) return null const start = moment(startDate) const end = moment(endDate) if (!start.isValid() || !end.isValid()) return null const now = moment() const currentYear = now.year() const currentQuarter = now.quarter() let compareStart: moment.Moment let compareEnd: moment.Moment // --- TYPE: CURRENT --- if (timeframe.type === 'current' && timeframe.timeValue) { if (compareWith === 'previous_period') { switch (timeframe.timeValue) { case 'week': case 'month': case 'year': compareStart = start .clone() .subtract(1, timeframe.timeValue) .startOf(timeframe.timeValue) compareEnd = compareStart.clone().endOf(timeframe.timeValue) break default: return null } } else if (compareWith === 'previous_year') { switch (timeframe.timeValue) { case 'week': compareStart = start.clone().subtract(1, 'year') compareEnd = compareStart.clone().add(6, 'days') // full week break case 'month': compareStart = start.clone().subtract(1, 'year').startOf('month') compareEnd = compareStart.clone().endOf('month') break case 'year': compareStart = start.clone().subtract(1, 'year').startOf('year') compareEnd = compareStart.clone().endOf('year') break default: return null } } else { return null } return `${compareStart.format('MM/DD/YYYY')} - ${compareEnd.format('MM/DD/YYYY')}` } // --- TYPE: QUARTERLY --- if (timeframe.type === 'quarterly' && timeframe.year) { const year = Number(timeframe.year) const quarter = Number(timeframe.quarter) const isCurrentQuarter = year === currentYear && quarter === currentQuarter const isCurrentYearOnly = year === currentYear && timeframe.timeValue === 'year' if (!(isCurrentQuarter || isCurrentYearOnly)) return null if (compareWith === 'previous_period') { if (isCurrentYearOnly) { compareStart = moment() .year(year - 1) .startOf('year') compareEnd = moment() .year(year - 1) .endOf('year') } else if (isCurrentQuarter && quarter) { const reference = moment().year(year).quarter(quarter) const prevQuarter = reference.clone().subtract(1, 'quarter') compareStart = prevQuarter.clone().startOf('quarter') compareEnd = prevQuarter.clone().endOf('quarter') } else { return null } } else if (compareWith === 'previous_year') { if (quarter && timeframe.timeValue === 'quarter') { const reference = moment() .year(year - 1) .quarter(quarter) compareStart = reference.clone().startOf('quarter') compareEnd = reference.clone().endOf('quarter') } else { compareStart = moment() .year(year - 1) .startOf('year') compareEnd = moment() .year(year - 1) .endOf('year') } } else { return null } return `${compareStart.format('MM/DD/YYYY')} - ${compareEnd.format('MM/DD/YYYY')}` } return null } export type DateType = { startDate: string endDate: string } export const formatDates = ( currentPeriodDates: DateType, comparisonPeriodDates: DateType | undefined, ) => { const currentPeriodStartDate = moment(currentPeriodDates.startDate) const currentPeriodEndDate = moment(currentPeriodDates.endDate) const comparisonPeriodStartDate = moment(comparisonPeriodDates?.startDate) const comparisonPeriodEndDate = moment(comparisonPeriodDates?.endDate) if ( currentPeriodStartDate.format('MM/DD/YYYY') === currentPeriodEndDate.format('MM/DD/YYYY') && comparisonPeriodStartDate.format('MM/DD/YYYY') === comparisonPeriodEndDate.format('MM/DD/YYYY') ) { return c('currentDateVsComparisonDate', { currentDate: currentPeriodStartDate.format('MM/DD/YYYY'), comparisonDate: comparisonPeriodStartDate.format('MM/DD/YYYY'), }) } return c('currentDateVsComparisonDateRange', { currentPeriodStartDate: currentPeriodStartDate.format('MM/DD/YYYY'), currentPeriodEndDate: currentPeriodEndDate.format('MM/DD/YYYY'), comparisonPeriodStartDate: comparisonPeriodStartDate.format('MM/DD/YYYY'), comparisonPeriodEndDate: comparisonPeriodEndDate.format('MM/DD/YYYY'), }) } export const getPartialPeriodDates = ( currentPeriodDates: DateType, comparisonPeriodDates?: DateType, ) => { const format = 'MM/DD/YYYY' const currentStart = moment(currentPeriodDates.startDate).format(format) const currentEnd = moment(currentPeriodDates.endDate).format(format) const comparisonStart = moment(comparisonPeriodDates?.startDate).format( format, ) const comparisonEnd = moment(comparisonPeriodDates?.endDate).format(format) const isSingleDate = currentStart === currentEnd && comparisonStart === comparisonEnd const currentDate = isSingleDate ? currentStart : `${currentStart} - ${currentEnd}` const comparisonDate = isSingleDate ? comparisonStart : `${comparisonStart} - ${comparisonEnd}` return { currentDate, comparisonDate } }