Improve the frontend 4

This commit is contained in:
Urtzi Alfaro
2025-11-01 21:35:03 +01:00
parent f44d235c6d
commit 0220da1725
59 changed files with 5785 additions and 1870 deletions

View File

@@ -12,11 +12,21 @@ import {
Truck,
Calendar
} from 'lucide-react';
import {
LineChart,
Line,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
ResponsiveContainer,
Legend
} from 'recharts';
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 { useProcurementDashboard } from '../../../api/hooks/orders';
import { useProcurementDashboard, useProcurementTrends } from '../../../api/hooks/procurement';
import { formatters } from '../../../components/ui/Stats/StatsPresets';
const ProcurementAnalyticsPage: React.FC = () => {
@@ -27,6 +37,7 @@ const ProcurementAnalyticsPage: React.FC = () => {
const [activeTab, setActiveTab] = useState('overview');
const { data: dashboard, isLoading: dashboardLoading } = useProcurementDashboard(tenantId);
const { data: trends, isLoading: trendsLoading } = useProcurementTrends(tenantId, 7);
// Check if user has access to advanced analytics (professional/enterprise)
const hasAdvancedAccess = canAccessAnalytics('advanced');
@@ -162,32 +173,32 @@ const ProcurementAnalyticsPage: React.FC = () => {
<>
{/* Overview Tab */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{/* Plan Status Distribution */}
<Card>
<div className="p-6">
<h3 className="text-lg font-medium text-[var(--text-primary)] mb-4">
Distribución de Estados de Planes
</h3>
<div className="space-y-3">
{dashboard?.plan_status_distribution?.map((status: any) => (
<div key={status.status} className="flex items-center justify-between">
<span className="text-[var(--text-secondary)]">{status.status}</span>
<div className="flex items-center gap-2">
<div className="w-32 h-2 bg-[var(--bg-tertiary)] rounded-full overflow-hidden">
<div
className="h-full bg-[var(--color-primary)]"
style={{ width: `${(status.count / (dashboard?.summary?.total_plans || 1)) * 100}%` }}
/>
</div>
<span className="text-sm font-medium text-[var(--text-primary)] w-8 text-right">
{status.count}
</span>
{/* Plan Status Distribution */}
<Card>
<div className="p-6">
<h3 className="text-lg font-medium text-[var(--text-primary)] mb-4">
Distribución de Estados de Planes
</h3>
<div className="space-y-3">
{dashboard?.plan_status_distribution?.map((status: any) => (
<div key={status.status} className="flex items-center justify-between">
<span className="text-[var(--text-secondary)]">{status.status}</span>
<div className="flex items-center gap-2">
<div className="w-32 h-2 bg-[var(--bg-tertiary)] rounded-full overflow-hidden">
<div
className="h-full bg-[var(--color-primary)]"
style={{ width: `${(status.count / (dashboard?.summary?.total_plans || 1)) * 100}%` }}
/>
</div>
<span className="text-sm font-medium text-[var(--text-primary)] w-8 text-right">
{status.count}
</span>
</div>
))}
</div>
</div>
))}
</div>
</Card>
</div>
</Card>
{/* Critical Requirements */}
<Card>
@@ -302,15 +313,63 @@ const ProcurementAnalyticsPage: React.FC = () => {
</Card>
</div>
{/* Performance Trend Chart Placeholder */}
{/* Performance Trend Chart */}
<Card>
<div className="p-6">
<h3 className="text-lg font-medium text-[var(--text-primary)] mb-4">
Tendencias de Rendimiento
Tendencias de Rendimiento (Últimos 7 días)
</h3>
<div className="h-64 flex items-center justify-center text-[var(--text-tertiary)]">
Gráfico de tendencias - Próximamente
</div>
{trendsLoading ? (
<div className="h-64 flex items-center justify-center">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-[var(--color-primary)]"></div>
</div>
) : trends && trends.performance_trend && trends.performance_trend.length > 0 ? (
<ResponsiveContainer width="100%" height={300}>
<LineChart data={trends.performance_trend}>
<CartesianGrid strokeDasharray="3 3" stroke="var(--border-primary)" />
<XAxis
dataKey="date"
stroke="var(--text-tertiary)"
tick={{ fill: 'var(--text-secondary)' }}
/>
<YAxis
stroke="var(--text-tertiary)"
tick={{ fill: 'var(--text-secondary)' }}
tickFormatter={(value) => `${(value * 100).toFixed(0)}%`}
/>
<Tooltip
contentStyle={{
backgroundColor: 'var(--bg-primary)',
border: '1px solid var(--border-primary)',
borderRadius: '8px'
}}
formatter={(value: any) => `${(value * 100).toFixed(1)}%`}
labelStyle={{ color: 'var(--text-primary)' }}
/>
<Legend />
<Line
type="monotone"
dataKey="fulfillment_rate"
stroke="var(--color-success)"
strokeWidth={2}
name="Tasa de Cumplimiento"
dot={{ fill: 'var(--color-success)' }}
/>
<Line
type="monotone"
dataKey="on_time_rate"
stroke="var(--color-info)"
strokeWidth={2}
name="Entregas a Tiempo"
dot={{ fill: 'var(--color-info)' }}
/>
</LineChart>
</ResponsiveContainer>
) : (
<div className="h-64 flex items-center justify-center text-[var(--text-tertiary)]">
No hay datos de tendencias disponibles
</div>
)}
</div>
</Card>
</>
@@ -459,11 +518,51 @@ const ProcurementAnalyticsPage: React.FC = () => {
<Card>
<div className="p-6">
<h3 className="text-lg font-medium text-[var(--text-primary)] mb-4">
Tendencia de Calidad
Tendencia de Calidad (Últimos 7 días)
</h3>
<div className="h-48 flex items-center justify-center text-[var(--text-tertiary)]">
Gráfico de tendencia de calidad - Próximamente
</div>
{trendsLoading ? (
<div className="h-48 flex items-center justify-center">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-[var(--color-primary)]"></div>
</div>
) : trends && trends.quality_trend && trends.quality_trend.length > 0 ? (
<ResponsiveContainer width="100%" height={200}>
<LineChart data={trends.quality_trend}>
<CartesianGrid strokeDasharray="3 3" stroke="var(--border-primary)" />
<XAxis
dataKey="date"
stroke="var(--text-tertiary)"
tick={{ fill: 'var(--text-secondary)' }}
/>
<YAxis
stroke="var(--text-tertiary)"
tick={{ fill: 'var(--text-secondary)' }}
domain={[0, 10]}
ticks={[0, 2, 4, 6, 8, 10]}
/>
<Tooltip
contentStyle={{
backgroundColor: 'var(--bg-primary)',
border: '1px solid var(--border-primary)',
borderRadius: '8px'
}}
formatter={(value: any) => `${value.toFixed(1)} / 10`}
labelStyle={{ color: 'var(--text-primary)' }}
/>
<Line
type="monotone"
dataKey="quality_score"
stroke="var(--color-warning)"
strokeWidth={2}
name="Puntuación de Calidad"
dot={{ fill: 'var(--color-warning)' }}
/>
</LineChart>
</ResponsiveContainer>
) : (
<div className="h-48 flex items-center justify-center text-[var(--text-tertiary)]">
No hay datos de calidad disponibles
</div>
)}
</div>
</Card>
</div>