Files
Nexus/apps/web/src/components/mobile/MobileCapacityCard.tsx
T
Hartmut 8f7c69056f refactor(web): remove unnecessary "use client" from 6 pure-render components
BenchResourceCard, MobileProjectCard, MobileCapacityCard, DynamicFieldRenderer,
BudgetStatusBar, and TimelineHeader use no hooks, event handlers, or browser APIs —
they can be server components, reducing client bundle size.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-11 23:36:34 +02:00

80 lines
2.5 KiB
TypeScript

interface MobileCapacityCardProps {
totalResources: number;
activeResources: number;
avgUtilizationPct: number;
overbookedCount?: number;
}
export function MobileCapacityCard({
totalResources,
activeResources,
avgUtilizationPct,
overbookedCount = 0,
}: MobileCapacityCardProps) {
const pct = Math.min(100, Math.max(0, avgUtilizationPct));
const circumference = 2 * Math.PI * 34; // radius = 34
const dashOffset = circumference * (1 - pct / 100);
const color = pct >= 90 ? "#d97706" : pct >= 70 ? "#059669" : "#6b7280";
return (
<div className="rounded-2xl border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 p-5">
<div className="text-xs font-semibold uppercase tracking-wider text-gray-500 dark:text-gray-400 mb-4">
Team Capacity
</div>
<div className="flex items-center gap-5">
{/* CSS-only donut */}
<svg width="80" height="80" viewBox="0 0 80 80" className="shrink-0">
<circle
cx="40"
cy="40"
r="34"
fill="none"
stroke="#e5e7eb"
strokeWidth="8"
className="dark:stroke-gray-700"
/>
<circle
cx="40"
cy="40"
r="34"
fill="none"
stroke={color}
strokeWidth="8"
strokeDasharray={circumference}
strokeDashoffset={dashOffset}
strokeLinecap="round"
transform="rotate(-90 40 40)"
/>
<text
x="40"
y="40"
textAnchor="middle"
dominantBaseline="middle"
fontSize="15"
fontWeight="700"
fill={color}
>
{Math.round(pct)}%
</text>
</svg>
<div className="space-y-2 flex-1">
<div className="flex items-center justify-between text-sm">
<span className="text-gray-500 dark:text-gray-400">Resources</span>
<span className="font-semibold text-gray-900 dark:text-gray-100">
{activeResources} / {totalResources}
</span>
</div>
{overbookedCount > 0 && (
<div className="flex items-center justify-between text-sm">
<span className="text-amber-600 dark:text-amber-400">Overbooked</span>
<span className="font-semibold text-amber-600 dark:text-amber-400">
{overbookedCount}
</span>
</div>
)}
</div>
</div>
</div>
);
}