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; isPrimary?: boolean;
stale?: 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; const StatusIcon = status.icon;
return ( return (
@@ -131,7 +135,7 @@ export function ClaudeUsagePopover() {
className={cn( className={cn(
"rounded-xl border bg-card/50 p-4 transition-opacity", "rounded-xl border bg-card/50 p-4 transition-opacity",
isPrimary ? "border-border/60 shadow-sm" : "border-border/40", 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"> <div className="flex items-start justify-between mb-3">
@@ -141,6 +145,7 @@ export function ClaudeUsagePopover() {
</h4> </h4>
<p className="text-[10px] text-muted-foreground">{subtitle}</p> <p className="text-[10px] text-muted-foreground">{subtitle}</p>
</div> </div>
{isValidPercentage ? (
<div className="flex items-center gap-1.5"> <div className="flex items-center gap-1.5">
<StatusIcon className={cn("w-3.5 h-3.5", status.color)} /> <StatusIcon className={cn("w-3.5 h-3.5", status.color)} />
<span <span
@@ -150,11 +155,14 @@ export function ClaudeUsagePopover() {
isPrimary ? "text-base" : "text-sm" isPrimary ? "text-base" : "text-sm"
)} )}
> >
{Math.round(percentage)}% {Math.round(safePercentage)}%
</span> </span>
</div> </div>
) : (
<span className="text-xs text-muted-foreground">N/A</span>
)}
</div> </div>
<ProgressBar percentage={percentage} colorClass={status.bg} /> <ProgressBar percentage={safePercentage} colorClass={isValidPercentage ? status.bg : "bg-muted-foreground/30"} />
{resetText && ( {resetText && (
<div className="mt-2 flex justify-end"> <div className="mt-2 flex justify-end">
<p className="text-xs text-muted-foreground flex items-center gap-1"> <p className="text-xs text-muted-foreground flex items-center gap-1">
@@ -267,8 +275,8 @@ export function ClaudeUsagePopover() {
<UsageCard <UsageCard
title="Sonnet" title="Sonnet"
subtitle="Weekly" subtitle="Weekly"
percentage={claudeUsage.opusWeeklyPercentage} percentage={claudeUsage.sonnetWeeklyPercentage}
resetText={claudeUsage.opusResetText} resetText={claudeUsage.sonnetResetText}
stale={isStale} stale={isStale}
/> />
</div> </div>

View File

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

View File

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