Usage bar chart now supports a paying customer option and optional billing limit. Also added more usage examples to storybook
This commit is contained in:
@@ -3,9 +3,10 @@ import { Paragraph } from "../primitives/Paragraph";
|
||||
|
||||
type UsageBarProps = {
|
||||
numberOfCurrentRuns: number;
|
||||
billingLimit: number;
|
||||
billingLimit?: number | undefined;
|
||||
tierRunLimit: number;
|
||||
projectedRuns: number;
|
||||
subscribedToPaidTier?: boolean;
|
||||
};
|
||||
|
||||
export function UsageBar({
|
||||
@@ -13,9 +14,15 @@ export function UsageBar({
|
||||
billingLimit,
|
||||
tierRunLimit,
|
||||
projectedRuns,
|
||||
subscribedToPaidTier = false,
|
||||
}: UsageBarProps) {
|
||||
//create a maximum range for the progress bar
|
||||
const getLargestNumber = Math.max(numberOfCurrentRuns, tierRunLimit, billingLimit, projectedRuns);
|
||||
const getLargestNumber = Math.max(
|
||||
numberOfCurrentRuns,
|
||||
tierRunLimit,
|
||||
projectedRuns,
|
||||
billingLimit ?? -Infinity
|
||||
);
|
||||
const maxRange = Math.round(getLargestNumber * 1.15);
|
||||
|
||||
//convert the freeRunLimit into a percentage
|
||||
@@ -25,7 +32,8 @@ export function UsageBar({
|
||||
const projectedRunsPercentage = Math.round((projectedRuns / maxRange) * 100);
|
||||
|
||||
//convert the BillingLimit into a percentage
|
||||
const billingLimitPercentage = Math.round((billingLimit / maxRange) * 100);
|
||||
const billingLimitPercentage =
|
||||
billingLimit !== undefined ? Math.round((billingLimit / maxRange) * 100) : 0;
|
||||
|
||||
const usagePercentage = Math.round((numberOfCurrentRuns / maxRange) * 100);
|
||||
|
||||
@@ -33,23 +41,25 @@ export function UsageBar({
|
||||
return (
|
||||
<div className="h-fit w-full py-16">
|
||||
<div className="relative h-3 w-full rounded-sm bg-slate-800">
|
||||
{billingLimit && (
|
||||
<div
|
||||
style={{ width: `${billingLimitPercentage}%` }}
|
||||
className="absolute h-3 rounded-l-sm"
|
||||
>
|
||||
<Legend
|
||||
text="Billing limit:"
|
||||
value={billingLimit}
|
||||
position="bottomRow2"
|
||||
percentage={billingLimitPercentage}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
style={{ width: `${billingLimitPercentage}%` }}
|
||||
style={{ width: `${tierRunLimitPercentage}%` }}
|
||||
className="absolute h-3 rounded-l-sm bg-green-900/50"
|
||||
>
|
||||
<Legend
|
||||
text="Billing limit:"
|
||||
value={billingLimit}
|
||||
position="bottomRow2"
|
||||
percentage={billingLimitPercentage}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
style={{ width: `${tierRunLimitPercentage}%` }}
|
||||
className="absolute h-3 rounded-l-sm bg-green-900"
|
||||
>
|
||||
<Legend
|
||||
text="Free tier limit:"
|
||||
text={`${subscribedToPaidTier ? "Included free:" : "Free tier limit:"}`}
|
||||
value={tierRunLimit}
|
||||
position="bottomRow1"
|
||||
percentage={tierRunLimitPercentage}
|
||||
@@ -66,7 +76,10 @@ export function UsageBar({
|
||||
|
||||
<div
|
||||
style={{ width: `${usagePercentage}%` }}
|
||||
className="absolute h-3 rounded-l-sm bg-red-500"
|
||||
className={cn(
|
||||
"absolute h-3 rounded-l-sm",
|
||||
subscribedToPaidTier ? "bg-green-600" : "bg-rose-600"
|
||||
)}
|
||||
>
|
||||
<Legend
|
||||
text="Current:"
|
||||
@@ -109,7 +122,7 @@ function Legend({ text, value, position, percentage }: LegendProps) {
|
||||
flipLegendPosition === true ? "-translate-x-full border-r" : "border-l"
|
||||
)}
|
||||
>
|
||||
<Paragraph className="h-fit whitespace-nowrap bg-background px-1.5 text-xs text-dimmed">
|
||||
<Paragraph className="mr-px h-fit whitespace-nowrap bg-background px-1.5 text-xs text-dimmed">
|
||||
{text}
|
||||
<span className="ml-1 text-bright">{value}</span>
|
||||
</Paragraph>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import { UsageBar } from "../billing/UsageBar";
|
||||
import { Paragraph } from "../primitives/Paragraph";
|
||||
|
||||
const meta: Meta<typeof UsageProgressBar> = {
|
||||
title: "Billing/UsageBar",
|
||||
@@ -16,25 +17,57 @@ export const JobsUsageBar: Story = {
|
||||
|
||||
function UsageProgressBar() {
|
||||
return (
|
||||
<div className="flex h-screen flex-col items-center justify-center p-12">
|
||||
<UsageBar
|
||||
numberOfCurrentRuns={90000}
|
||||
billingLimit={180000}
|
||||
tierRunLimit={50000}
|
||||
projectedRuns={120000}
|
||||
/>
|
||||
<UsageBar
|
||||
numberOfCurrentRuns={30000}
|
||||
billingLimit={180000}
|
||||
tierRunLimit={50000}
|
||||
projectedRuns={120000}
|
||||
/>
|
||||
<UsageBar
|
||||
numberOfCurrentRuns={90000}
|
||||
billingLimit={180000}
|
||||
tierRunLimit={50000}
|
||||
projectedRuns={120000}
|
||||
/>
|
||||
<div className="flex flex-col justify-center gap-4 p-12">
|
||||
<UsageBarWrapper title="Usage within the free tier limit">
|
||||
<UsageBar numberOfCurrentRuns={30000} tierRunLimit={50000} projectedRuns={120000} />
|
||||
</UsageBarWrapper>
|
||||
<UsageBarWrapper title="Usage over the free tier limit">
|
||||
<UsageBar numberOfCurrentRuns={90000} tierRunLimit={50000} projectedRuns={120000} />
|
||||
</UsageBarWrapper>
|
||||
<UsageBarWrapper title="Billing limit set">
|
||||
<UsageBar
|
||||
numberOfCurrentRuns={30000}
|
||||
tierRunLimit={50000}
|
||||
projectedRuns={120000}
|
||||
billingLimit={180000}
|
||||
/>
|
||||
</UsageBarWrapper>
|
||||
<UsageBarWrapper title="Paid subscriber under the free included Runs">
|
||||
<UsageBar
|
||||
numberOfCurrentRuns={10000}
|
||||
tierRunLimit={50000}
|
||||
billingLimit={180000}
|
||||
projectedRuns={120000}
|
||||
subscribedToPaidTier
|
||||
/>
|
||||
</UsageBarWrapper>
|
||||
<UsageBarWrapper title="Paid subscriber over the free included Runs">
|
||||
<UsageBar
|
||||
numberOfCurrentRuns={90000}
|
||||
tierRunLimit={50000}
|
||||
billingLimit={180000}
|
||||
projectedRuns={120000}
|
||||
subscribedToPaidTier
|
||||
/>
|
||||
</UsageBarWrapper>
|
||||
<UsageBarWrapper title="Overlapping UI example">
|
||||
<UsageBar
|
||||
numberOfCurrentRuns={90000}
|
||||
tierRunLimit={50000}
|
||||
billingLimit={55000}
|
||||
projectedRuns={100000}
|
||||
subscribedToPaidTier
|
||||
/>
|
||||
</UsageBarWrapper>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function UsageBarWrapper({ title, children }: { title: string; children: React.ReactNode }) {
|
||||
return (
|
||||
<div className="rounded-md border border-border p-6">
|
||||
<Paragraph>{title}</Paragraph>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user