Skip to content

Commit

Permalink
chore: use union type for traffic search data (#9221)
Browse files Browse the repository at this point in the history
Makes the data returned from the traffic search a union type to avoid
nasty object-is-undefined errors at runtime.

It requires more explicit handling, sure, but it means we don't need
to accept undefined.
  • Loading branch information
thomasheartman authored Feb 5, 2025
1 parent a11c965 commit 90e5adb
Show file tree
Hide file tree
Showing 8 changed files with 91 additions and 80 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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' &&
Expand Down Expand Up @@ -296,13 +340,7 @@ const NewNetworkTrafficUsage: FC = () => {
<TrafficInfoBoxes>
<RequestSummary
period={chartDataSelection}
usageTotal={
chartDataSelection.grouping === 'daily'
? usageTotal
: averageTrafficPreviousMonths(
traffic.usage,
)
}
usageTotal={requestSummaryUsage}
includedTraffic={includedTraffic}
/>
{showOverageCalculations && (
Expand All @@ -321,7 +359,7 @@ const NewNetworkTrafficUsage: FC = () => {
/>
</TopRow>
<Bar
data={data}
data={chartData}
plugins={[customHighlightPlugin()]}
options={options}
aria-label={getChartLabel(chartDataSelection)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { currentMonth } from './dates';
export const averageTrafficPreviousMonths = (
traffic: TrafficUsageDataSegmentedCombinedSchema,
) => {
if (!traffic || traffic.grouping === 'daily') {
if (traffic.grouping === 'daily') {
return 0;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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: [],
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 = (
Expand All @@ -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) => {
Expand Down
10 changes: 0 additions & 10 deletions frontend/src/utils/traffic-calculations.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
17 changes: 4 additions & 13 deletions frontend/src/utils/traffic-calculations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -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');
Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit 90e5adb

Please sign in to comment.