refactor: Simplify usage data extraction and update refresh interval handling in Claude components

This commit is contained in:
Mohamad Yahia
2025-12-21 11:02:54 +04:00
parent 5be85a45b1
commit 7dff6ea0ed
3 changed files with 30 additions and 62 deletions

View File

@@ -316,17 +316,19 @@ export class ClaudeUsageService {
const searchWindow = lines.slice(sectionIndex, sectionIndex + 5);
for (const line of searchWindow) {
// Extract percentage - look for patterns like "65% left" or "35% used"
const percentMatch = line.match(/(\d{1,3})\s*%\s*(left|used|remaining)/i);
if (percentMatch) {
const value = parseInt(percentMatch[1], 10);
const isUsed = percentMatch[2].toLowerCase() === "used";
// Convert "left" to "used" percentage (our UI shows % used)
percentage = isUsed ? value : (100 - value);
// Extract percentage - only take the first match (avoid picking up next section's data)
if (percentage === 0) {
const percentMatch = line.match(/(\d{1,3})\s*%\s*(left|used|remaining)/i);
if (percentMatch) {
const value = parseInt(percentMatch[1], 10);
const isUsed = percentMatch[2].toLowerCase() === "used";
// Convert "left" to "used" percentage (our UI shows % used)
percentage = isUsed ? value : (100 - value);
}
}
// Extract reset time
if (line.toLowerCase().includes("reset")) {
// Extract reset time - only take the first match
if (!resetText && line.toLowerCase().includes("reset")) {
resetText = line;
}
}

View File

@@ -31,9 +31,11 @@ type UsageError = {
message: string;
};
// Fixed refresh interval (45 seconds)
const REFRESH_INTERVAL_SECONDS = 45;
export function ClaudeUsagePopover() {
const { claudeRefreshInterval, claudeUsage, claudeUsageLastUpdated, setClaudeUsage } =
useAppStore();
const { claudeUsage, claudeUsageLastUpdated, setClaudeUsage } = useAppStore();
const [open, setOpen] = useState(false);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<UsageError | null>(null);
@@ -94,16 +96,16 @@ export function ClaudeUsagePopover() {
// Auto-refresh interval (only when open)
let intervalId: NodeJS.Timeout | null = null;
if (open && claudeRefreshInterval > 0) {
if (open) {
intervalId = setInterval(() => {
fetchUsage(true);
}, claudeRefreshInterval * 1000);
}, REFRESH_INTERVAL_SECONDS * 1000);
}
return () => {
if (intervalId) clearInterval(intervalId);
};
}, [open, claudeUsage, isStale, claudeRefreshInterval, fetchUsage]);
}, [open, claudeUsage, isStale, fetchUsage]);
// Derived status color/icon helper
const getStatusInfo = (percentage: number) => {
@@ -244,14 +246,16 @@ export function ClaudeUsagePopover() {
<div className="flex items-center gap-2">
<span className="text-sm font-semibold">Claude Usage</span>
</div>
<Button
variant="ghost"
size="icon"
className={cn('h-6 w-6', loading && 'opacity-80')}
onClick={() => !loading && fetchUsage(false)}
>
<RefreshCw className="w-3.5 h-3.5" />
</Button>
{error && (
<Button
variant="ghost"
size="icon"
className={cn('h-6 w-6', loading && 'opacity-80')}
onClick={() => !loading && fetchUsage(false)}
>
<RefreshCw className="w-3.5 h-3.5" />
</Button>
)}
</div>
{/* Content */}
@@ -337,7 +341,7 @@ export function ClaudeUsagePopover() {
Claude Status <ExternalLink className="w-2.5 h-2.5" />
</a>
<div className="flex gap-2">{/* Could add quick settings link here */}</div>
<span className="text-[10px] text-muted-foreground">Updates every minute</span>
</div>
</PopoverContent>
</Popover>

View File

@@ -1,18 +1,6 @@
import { Clock } from "lucide-react";
import { cn } from "@/lib/utils";
import { useState, useEffect } from "react";
import { Slider } from "@/components/ui/slider";
import { useAppStore } from "@/store/app-store";
export function ClaudeUsageSection() {
const { claudeRefreshInterval, setClaudeRefreshInterval } = useAppStore();
const [localInterval, setLocalInterval] = useState(claudeRefreshInterval);
// Sync local state with store when store changes (e.g. initial load)
useEffect(() => {
setLocalInterval(claudeRefreshInterval);
}, [claudeRefreshInterval]);
return (
<div
className={cn(
@@ -40,35 +28,9 @@ export function ClaudeUsageSection() {
<ol className="list-decimal list-inside space-y-1 ml-1">
<li>Install Claude Code CLI if not already installed</li>
<li>Run <code className="font-mono bg-muted px-1 rounded">claude login</code> to authenticate</li>
<li>Usage data will be fetched automatically</li>
<li>Usage data will be fetched automatically every ~minute</li>
</ol>
</div>
{/* Refresh Interval Section */}
<div className="space-y-4">
<div className="space-y-1">
<h3 className="text-sm font-medium text-foreground flex items-center gap-2">
<Clock className="w-4 h-4 text-muted-foreground" />
Refresh Interval
</h3>
<p className="text-xs text-muted-foreground">
How often to check for usage updates.
</p>
</div>
<div className="flex items-center gap-4">
<Slider
value={[Math.max(30, Math.min(120, localInterval || 30))]}
onValueChange={(vals) => setLocalInterval(vals[0])}
onValueCommit={(vals) => setClaudeRefreshInterval(vals[0])}
min={30}
max={120}
step={5}
className="flex-1"
/>
<span className="w-12 text-sm font-mono text-right">{Math.max(30, Math.min(120, localInterval || 30))}s</span>
</div>
</div>
</div>
</div>
);