Much nicer chart
This commit is contained in:
@@ -49,7 +49,7 @@ const ChartContainer = React.forwardRef<
|
||||
data-chart={chartId}
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"[&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line-line]:stroke-border flex aspect-video justify-center text-xs [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-none [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-sector]:outline-none [&_.recharts-surface]:outline-none",
|
||||
"flex aspect-video justify-center text-xs [&_.recharts-cartesian-axis-tick_text]:fill-text-dimmed/50 [&_.recharts-cartesian-grid_line]:stroke-grid-bright/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-grid-dimmed [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-none [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-grid-dimmed [&_.recharts-radial-bar-background-sector]:fill-grid-dimmed [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-grid-dimmed [&_.recharts-reference-line-line]:stroke-grid-dimmed [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-sector]:outline-none [&_.recharts-surface]:outline-none",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
@@ -158,7 +158,7 @@ const ChartTooltipContent = React.forwardRef<
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"border-border/50 bg-background grid min-w-[8rem] items-start gap-1.5 rounded-lg border px-2.5 py-1.5 text-xs shadow-xl",
|
||||
"grid min-w-[8rem] items-start gap-1.5 rounded-lg border border-grid-bright/50 bg-background-dimmed px-2.5 py-1.5 text-xs shadow-xl",
|
||||
className
|
||||
)}
|
||||
>
|
||||
@@ -173,7 +173,7 @@ const ChartTooltipContent = React.forwardRef<
|
||||
<div
|
||||
key={item.dataKey}
|
||||
className={cn(
|
||||
"[&>svg]:text-muted-foreground flex w-full items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5",
|
||||
"flex w-full items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-text-dimmed",
|
||||
indicator === "dot" && "items-center"
|
||||
)}
|
||||
>
|
||||
@@ -207,18 +207,16 @@ const ChartTooltipContent = React.forwardRef<
|
||||
)}
|
||||
<div
|
||||
className={cn(
|
||||
"flex flex-1 justify-between leading-none",
|
||||
"flex flex-1 justify-between gap-1.5 leading-none",
|
||||
nestLabel ? "items-end" : "items-center"
|
||||
)}
|
||||
>
|
||||
<div className="grid gap-1.5">
|
||||
{nestLabel ? tooltipLabel : null}
|
||||
<span className="text-muted-foreground">
|
||||
{itemConfig?.label || item.name}
|
||||
</span>
|
||||
<span className="text-text-dimmed">{itemConfig?.label || item.name}</span>
|
||||
</div>
|
||||
{item.value && (
|
||||
<span className="text-foreground font-mono font-medium tabular-nums">
|
||||
<span className="font-mono font-medium tabular-nums text-text-bright">
|
||||
{item.value.toLocaleString()}
|
||||
</span>
|
||||
)}
|
||||
@@ -268,7 +266,7 @@ const ChartLegendContent = React.forwardRef<
|
||||
<div
|
||||
key={item.value}
|
||||
className={cn(
|
||||
"[&>svg]:text-muted-foreground flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3"
|
||||
"flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-text-dimmed"
|
||||
)}
|
||||
>
|
||||
{itemConfig?.icon && !hideIcon ? (
|
||||
|
||||
@@ -3,7 +3,16 @@ import { Await } from "@remix-run/react";
|
||||
import { LoaderFunctionArgs } from "@remix-run/server-runtime";
|
||||
import { formatDurationMilliseconds } from "@trigger.dev/core/v3";
|
||||
import { Suspense } from "react";
|
||||
import { Bar, BarChart, Rectangle, ResponsiveContainer, Tooltip, XAxis, YAxis } from "recharts";
|
||||
import {
|
||||
Bar,
|
||||
BarChart,
|
||||
CartesianGrid,
|
||||
Rectangle,
|
||||
ResponsiveContainer,
|
||||
Tooltip,
|
||||
XAxis,
|
||||
YAxis,
|
||||
} from "recharts";
|
||||
import { redirect, typeddefer, useTypedLoaderData } from "remix-typedjson";
|
||||
import { UsageBar } from "~/components/billing/v3/UsageBar";
|
||||
import { PageBody, PageContainer } from "~/components/layout/AppLayout";
|
||||
@@ -26,7 +35,12 @@ import { requireUserId } from "~/services/session.server";
|
||||
import { formatCurrency, formatCurrencyAccurate, formatNumber } from "~/utils/numberFormatter";
|
||||
import { OrganizationParamsSchema, organizationPath } from "~/utils/pathBuilder";
|
||||
import { useCurrentPlan } from "../_app.orgs.$organizationSlug/route";
|
||||
import { ChartConfig } from "~/components/primitives/Chart";
|
||||
import {
|
||||
ChartConfig,
|
||||
ChartContainer,
|
||||
ChartTooltip,
|
||||
ChartTooltipContent,
|
||||
} from "~/components/primitives/Chart";
|
||||
|
||||
export async function loader({ params, request }: LoaderFunctionArgs) {
|
||||
await requireUserId(request);
|
||||
@@ -227,25 +241,31 @@ const chartConfig = {
|
||||
} satisfies ChartConfig;
|
||||
|
||||
function UsageChart({ data }: { data: UsageSeriesData }) {
|
||||
const maxDollar = Math.max(...data.map((d) => d.dollars));
|
||||
const decimalPlaces = maxDollar < 1 ? 4 : 2;
|
||||
|
||||
return (
|
||||
<ResponsiveContainer width="100%" height="100%" className="min-h-96">
|
||||
<ChartContainer config={chartConfig} className="max-h-96 min-h-40 w-full">
|
||||
<BarChart
|
||||
accessibilityLayer
|
||||
data={data}
|
||||
margin={{
|
||||
top: 20,
|
||||
right: 0,
|
||||
left: -10,
|
||||
bottom: 10,
|
||||
}}
|
||||
// margin={{
|
||||
// top: 20,
|
||||
// right: 0,
|
||||
// left: -10,
|
||||
// bottom: 10,
|
||||
// }}
|
||||
>
|
||||
<CartesianGrid vertical={false} stroke="#212327" />
|
||||
<XAxis
|
||||
stroke="#5F6570"
|
||||
fontSize={12}
|
||||
tickLine={false}
|
||||
axisLine={true}
|
||||
dataKey={(item: { date: string }) => {
|
||||
if (!item.date) return "";
|
||||
const date = new Date(item.date);
|
||||
tickMargin={10}
|
||||
axisLine={false}
|
||||
dataKey="date"
|
||||
tickFormatter={(value) => {
|
||||
if (!value) return "";
|
||||
const date = new Date(value);
|
||||
if (date.getDate() === 1) {
|
||||
return dateFormatter.format(date);
|
||||
}
|
||||
@@ -254,14 +274,14 @@ function UsageChart({ data }: { data: UsageSeriesData }) {
|
||||
className="text-xs"
|
||||
/>
|
||||
<YAxis
|
||||
stroke="#5F6570"
|
||||
fontSize={12}
|
||||
tickLine={false}
|
||||
axisLine={true}
|
||||
tickMargin={10}
|
||||
axisLine={false}
|
||||
allowDecimals={true}
|
||||
tickFormatter={(value) => `$${value.toFixed(2)}`}
|
||||
tickFormatter={(value) => `$${value.toFixed(decimalPlaces)}`}
|
||||
/>
|
||||
<Tooltip
|
||||
{/* <Tooltip
|
||||
cursor={{ fill: "rgba(255,255,255,0.05)" }}
|
||||
contentStyle={tooltipStyle}
|
||||
labelFormatter={(value, data) => {
|
||||
@@ -276,9 +296,24 @@ function UsageChart({ data }: { data: UsageSeriesData }) {
|
||||
const numValue = Number(value);
|
||||
return [` ${formatCurrencyAccurate(numValue)}`];
|
||||
}}
|
||||
/> */}
|
||||
<ChartTooltip
|
||||
content={<ChartTooltipContent />}
|
||||
labelFormatter={(value, data) => {
|
||||
const dateString = data.at(0)?.payload.date;
|
||||
if (!dateString) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return dateFormatter.format(new Date(dateString));
|
||||
}}
|
||||
// formatter={(value) => {
|
||||
// const numValue = Number(value);
|
||||
// return [` ${formatCurrencyAccurate(numValue)}`];
|
||||
// }}
|
||||
/>
|
||||
<Bar dataKey="dollars" fill="#28BF5C" activeBar={<Rectangle fill="#5ADE87" />} />
|
||||
<Bar dataKey="dollars" fill="var(--color-dollars)" radius={[4, 4, 0, 0]} />
|
||||
</BarChart>
|
||||
</ResponsiveContainer>
|
||||
</ChartContainer>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user