Kyle Pope cbf4663e8d Fix TS build errors and apply remaining QA fixes
Remove unused imports (UserCheck, Loader2, ShieldOff) and replace
non-existent SmartphoneOff icon with Smartphone in admin components.
Includes backend query fixes, performance indexes migration, and
admin page shared utilities extraction.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 04:42:23 +08:00

43 lines
1.7 KiB
TypeScript

import { Card, CardContent } from '@/components/ui/card';
import { cn } from '@/lib/utils';
// ── StatCard ─────────────────────────────────────────────────────────────────
interface StatCardProps {
icon: React.ReactNode;
label: string;
value: string | number;
iconBg?: string;
}
export function StatCard({ icon, label, value, iconBg = 'bg-accent/10' }: StatCardProps) {
return (
<Card className="bg-gradient-to-br from-accent/[0.03] to-transparent">
<CardContent className="p-5">
<div className="flex items-center gap-3">
<div className={cn('p-1.5 rounded-md', iconBg)}>{icon}</div>
<div>
<p className="text-[10px] tracking-wider uppercase text-muted-foreground">{label}</p>
<p className="font-heading text-xl font-bold tabular-nums">{value}</p>
</div>
</div>
</CardContent>
</Card>
);
}
// ── actionColor ──────────────────────────────────────────────────────────────
export function actionColor(action: string): string {
if (action.includes('failed') || action.includes('locked') || action.includes('disabled')) {
return 'bg-red-500/15 text-red-400';
}
if (action.includes('login') || action.includes('create') || action.includes('enabled')) {
return 'bg-green-500/15 text-green-400';
}
if (action.includes('config') || action.includes('role') || action.includes('password')) {
return 'bg-orange-500/15 text-orange-400';
}
return 'bg-blue-500/15 text-blue-400';
}