Add a new analitycs page for production
This commit is contained in:
103
frontend/src/components/analytics/production/AnalyticsWidget.tsx
Normal file
103
frontend/src/components/analytics/production/AnalyticsWidget.tsx
Normal file
@@ -0,0 +1,103 @@
|
||||
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>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user