Skip to content

Commit 9283999

Browse files
committed
fix: a few issues in light mode and overage
1 parent 4ac9499 commit 9283999

File tree

6 files changed

+23015
-4609
lines changed

6 files changed

+23015
-4609
lines changed

apps/dashboard/app/(main)/billing/components/credit-card-display.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export function CreditCardDisplay({ customer }: CreditCardDisplayProps) {
4545
<div
4646
className={cn(
4747
"absolute inset-0 flex flex-col justify-between overflow-hidden rounded-xl p-4",
48-
"bg-linear-to-tr from-foreground to-foreground/80",
48+
"bg-linear-to-tr from-foreground to-foreground/80 dark:from-zinc-800 dark:to-zinc-900",
4949
"before:pointer-events-none before:absolute before:inset-0 before:z-1 before:rounded-[inherit] before:ring-1 before:ring-white/20 before:ring-inset"
5050
)}
5151
>

apps/dashboard/app/(main)/billing/components/usage-row.tsx

Lines changed: 67 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
GiftIcon,
88
LightningIcon,
99
UsersIcon,
10+
WarningIcon,
1011
} from "@phosphor-icons/react";
1112
import Link from "next/link";
1213
import { memo } from "react";
@@ -18,6 +19,16 @@ import {
1819
getResetText,
1920
} from "../utils/feature-usage";
2021

22+
function formatCurrency(amount: number): string {
23+
if (amount >= 1000) {
24+
return `$${(amount / 1000).toFixed(1)}K`;
25+
}
26+
if (amount >= 1) {
27+
return `$${amount.toFixed(2)}`;
28+
}
29+
return `$${amount.toFixed(4)}`;
30+
}
31+
2132
const FEATURE_ICONS: Record<string, typeof ChartBarIcon> = {
2233
event: ChartBarIcon,
2334
storage: DatabaseIcon,
@@ -37,28 +48,19 @@ function getFeatureIcon(name: string): typeof ChartBarIcon {
3748
return ChartBarIcon;
3849
}
3950

40-
type UsageRowProps = {
41-
feature: FeatureUsage;
42-
};
43-
4451
export const UsageRow = memo(function UsageRowComponent({
4552
feature,
46-
}: UsageRowProps) {
47-
const percentage = feature.unlimited
48-
? 0
49-
: feature.limit > 0
50-
? Math.min((feature.used / feature.limit) * 100, 100)
51-
: 0;
52-
53-
const isNearLimit =
54-
!(feature.unlimited || feature.hasExtraCredits) &&
55-
(percentage > 80 || feature.balance < feature.limit * 0.2);
56-
57-
const isOverLimit =
58-
!feature.unlimited && (percentage >= 100 || feature.balance <= 0);
53+
}: {
54+
feature: FeatureUsage;
55+
}) {
56+
const remainingPercent = feature.unlimited
57+
? 100
58+
: Math.min(Math.max((feature.balance / feature.limit) * 100, 0), 100);
59+
const hasNormalLimit = !(feature.unlimited || feature.hasExtraCredits);
60+
const isLow = hasNormalLimit && remainingPercent < 20;
61+
const hasOverage = feature.overage !== null;
5962

6063
const Icon = getFeatureIcon(feature.name);
61-
const resetText = getResetText(feature);
6264

6365
return (
6466
<div className="px-5 py-4">
@@ -83,53 +85,76 @@ export const UsageRow = memo(function UsageRowComponent({
8385
Bonus
8486
</Badge>
8587
)}
88+
{hasOverage && (
89+
<Badge
90+
className="bg-destructive/10 text-destructive"
91+
variant="secondary"
92+
>
93+
<WarningIcon className="mr-1" size={10} weight="fill" />
94+
Overage
95+
</Badge>
96+
)}
8697
</div>
8798
<div className="flex items-center gap-1 text-muted-foreground text-sm">
8899
<ClockIcon size={12} />
89-
{resetText}
100+
{getResetText(feature)}
90101
</div>
91102
</div>
92103
</div>
104+
93105
{feature.unlimited ? (
94106
<Badge variant="secondary">
95107
<LightningIcon className="mr-1" size={12} />
96108
Unlimited
97109
</Badge>
110+
) : feature.hasExtraCredits ? (
111+
<div className="text-right">
112+
<span className="font-mono text-base">
113+
{formatCompactNumber(feature.balance)}
114+
</span>
115+
<div className="text-muted-foreground text-xs">remaining</div>
116+
</div>
117+
) : feature.overage ? (
118+
<div className="text-right">
119+
<span className="font-mono text-base text-destructive">
120+
+{formatCompactNumber(feature.overage.amount)} over
121+
</span>
122+
<div className="text-destructive text-xs">
123+
~{formatCurrency(feature.overage.cost)} overage
124+
</div>
125+
</div>
98126
) : (
99-
<span
100-
className={cn(
101-
"font-mono text-base",
102-
isOverLimit
103-
? "text-destructive"
104-
: isNearLimit
105-
? "text-warning"
106-
: "text-foreground"
107-
)}
108-
>
109-
{formatCompactNumber(feature.used)} /{" "}
110-
{formatCompactNumber(feature.limit)}
111-
</span>
127+
<div className="text-right">
128+
<span
129+
className={cn(
130+
"font-mono text-base",
131+
isLow ? "text-warning" : "text-foreground"
132+
)}
133+
>
134+
{formatCompactNumber(feature.balance)} /{" "}
135+
{formatCompactNumber(feature.limit)}
136+
</span>
137+
<div className="text-muted-foreground text-xs">remaining</div>
138+
</div>
112139
)}
113140
</div>
114141

115-
{!feature.unlimited && (
142+
{hasNormalLimit && (
116143
<div className="flex items-center gap-3">
117144
<div className="h-2 flex-1 overflow-hidden rounded-full bg-muted">
118145
<div
119146
className={cn(
120147
"h-full transition-all",
121-
feature.hasExtraCredits
122-
? "bg-primary"
123-
: isOverLimit
124-
? "bg-destructive"
125-
: isNearLimit
126-
? "bg-warning"
127-
: "bg-primary"
148+
hasOverage
149+
? "bg-destructive"
150+
: isLow
151+
? "bg-warning"
152+
: "bg-primary"
128153
)}
129-
style={{ width: `${percentage}%` }}
154+
style={{ width: hasOverage ? "100%" : `${remainingPercent}%` }}
130155
/>
131156
</div>
132-
{isNearLimit && (
157+
{(isLow || hasOverage) && (
133158
<Link
134159
className="shrink-0 font-medium text-primary text-sm hover:underline"
135160
href="/billing/plans"

0 commit comments

Comments
 (0)