From aa52251be6193d0920af497b51f4f701834450df Mon Sep 17 00:00:00 2001 From: yivlad Date: Thu, 19 Dec 2024 12:41:10 +0100 Subject: [PATCH] Change My earnings chart timeframes --- .../useMyEarningsInfo/calculatePredictions.ts | 58 +--------------- .../useMyEarningsInfo/common.ts | 2 +- .../getFilteredEarningsWithPredictions.ts | 21 +++++- .../savings/views/SavingsUSDSView.stories.ts | 2 +- packages/app/src/ui/charts/utils.ts | 67 ++++++++++--------- 5 files changed, 59 insertions(+), 91 deletions(-) diff --git a/packages/app/src/domain/savings-charts/useMyEarningsInfo/calculatePredictions.ts b/packages/app/src/domain/savings-charts/useMyEarningsInfo/calculatePredictions.ts index 28544168b..1abde6180 100644 --- a/packages/app/src/domain/savings-charts/useMyEarningsInfo/calculatePredictions.ts +++ b/packages/app/src/domain/savings-charts/useMyEarningsInfo/calculatePredictions.ts @@ -1,77 +1,23 @@ import { SavingsInfo } from '@/domain/savings-info/types' import { range } from '@/utils/array' -import { assertNever } from '@/utils/assertNever' import { NormalizedUnitNumber } from '@marsfoundation/common-universal' -import { MyEarningsTimeframe } from './common' import { MyEarningsInfoItem } from './types' const SECONDS_PER_DAY = 24 * 60 * 60 -export interface CalculatePredictionsParams { - timestamp: number // in seconds - shares: NormalizedUnitNumber - savingsInfo: SavingsInfo - timeframe: MyEarningsTimeframe - dataLength: number -} - export function calculatePredictions({ - timestamp, - shares, - savingsInfo, - timeframe, - dataLength, -}: CalculatePredictionsParams): MyEarningsInfoItem[] { - const optimalPredictionsLength = Math.floor(dataLength * 1.66) - - switch (timeframe) { - case '7D': - return calculatePredictionsIncomeByDays({ - days: Math.max(optimalPredictionsLength, 7), - shares, - timestamp, - savingsInfo, - step: 1, - }) - - case '1M': - return calculatePredictionsIncomeByDays({ - days: Math.max(optimalPredictionsLength, 30), - shares, - timestamp, - savingsInfo, - step: 1, - }) - - case '1Y': - case 'All': - return calculatePredictionsIncomeByDays({ - // setting upper bounds due to visible performance problems - days: Math.max(Math.min(optimalPredictionsLength, 360), 90), - shares, - timestamp, - savingsInfo, - step: 3, - }) - - default: - assertNever(timeframe) - } -} - -function calculatePredictionsIncomeByDays({ days, savingsInfo, shares, timestamp, - step, }: { days: number savingsInfo: SavingsInfo shares: NormalizedUnitNumber timestamp: number - step: number }): MyEarningsInfoItem[] { + const step = days > 366 ? 3 : 1 + // @note For today we have only current balance (with slight delay) but we need also balance for next data-point return range(0, days, step).map((day) => { const dayTimestamp = timestamp + day * SECONDS_PER_DAY diff --git a/packages/app/src/domain/savings-charts/useMyEarningsInfo/common.ts b/packages/app/src/domain/savings-charts/useMyEarningsInfo/common.ts index 0694cf345..84397ae9c 100644 --- a/packages/app/src/domain/savings-charts/useMyEarningsInfo/common.ts +++ b/packages/app/src/domain/savings-charts/useMyEarningsInfo/common.ts @@ -1,4 +1,4 @@ import { Timeframe } from '@/ui/charts/defaults' -export const MY_EARNINGS_TIMEFRAMES = ['7D', '1M', '1Y', 'All'] as const satisfies Timeframe[] +export const MY_EARNINGS_TIMEFRAMES = ['1M', '1Y', '3Y', 'All'] as const satisfies Timeframe[] export type MyEarningsTimeframe = (typeof MY_EARNINGS_TIMEFRAMES)[number] diff --git a/packages/app/src/domain/savings-charts/useMyEarningsInfo/getFilteredEarningsWithPredictions.ts b/packages/app/src/domain/savings-charts/useMyEarningsInfo/getFilteredEarningsWithPredictions.ts index cfb9e6cb0..f048e72a4 100644 --- a/packages/app/src/domain/savings-charts/useMyEarningsInfo/getFilteredEarningsWithPredictions.ts +++ b/packages/app/src/domain/savings-charts/useMyEarningsInfo/getFilteredEarningsWithPredictions.ts @@ -1,6 +1,7 @@ import { TokenWithBalance } from '@/domain/common/types' import { SavingsInfo } from '@/domain/savings-info/types' import { filterDataByTimeframe } from '@/ui/charts/utils' +import { assertNever } from '@marsfoundation/common-universal' import { calculatePredictions } from './calculatePredictions' import { MyEarningsTimeframe } from './common' import { MyEarningsInfoItem } from './types' @@ -42,12 +43,28 @@ export function getFilteredEarningsWithPredictions({ balance: savingsInfo.convertToAssets({ shares: savingsTokenWithBalance.balance }), } + const predictionsLength = Math.ceil( + (() => { + switch (timeframe) { + case '1M': + return 30 * 0.5 + case '1Y': + return 365 * 0.5 + case '3Y': + return 365 * 1.5 + case 'All': + return 365 * 3 + default: + assertNever(timeframe) + } + })(), + ) + const calculatedPredictions = calculatePredictions({ savingsInfo, - timeframe, timestamp: Math.floor(getEndOfDayTimestamp(todaysItem.date) / 1000), shares: savingsTokenWithBalance.balance, - dataLength: filteredData.length, + days: predictionsLength, }) filteredData.push(todaysItem) diff --git a/packages/app/src/features/savings/views/SavingsUSDSView.stories.ts b/packages/app/src/features/savings/views/SavingsUSDSView.stories.ts index 75a9a613d..1df28820a 100644 --- a/packages/app/src/features/savings/views/SavingsUSDSView.stories.ts +++ b/packages/app/src/features/savings/views/SavingsUSDSView.stories.ts @@ -28,7 +28,7 @@ const myEarningsInfo = { error: null, }, shouldDisplayMyEarnings: true, - selectedTimeframe: '7D', + selectedTimeframe: '1M', setSelectedTimeframe: () => {}, availableTimeframes: MY_EARNINGS_TIMEFRAMES, } satisfies UseMyEarningsInfoResult diff --git a/packages/app/src/ui/charts/utils.ts b/packages/app/src/ui/charts/utils.ts index 5cf922d63..828918879 100644 --- a/packages/app/src/ui/charts/utils.ts +++ b/packages/app/src/ui/charts/utils.ts @@ -1,5 +1,5 @@ import { USD_MOCK_TOKEN } from '@/domain/types/Token' -import { NormalizedUnitNumber } from '@marsfoundation/common-universal' +import { NormalizedUnitNumber, assertNever } from '@marsfoundation/common-universal' import { Timeframe } from './defaults' export function formatTooltipDate(date: Date): string { @@ -34,40 +34,45 @@ export function filterDataByTimeframe({ }: FilterDataByTimeframeParams): Data[] { const now = new Date(currentTimestamp * 1000) - switch (timeframe) { - case '7D': { - const sevenDaysAgo = new Date(now) - sevenDaysAgo.setDate(now.getDate() - 7) - return data.filter((d) => new Date(d.date) >= sevenDaysAgo) - } - - case '1M': { - const oneMonthAgo = new Date(now) - oneMonthAgo.setMonth(now.getMonth() - 1) - return data.filter((d) => new Date(d.date) >= oneMonthAgo) - } - - case '3M': { - const threeMonthsAgo = new Date(now) - threeMonthsAgo.setMonth(now.getMonth() - 3) - return data.filter((d) => new Date(d.date) >= threeMonthsAgo) - } + if (timeframe === 'All') { + return data + } - case '1Y': { - const oneYearAgo = new Date(now) - oneYearAgo.setFullYear(now.getFullYear() - 1) - return data.filter((d) => new Date(d.date) >= oneYearAgo) + const cutoff = (() => { + switch (timeframe) { + case '7D': { + const sevenDaysAgo = new Date(now) + sevenDaysAgo.setDate(now.getDate() - 7) + return sevenDaysAgo + } + case '1M': { + const oneMonthAgo = new Date(now) + oneMonthAgo.setMonth(now.getMonth() - 1) + return oneMonthAgo + } + case '3M': { + const threeMonthsAgo = new Date(now) + threeMonthsAgo.setMonth(now.getMonth() - 3) + return threeMonthsAgo + } + case '1Y': { + const oneYearAgo = new Date(now) + oneYearAgo.setFullYear(now.getFullYear() - 1) + return oneYearAgo + } + case '3Y': { + const threeYearsAgo = new Date(now) + threeYearsAgo.setFullYear(now.getFullYear() - 3) + return threeYearsAgo + } + default: + assertNever(timeframe) } + })() - case '3Y': { - const threeYearsAgo = new Date(now) - threeYearsAgo.setFullYear(now.getFullYear() - 3) - return data.filter((d) => new Date(d.date) >= threeYearsAgo) - } + const filteredData = data.filter((d) => new Date(d.date) >= cutoff) - case 'All': - return data - } + return filteredData } export function getVerticalDomainWithPadding(min: number, max: number): [number, number] {