969dc0ea86
Co-authored-by: Kandev Agent <agent@kandev.dev>
82 lines
2.7 KiB
TypeScript
82 lines
2.7 KiB
TypeScript
"use client";
|
|
|
|
import { Tooltip, TooltipContent, TooltipTrigger } from "@kandev/ui/tooltip";
|
|
import type { ProviderUsage } from "@/lib/state/slices/office/types";
|
|
import type { TFunction } from "i18next";
|
|
import { useTranslation } from "react-i18next";
|
|
|
|
type Props = {
|
|
usage: ProviderUsage;
|
|
};
|
|
|
|
function getBarColor(pct: number): string {
|
|
if (pct >= 90) return "bg-red-500";
|
|
if (pct >= 80) return "bg-amber-500";
|
|
return "bg-blue-500";
|
|
}
|
|
|
|
function getTextColor(pct: number): string {
|
|
if (pct >= 90) return "text-red-600 dark:text-red-400";
|
|
if (pct >= 80) return "text-amber-600 dark:text-amber-400";
|
|
return "text-muted-foreground";
|
|
}
|
|
|
|
// Takes `t` rather than calling the module-level one: the copy here is rendered,
|
|
// not logged, so it has to re-resolve when the locale changes.
|
|
function formatResetTime(t: TFunction, resetAt: string): string {
|
|
const now = Date.now();
|
|
const reset = new Date(resetAt).getTime();
|
|
const diffMs = reset - now;
|
|
if (diffMs <= 0) return t("office:resettingSoon");
|
|
const diffH = Math.floor(diffMs / (1000 * 60 * 60));
|
|
const diffM = Math.floor((diffMs % (1000 * 60 * 60)) / (1000 * 60));
|
|
if (diffH > 0) return t("office:resetsInHoursMinutes", { hours: diffH, minutes: diffM });
|
|
return t("office:resetsInMinutes", { minutes: diffM });
|
|
}
|
|
|
|
function WindowBar({ label, pct, resetAt }: { label: string; pct: number; resetAt: string }) {
|
|
const { t } = useTranslation();
|
|
const clampedPct = Math.min(100, Math.max(0, pct));
|
|
const barColor = getBarColor(clampedPct);
|
|
const textColor = getTextColor(clampedPct);
|
|
|
|
return (
|
|
<Tooltip>
|
|
<TooltipTrigger asChild>
|
|
<div className="space-y-1 cursor-default">
|
|
<div className="flex items-center justify-between text-xs">
|
|
<span className="text-muted-foreground capitalize">{label}</span>
|
|
<span className={`font-medium ${textColor}`}>{Math.round(clampedPct)}%</span>
|
|
</div>
|
|
<div className="h-2 bg-muted rounded-full overflow-hidden">
|
|
<div
|
|
className={`h-full rounded-full transition-all ${barColor}`}
|
|
style={{ width: `${clampedPct}%` }}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</TooltipTrigger>
|
|
<TooltipContent>
|
|
<p className="text-xs">{formatResetTime(t, resetAt)}</p>
|
|
</TooltipContent>
|
|
</Tooltip>
|
|
);
|
|
}
|
|
|
|
export function UtilizationBars({ usage }: Props) {
|
|
const { t } = useTranslation();
|
|
if (!usage || usage.windows.length === 0) {
|
|
return (
|
|
<p className="text-xs text-muted-foreground">{t("office:noUtilizationDataAvailable")}</p>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="space-y-3">
|
|
{usage.windows.map((w) => (
|
|
<WindowBar key={w.label} label={w.label} pct={w.utilization_pct} resetAt={w.reset_at} />
|
|
))}
|
|
</div>
|
|
);
|
|
}
|