103 lines
3.6 KiB
TypeScript
103 lines
3.6 KiB
TypeScript
import React from 'react';
|
|
import { Card } from '../../../ui';
|
|
import { LucideIcon } from 'lucide-react';
|
|
|
|
export interface AnalyticsWidgetProps {
|
|
title: string;
|
|
subtitle?: string;
|
|
icon?: LucideIcon;
|
|
loading?: boolean;
|
|
error?: string;
|
|
className?: string;
|
|
children: React.ReactNode;
|
|
actions?: React.ReactNode;
|
|
}
|
|
|
|
export const AnalyticsWidget: React.FC<AnalyticsWidgetProps> = ({
|
|
title,
|
|
subtitle,
|
|
icon: Icon,
|
|
loading = false,
|
|
error,
|
|
className = '',
|
|
children,
|
|
actions
|
|
}) => {
|
|
if (error) {
|
|
return (
|
|
<Card className={`p-6 ${className}`}>
|
|
<div className="flex items-center justify-between mb-4">
|
|
<div className="flex items-center space-x-3">
|
|
{Icon && (
|
|
<div className="w-10 h-10 bg-red-100 dark:bg-red-900/20 rounded-lg flex items-center justify-center">
|
|
<Icon className="w-5 h-5 text-red-600 dark:text-red-400" />
|
|
</div>
|
|
)}
|
|
<div>
|
|
<h3 className="text-lg font-semibold text-[var(--text-primary)]">{title}</h3>
|
|
{subtitle && <p className="text-sm text-[var(--text-secondary)]">{subtitle}</p>}
|
|
</div>
|
|
</div>
|
|
{actions}
|
|
</div>
|
|
<div className="text-center py-8">
|
|
<div className="w-12 h-12 mx-auto bg-red-100 dark:bg-red-900/20 rounded-lg flex items-center justify-center mb-3">
|
|
{Icon && <Icon className="w-6 h-6 text-red-600 dark:text-red-400" />}
|
|
</div>
|
|
<p className="text-sm text-red-600 dark:text-red-400">Error: {error}</p>
|
|
</div>
|
|
</Card>
|
|
);
|
|
}
|
|
|
|
if (loading) {
|
|
return (
|
|
<Card className={`p-6 ${className}`}>
|
|
<div className="flex items-center justify-between mb-4">
|
|
<div className="flex items-center space-x-3">
|
|
{Icon && (
|
|
<div className="w-10 h-10 bg-[var(--bg-tertiary)] rounded-lg flex items-center justify-center">
|
|
<Icon className="w-5 h-5 text-[var(--text-tertiary)]" />
|
|
</div>
|
|
)}
|
|
<div>
|
|
<h3 className="text-lg font-semibold text-[var(--text-primary)]">{title}</h3>
|
|
{subtitle && <p className="text-sm text-[var(--text-secondary)]">{subtitle}</p>}
|
|
</div>
|
|
</div>
|
|
{actions}
|
|
</div>
|
|
<div className="animate-pulse">
|
|
<div className="h-4 bg-[var(--bg-tertiary)] rounded w-3/4 mb-3"></div>
|
|
<div className="h-4 bg-[var(--bg-tertiary)] rounded w-1/2 mb-3"></div>
|
|
<div className="h-8 bg-[var(--bg-tertiary)] rounded w-full mb-4"></div>
|
|
<div className="space-y-2">
|
|
<div className="h-4 bg-[var(--bg-tertiary)] rounded"></div>
|
|
<div className="h-4 bg-[var(--bg-tertiary)] rounded w-5/6"></div>
|
|
<div className="h-4 bg-[var(--bg-tertiary)] rounded w-4/6"></div>
|
|
</div>
|
|
</div>
|
|
</Card>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<Card className={`p-6 ${className}`}>
|
|
<div className="flex items-center justify-between mb-4">
|
|
<div className="flex items-center space-x-3">
|
|
{Icon && (
|
|
<div className="w-10 h-10 bg-[var(--color-primary)]/10 rounded-lg flex items-center justify-center">
|
|
<Icon className="w-5 h-5 text-[var(--color-primary)]" />
|
|
</div>
|
|
)}
|
|
<div>
|
|
<h3 className="text-lg font-semibold text-[var(--text-primary)]">{title}</h3>
|
|
{subtitle && <p className="text-sm text-[var(--text-secondary)]">{subtitle}</p>}
|
|
</div>
|
|
</div>
|
|
{actions}
|
|
</div>
|
|
{children}
|
|
</Card>
|
|
);
|
|
}; |