271 lines
8.1 KiB
TypeScript
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; |