Files
bakery-ia/frontend/src/pages/app/analytics/ProductionAnalyticsPage.tsx
2025-10-23 07:44:54 +02:00

271 lines
8.1 KiB
TypeScript

import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import {
Factory,
DollarSign,
Award,
Settings,
Brain,
Lock,
BarChart3,
TrendingUp,
Target,
Zap
} from 'lucide-react';
import { PageHeader } from '../../../components/layout';
import { Card, StatsGrid, Button, Tabs } from '../../../components/ui';
import { useSubscription } from '../../../api/hooks/subscription';
import { useCurrentTenant } from '../../../stores/tenant.store';
import { useProductionDashboard } from '../../../api/hooks/production';
// Import all analytics widgets
import {
TodaysScheduleSummaryWidget,
LiveBatchTrackerWidget,
OnTimeCompletionWidget,
CapacityUtilizationWidget,
CostPerUnitWidget,
WasteDefectTrackerWidget,
YieldPerformanceWidget,
QualityScoreTrendsWidget,
TopDefectTypesWidget,
EquipmentStatusWidget,
MaintenanceScheduleWidget,
EquipmentEfficiencyWidget,
AIInsightsWidget,
PredictiveMaintenanceWidget
} from '../../../components/domain/production/analytics/widgets';
const ProductionAnalyticsPage: React.FC = () => {
const { t } = useTranslation('production');
const { canAccessAnalytics, subscriptionInfo } = useSubscription();
const currentTenant = useCurrentTenant();
const tenantId = currentTenant?.id || '';
const [activeTab, setActiveTab] = useState('overview');
const { data: dashboard, isLoading: dashboardLoading } = useProductionDashboard(tenantId);
// Check if user has access to advanced analytics (professional/enterprise)
const hasAdvancedAccess = canAccessAnalytics('advanced');
// Show loading state while subscription data is being fetched
if (subscriptionInfo.loading) {
return (
<div className="space-y-6">
<PageHeader
title={t('analytics.production_analytics')}
description={t('analytics.advanced_insights_professionals_enterprises')}
/>
<Card className="p-8 text-center">
<div className="flex flex-col items-center gap-4">
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-[var(--color-primary)]"></div>
<p className="text-[var(--text-secondary)]">{t('common.loading') || 'Cargando información de suscripción...'}</p>
</div>
</Card>
</div>
);
}
// If user doesn't have access to advanced analytics, show upgrade message
if (!hasAdvancedAccess) {
return (
<div className="space-y-6">
<PageHeader
title={t('analytics.production_analytics')}
description={t('analytics.advanced_insights_professionals_enterprises')}
/>
<Card className="p-8 text-center">
<Lock className="mx-auto h-12 w-12 text-[var(--text-tertiary)] mb-4" />
<h3 className="text-lg font-medium text-[var(--text-primary)] mb-2">
{t('subscription.exclusive_professional_enterprise')}
</h3>
<p className="text-[var(--text-secondary)] mb-4">
{t('subscription.advanced_production_analytics_description')}
</p>
<Button
variant="primary"
size="md"
onClick={() => window.location.hash = '#/app/settings/profile'}
>
{t('subscription.upgrade_plan')}
</Button>
</Card>
</div>
);
}
// Tab configuration
const tabs = [
{
id: 'overview',
label: t('tabs.overview'),
icon: BarChart3
},
{
id: 'operations',
label: t('tabs.bakery_operations'),
icon: Factory
},
{
id: 'cost-efficiency',
label: t('tabs.cost_efficiency'),
icon: DollarSign
},
{
id: 'quality',
label: t('tabs.quality_assurance'),
icon: Award
},
{
id: 'equipment',
label: t('tabs.equipment_maintenance'),
icon: Settings
},
{
id: 'ai-insights',
label: t('tabs.ai_insights'),
icon: Brain
}
];
return (
<div className="space-y-6">
<PageHeader
title={t('analytics.production_analytics')}
description={t('analytics.advanced_insights_professionals_enterprises')}
actions={
<div className="flex space-x-2">
<Button variant="outline" size="sm">
<TrendingUp className="w-4 h-4 mr-2" />
{t('actions.export_report')}
</Button>
<Button variant="primary" size="sm">
<Zap className="w-4 h-4 mr-2" />
{t('actions.optimize_production')}
</Button>
</div>
}
/>
{/* Key Performance Indicators */}
<StatsGrid
stats={[
{
title: t('stats.overall_efficiency'),
value: dashboard?.efficiency_percentage ? `${dashboard.efficiency_percentage.toFixed(1)}%` : '94%',
variant: 'success' as const,
icon: Target,
subtitle: t('stats.vs_target_95')
},
{
title: t('stats.average_cost_per_unit'),
value: '€2.45',
variant: 'info' as const,
icon: DollarSign,
subtitle: t('stats.down_3_vs_last_week')
},
{
title: t('stats.active_equipment'),
value: '8/9',
variant: 'warning' as const,
icon: Settings,
subtitle: t('stats.one_in_maintenance')
},
{
title: t('stats.quality_score'),
value: dashboard?.average_quality_score ? `${dashboard.average_quality_score.toFixed(1)}/10` : '9.2/10',
variant: 'success' as const,
icon: Award,
subtitle: t('stats.excellent_standards')
}
]}
columns={4}
/>
{/* Analytics Tabs */}
<Tabs
items={tabs.map(tab => ({ id: tab.id, label: tab.label }))}
activeTab={activeTab}
onTabChange={setActiveTab}
/>
{/* Tab Content */}
<div className="min-h-screen">
{/* Overview Tab - Mixed Dashboard */}
{activeTab === 'overview' && (
<div className="grid gap-6">
<LiveBatchTrackerWidget />
<OnTimeCompletionWidget />
<QualityScoreTrendsWidget />
<WasteDefectTrackerWidget />
<CapacityUtilizationWidget />
</div>
)}
{/* Bakery Operations Tab */}
{activeTab === 'operations' && (
<div className="grid gap-6">
<TodaysScheduleSummaryWidget />
<OnTimeCompletionWidget />
<LiveBatchTrackerWidget />
<CapacityUtilizationWidget />
</div>
)}
{/* Cost & Efficiency Tab */}
{activeTab === 'cost-efficiency' && (
<div className="grid gap-6">
<CostPerUnitWidget />
<WasteDefectTrackerWidget />
<YieldPerformanceWidget />
</div>
)}
{/* Quality Assurance Tab */}
{activeTab === 'quality' && (
<div className="grid gap-6">
<QualityScoreTrendsWidget />
<WasteDefectTrackerWidget />
<TopDefectTypesWidget />
</div>
)}
{/* Equipment & Maintenance Tab */}
{activeTab === 'equipment' && (
<div className="grid gap-6">
<EquipmentStatusWidget />
<MaintenanceScheduleWidget />
<EquipmentEfficiencyWidget />
</div>
)}
{/* AI Insights Tab */}
{activeTab === 'ai-insights' && (
<div className="grid gap-6">
<AIInsightsWidget />
<PredictiveMaintenanceWidget />
</div>
)}
</div>
{/* Mobile Optimization Notice */}
<div className="md:hidden p-4 bg-blue-50 dark:bg-blue-900/20 rounded-lg">
<div className="flex items-start space-x-3">
<Target className="w-5 h-5 mt-0.5 text-blue-600 flex-shrink-0" />
<div>
<p className="text-sm font-medium text-blue-600">
{t('mobile.optimized_experience')}
</p>
<p className="text-xs text-[var(--text-secondary)] mt-1">
{t('mobile.swipe_scroll_interact')}
</p>
</div>
</div>
</div>
</div>
);
};
export default ProductionAnalyticsPage;