fix: handle NaN percentage values and rename opus to sonnet

- Show 'N/A' and dim card when percentage is NaN/invalid
- Use gray progress bar for invalid values
- Rename opusWeekly* properties to sonnetWeekly* to match server types
This commit is contained in:
Mohamad Yahia
2025-12-21 08:32:30 +04:00
parent 6533a15653
commit f2582c4453
3 changed files with 31 additions and 23 deletions

View File

@@ -123,7 +123,11 @@ export function ClaudeUsagePopover() {
isPrimary?: boolean;
stale?: boolean;
}) => {
const status = getStatusInfo(percentage);
// Check if percentage is valid (not NaN, not undefined, is a finite number)
const isValidPercentage = typeof percentage === "number" && !isNaN(percentage) && isFinite(percentage);
const safePercentage = isValidPercentage ? percentage : 0;
const status = getStatusInfo(safePercentage);
const StatusIcon = status.icon;
return (
@@ -131,7 +135,7 @@ export function ClaudeUsagePopover() {
className={cn(
"rounded-xl border bg-card/50 p-4 transition-opacity",
isPrimary ? "border-border/60 shadow-sm" : "border-border/40",
stale && "opacity-60"
(stale || !isValidPercentage) && "opacity-50"
)}
>
<div className="flex items-start justify-between mb-3">
@@ -141,20 +145,24 @@ export function ClaudeUsagePopover() {
</h4>
<p className="text-[10px] text-muted-foreground">{subtitle}</p>
</div>
<div className="flex items-center gap-1.5">
<StatusIcon className={cn("w-3.5 h-3.5", status.color)} />
<span
className={cn(
"font-mono font-bold",
status.color,
isPrimary ? "text-base" : "text-sm"
)}
>
{Math.round(percentage)}%
</span>
</div>
{isValidPercentage ? (
<div className="flex items-center gap-1.5">
<StatusIcon className={cn("w-3.5 h-3.5", status.color)} />
<span
className={cn(
"font-mono font-bold",
status.color,
isPrimary ? "text-base" : "text-sm"
)}
>
{Math.round(safePercentage)}%
</span>
</div>
) : (
<span className="text-xs text-muted-foreground">N/A</span>
)}
</div>
<ProgressBar percentage={percentage} colorClass={status.bg} />
<ProgressBar percentage={safePercentage} colorClass={isValidPercentage ? status.bg : "bg-muted-foreground/30"} />
{resetText && (
<div className="mt-2 flex justify-end">
<p className="text-xs text-muted-foreground flex items-center gap-1">
@@ -267,8 +275,8 @@ export function ClaudeUsagePopover() {
<UsageCard
title="Sonnet"
subtitle="Weekly"
percentage={claudeUsage.opusWeeklyPercentage}
resetText={claudeUsage.opusResetText}
percentage={claudeUsage.sonnetWeeklyPercentage}
resetText={claudeUsage.sonnetResetText}
stale={isStale}
/>
</div>

View File

@@ -898,9 +898,9 @@ const getMockElectronAPI = (): ElectronAPI => {
weeklyPercentage: 5,
weeklyResetTime: new Date(Date.now() + 86400000 * 2).toISOString(),
weeklyResetText: "Resets Dec 23",
opusWeeklyTokensUsed: 0,
opusWeeklyPercentage: 1,
opusResetText: "Resets Dec 27",
sonnetWeeklyTokensUsed: 0,
sonnetWeeklyPercentage: 1,
sonnetResetText: "Resets Dec 27",
costUsed: null,
costLimit: null,
costCurrency: null,

View File

@@ -528,9 +528,9 @@ export interface ClaudeUsage {
weeklyResetTime: string;
weeklyResetText: string;
opusWeeklyTokensUsed: number;
opusWeeklyPercentage: number;
opusResetText: string;
sonnetWeeklyTokensUsed: number;
sonnetWeeklyPercentage: number;
sonnetResetText: string;
costUsed: number | null;
costLimit: number | null;