diff --git a/frontend/src/component/admin/billing/BillingDashboard/BillingPlan/useOverageCost.ts b/frontend/src/component/admin/billing/BillingDashboard/BillingPlan/useOverageCost.ts index 89a0bae91b..bea952a59b 100644 --- a/frontend/src/component/admin/billing/BillingDashboard/BillingPlan/useOverageCost.ts +++ b/frontend/src/component/admin/billing/BillingDashboard/BillingPlan/useOverageCost.ts @@ -30,16 +30,19 @@ const useNewOverageCostCalculation = (includedTraffic: number) => { const from = formatDate(startOfMonth(now)); const to = formatDate(endOfMonth(now)); - const { usage } = useTrafficSearch('daily', { from, to }); - + const { result } = useTrafficSearch('daily', { from, to }); const overageCost = useMemo(() => { - const totalUsage = calculateTotalUsage(usage); + if (result.state !== 'success') { + return 0; + } + + const totalUsage = calculateTotalUsage(result.data); return calculateOverageCost( totalUsage, includedTraffic, BILLING_TRAFFIC_BUNDLE_PRICE, ); - }, [includedTraffic, usage]); + }, [includedTraffic, JSON.stringify(result)]); return overageCost; }; diff --git a/frontend/src/component/admin/network/NetworkTrafficUsage/NetworkTrafficUsage.tsx b/frontend/src/component/admin/network/NetworkTrafficUsage/NetworkTrafficUsage.tsx index 1d375c533b..15704d3fe6 100644 --- a/frontend/src/component/admin/network/NetworkTrafficUsage/NetworkTrafficUsage.tsx +++ b/frontend/src/component/admin/network/NetworkTrafficUsage/NetworkTrafficUsage.tsx @@ -178,6 +178,62 @@ const BoldText = styled('span')(({ theme }) => ({ fontWeight: 'bold', })); +const useTrafficStats = ( + includedTraffic: number, + chartDataSelection: ChartDataSelection, +) => { + const { result } = useTrafficSearch( + chartDataSelection.grouping, + toDateRange(chartDataSelection, currentDate), + ); + const results = useMemo(() => { + if (result.state !== 'success') { + return { + chartData: { datasets: [], labels: [] }, + usageTotal: 0, + overageCost: 0, + estimatedMonthlyCost: 0, + requestSummaryUsage: 0, + }; + } + const traffic = result.data; + + const chartData = newToChartData(traffic); + const usageTotal = calculateTotalUsage(traffic); + const overageCost = calculateOverageCost( + usageTotal, + includedTraffic, + BILLING_TRAFFIC_BUNDLE_PRICE, + ); + + const estimatedMonthlyCost = calculateEstimatedMonthlyCost( + traffic.apiData, + includedTraffic, + currentDate, + BILLING_TRAFFIC_BUNDLE_PRICE, + ); + + const requestSummaryUsage = + chartDataSelection.grouping === 'daily' + ? usageTotal + : averageTrafficPreviousMonths(traffic); + + return { + chartData, + usageTotal, + overageCost, + estimatedMonthlyCost, + requestSummaryUsage, + }; + }, [ + JSON.stringify(result), + includedTraffic, + JSON.stringify(chartDataSelection), + ]); + + return results; +}; + const NewNetworkTrafficUsage: FC = () => { usePageTitle('Network - Data Usage'); const theme = useTheme(); @@ -233,25 +289,13 @@ const NewNetworkTrafficUsage: FC = () => { ); }, [theme, chartDataSelection]); - const traffic = useTrafficSearch( - chartDataSelection.grouping, - toDateRange(chartDataSelection, currentDate), - ); - - const data = newToChartData(traffic.usage); - const usageTotal = calculateTotalUsage(traffic.usage); - const overageCost = calculateOverageCost( + const { + chartData, usageTotal, - includedTraffic, - BILLING_TRAFFIC_BUNDLE_PRICE, - ); - - const estimatedMonthlyCost = calculateEstimatedMonthlyCost( - traffic.usage?.apiData, - includedTraffic, - currentDate, - BILLING_TRAFFIC_BUNDLE_PRICE, - ); + overageCost, + estimatedMonthlyCost, + requestSummaryUsage, + } = useTrafficStats(includedTraffic, chartDataSelection); const showOverageCalculations = chartDataSelection.grouping === 'daily' && @@ -296,13 +340,7 @@ const NewNetworkTrafficUsage: FC = () => { {showOverageCalculations && ( @@ -321,7 +359,7 @@ const NewNetworkTrafficUsage: FC = () => { /> { - if (!traffic || traffic.grouping === 'daily') { + if (traffic.grouping === 'daily') { return 0; } diff --git a/frontend/src/component/admin/network/NetworkTrafficUsage/chart-functions.test.ts b/frontend/src/component/admin/network/NetworkTrafficUsage/chart-functions.test.ts index ea426f5a2a..ddcd3e8fc0 100644 --- a/frontend/src/component/admin/network/NetworkTrafficUsage/chart-functions.test.ts +++ b/frontend/src/component/admin/network/NetworkTrafficUsage/chart-functions.test.ts @@ -148,11 +148,4 @@ describe('toChartData', () => { expect(toChartData(input)).toMatchObject(expectedOutput); }); - - test('returns empty data if traffic is undefined', () => { - expect(toChartData(undefined)).toStrictEqual({ - labels: [], - datasets: [], - }); - }); }); diff --git a/frontend/src/component/admin/network/NetworkTrafficUsage/chart-functions.ts b/frontend/src/component/admin/network/NetworkTrafficUsage/chart-functions.ts index 0e97c2d7cc..e287e78a43 100644 --- a/frontend/src/component/admin/network/NetworkTrafficUsage/chart-functions.ts +++ b/frontend/src/component/admin/network/NetworkTrafficUsage/chart-functions.ts @@ -12,12 +12,8 @@ import type { ChartDataSelection } from './chart-data-selection'; export type ChartDatasetType = ChartDataset<'bar'>; export const toChartData = ( - traffic?: TrafficUsageDataSegmentedCombinedSchema, + traffic: TrafficUsageDataSegmentedCombinedSchema, ): { datasets: ChartDatasetType[]; labels: string[] } => { - if (!traffic) { - return { labels: [], datasets: [] }; - } - const { newRecord, labels } = getLabelsAndRecords(traffic); const datasets = traffic.apiData .sort( diff --git a/frontend/src/hooks/api/getters/useInstanceTrafficMetrics/useInstanceTrafficMetrics.ts b/frontend/src/hooks/api/getters/useInstanceTrafficMetrics/useInstanceTrafficMetrics.ts index f2e322e427..9823e21f52 100644 --- a/frontend/src/hooks/api/getters/useInstanceTrafficMetrics/useInstanceTrafficMetrics.ts +++ b/frontend/src/hooks/api/getters/useInstanceTrafficMetrics/useInstanceTrafficMetrics.ts @@ -38,13 +38,11 @@ export const useInstanceTrafficMetrics = ( }; export type InstanceTrafficMetricsResponse2 = { - usage: TrafficUsageDataSegmentedCombinedSchema; - refetch: () => void; - - loading: boolean; - - error?: Error; + result: + | { state: 'success'; data: TrafficUsageDataSegmentedCombinedSchema } + | { state: 'error'; error: Error } + | { state: 'loading' }; }; export const useTrafficSearch = ( @@ -61,15 +59,17 @@ export const useTrafficSearch = ( const { data, error, mutate } = useSWR(formatApiPath(apiPath), fetcher); - return useMemo( - () => ({ - usage: cleanTrafficData(data) as any, - loading: !error && !data, + return useMemo(() => { + const result = data + ? { state: 'success' as const, data: cleanTrafficData(data) } + : error + ? { state: 'error' as const, error } + : { state: 'loading' as const }; + return { refetch: () => mutate(), - error, - }), - [data, error, mutate], - ); + result, + }; + }, [data, error, mutate]); }; const fetcher = (path: string) => { diff --git a/frontend/src/utils/traffic-calculations.test.ts b/frontend/src/utils/traffic-calculations.test.ts index e3bfda6559..19dc1a490b 100644 --- a/frontend/src/utils/traffic-calculations.test.ts +++ b/frontend/src/utils/traffic-calculations.test.ts @@ -171,16 +171,6 @@ describe('traffic overage calculation', () => { expect(result2).toBe(result); }); - it("doesn't die if traffic is undefined", () => { - expect( - calculateEstimatedMonthlyCost( - undefined, - 500_000, - new Date('2024-05-15'), - ), - ).toBe(0); - }); - it('supports custom price and unit size', () => { const dataUsage = 54_000_000; const includedTraffic = 53_000_000; diff --git a/frontend/src/utils/traffic-calculations.ts b/frontend/src/utils/traffic-calculations.ts index 036ce805a6..d995b9ec1f 100644 --- a/frontend/src/utils/traffic-calculations.ts +++ b/frontend/src/utils/traffic-calculations.ts @@ -16,12 +16,8 @@ export const METERED_TRAFFIC_ENDPOINTS = [ ]; export const cleanTrafficData = ( - data?: TrafficUsageDataSegmentedCombinedSchema, -): TrafficUsageDataSegmentedCombinedSchema | undefined => { - if (!data) { - return; - } - + data: TrafficUsageDataSegmentedCombinedSchema, +): TrafficUsageDataSegmentedCombinedSchema => { const { apiData, ...rest } = data; const cleanedApiData = apiData .filter((item) => METERED_TRAFFIC_ENDPOINTS.includes(item.apiPath)) @@ -67,11 +63,8 @@ const dailyTrafficDataToCurrentUsage = ( // Return the total number of requests for the selected month if showing daily // data, or the total for the most recent month if showing monthly data export const calculateTotalUsage = ( - data?: TrafficUsageDataSegmentedCombinedSchema, + data: TrafficUsageDataSegmentedCombinedSchema, ): number => { - if (!data) { - return 0; - } const { grouping, apiData } = data; if (grouping === 'monthly') { const latestMonth = format(new Date(data.dateRange.to), 'yyyy-MM'); @@ -135,9 +128,7 @@ export const calculateProjectedUsage = ({ }; export const calculateEstimatedMonthlyCost = ( - trafficData: - | TrafficUsageDataSegmentedCombinedSchemaApiDataItem[] - | undefined, + trafficData: TrafficUsageDataSegmentedCombinedSchemaApiDataItem[], includedTraffic: number, currentDate: Date, trafficUnitCost = DEFAULT_TRAFFIC_DATA_UNIT_COST,