1import { Chart, Host, type ChartDataPoint } from "@expo/ui/swift-ui";
2import { frame } from "@expo/ui/swift-ui/modifiers";
3import { useMemo } from "react";
4
5import type { DailyTotals } from "@t3tools/shared/usageMerge";
6
7import { buildChartDays, type UsageChartMetric } from "./usageChartData";
8import { useProviderColors } from "./usageProviders";
9
10export interface UsageDailyChartProps {
11 readonly days: readonly string[];
12 readonly daily: readonly DailyTotals[];
13 readonly metric: UsageChartMetric;
14 readonly height: number;
15}
16
17/**
18 * Native Swift Charts daily bars. Points sharing an x value stack, so emitting
19 * one point per provider per day yields per-provider bands whose stack height
20 * is the day's total; changes animate natively.
21 *
22 * Axes are hidden: 30-90 categorical day labels cannot fit on a phone, so the
23 * screen renders its own edge labels under the chart instead.
24 */
25export function UsageDailyChart({ days, daily, metric, height }: UsageDailyChartProps) {
26 const colors = useProviderColors();
27
28 const data = useMemo((): ChartDataPoint[] => {
29 return buildChartDays(days, daily, metric).flatMap((day) =>
30 day.values.map((entry) => ({
31 x: day.day,
32 y: entry.value,
33 color: colors[entry.provider],
34 })),
35 );
36 }, [days, daily, metric, colors]);
37
38 return (
39 <Host style={{ height, width: "100%" }}>
40 <Chart
41 type="bar"
42 data={data}
43 animate
44 showGrid={false}
45 barStyle={{ cornerRadius: 2 }}
46 modifiers={[frame({ height })]}
47 />
48 </Host>
49 );
50}