374 lines
12 KiB
TypeScript
374 lines
12 KiB
TypeScript
'use client';
|
|
|
|
import {
|
|
useMunicipalityQuery,
|
|
useParishQuery,
|
|
useStateQuery,
|
|
} from '@/feactures/location/hooks/use-query-location';
|
|
import { Button } from '@repo/shadcn/button';
|
|
import {
|
|
Card,
|
|
CardContent,
|
|
CardDescription,
|
|
CardHeader,
|
|
CardTitle,
|
|
} from '@repo/shadcn/card';
|
|
import { Input } from '@repo/shadcn/input';
|
|
import {
|
|
Select,
|
|
SelectContent,
|
|
SelectItem,
|
|
SelectTrigger,
|
|
SelectValue,
|
|
} from '@repo/shadcn/select';
|
|
import { SelectSearchable } from '@repo/shadcn/select-searchable';
|
|
import { useState } from 'react';
|
|
import {
|
|
Bar,
|
|
BarChart,
|
|
CartesianGrid,
|
|
Cell,
|
|
Legend,
|
|
Pie,
|
|
PieChart,
|
|
ResponsiveContainer,
|
|
Tooltip,
|
|
XAxis,
|
|
YAxis,
|
|
} from 'recharts';
|
|
import { useTrainingStatsQuery } from '../hooks/use-training-statistics';
|
|
|
|
const OSP_TYPES = [
|
|
'EPSD',
|
|
'EPSI',
|
|
'UPF',
|
|
'Cooperativa',
|
|
'Grupo de Intercambio',
|
|
];
|
|
|
|
export function TrainingStatistics() {
|
|
// Filter State
|
|
const [startDate, setStartDate] = useState<string>('');
|
|
const [endDate, setEndDate] = useState<string>('');
|
|
const [stateId, setStateId] = useState<number>(0);
|
|
const [municipalityId, setMunicipalityId] = useState<number>(0);
|
|
const [parishId, setParishId] = useState<number>(0);
|
|
const [ospType, setOspType] = useState<string>('');
|
|
|
|
// Location Data
|
|
const { data: dataState } = useStateQuery();
|
|
const { data: dataMunicipality } = useMunicipalityQuery(stateId);
|
|
const { data: dataParish } = useParishQuery(municipalityId);
|
|
|
|
const stateOptions = dataState?.data || [{ id: 0, name: 'Sin estados' }];
|
|
const municipalityOptions =
|
|
Array.isArray(dataMunicipality?.data) && dataMunicipality.data.length > 0
|
|
? dataMunicipality.data
|
|
: [{ id: 0, stateId: 0, name: 'Sin Municipios' }];
|
|
const parishOptions =
|
|
Array.isArray(dataParish?.data) && dataParish.data.length > 0
|
|
? dataParish.data
|
|
: [{ id: 0, stateId: 0, name: 'Sin Parroquias' }];
|
|
|
|
// Query with Filters
|
|
const { data, isLoading, refetch } = useTrainingStatsQuery({
|
|
startDate: startDate || undefined,
|
|
endDate: endDate || undefined,
|
|
stateId: stateId || undefined,
|
|
municipalityId: municipalityId || undefined,
|
|
parishId: parishId || undefined,
|
|
ospType: ospType || undefined,
|
|
});
|
|
|
|
const handleClearFilters = () => {
|
|
setStartDate('');
|
|
setEndDate('');
|
|
setStateId(0);
|
|
setMunicipalityId(0);
|
|
setParishId(0);
|
|
setOspType('');
|
|
};
|
|
|
|
if (isLoading) {
|
|
return (
|
|
<div className="flex justify-center p-8">Cargando estadísticas...</div>
|
|
);
|
|
}
|
|
|
|
if (!data) {
|
|
return (
|
|
<div className="flex justify-center p-8">No hay datos disponibles.</div>
|
|
);
|
|
}
|
|
|
|
const {
|
|
totalOsps,
|
|
totalProducers,
|
|
statusDistribution,
|
|
activityDistribution,
|
|
typeDistribution,
|
|
stateDistribution,
|
|
yearDistribution,
|
|
} = data;
|
|
|
|
const COLORS = [
|
|
'#0088FE',
|
|
'#00C49F',
|
|
'#FFBB28',
|
|
'#FF8042',
|
|
'#8884d8',
|
|
'#82ca9d',
|
|
];
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
{/* Filters Section */}
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Filtros</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="grid grid-cols-1 md:grid-cols-3 lg:grid-cols-4 gap-4">
|
|
<div className="space-y-2">
|
|
<label className="text-sm font-medium">Fecha Inicio</label>
|
|
<Input
|
|
type="date"
|
|
value={startDate}
|
|
onChange={(e) => setStartDate(e.target.value)}
|
|
/>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<label className="text-sm font-medium">Fecha Fin</label>
|
|
<Input
|
|
type="date"
|
|
value={endDate}
|
|
onChange={(e) => setEndDate(e.target.value)}
|
|
/>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<label className="text-sm font-medium">Estado</label>
|
|
<SelectSearchable
|
|
options={stateOptions.map((item) => ({
|
|
value: item.id.toString(),
|
|
label: item.name,
|
|
}))}
|
|
onValueChange={(value: any) => {
|
|
setStateId(Number(value));
|
|
setMunicipalityId(0); // Reset municipality
|
|
setParishId(0); // Reset parish
|
|
}}
|
|
placeholder="Selecciona un estado"
|
|
defaultValue={stateId ? stateId.toString() : ''}
|
|
/>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<label className="text-sm font-medium">Municipio</label>
|
|
<SelectSearchable
|
|
options={municipalityOptions.map((item) => ({
|
|
value: item.id.toString(),
|
|
label: item.name,
|
|
}))}
|
|
onValueChange={(value: any) => {
|
|
setMunicipalityId(Number(value));
|
|
setParishId(0);
|
|
}}
|
|
placeholder="Selecciona municipio"
|
|
defaultValue={municipalityId ? municipalityId.toString() : ''}
|
|
disabled={!stateId || stateId === 0}
|
|
/>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<label className="text-sm font-medium">Parroquia</label>
|
|
<SelectSearchable
|
|
options={parishOptions.map((item) => ({
|
|
value: item.id.toString(),
|
|
label: item.name,
|
|
}))}
|
|
onValueChange={(value: any) => setParishId(Number(value))}
|
|
placeholder="Selecciona parroquia"
|
|
defaultValue={parishId ? parishId.toString() : ''}
|
|
disabled={!municipalityId || municipalityId === 0}
|
|
/>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<label className="text-sm font-medium">Tipo de OSP</label>
|
|
<Select value={ospType} onValueChange={setOspType}>
|
|
<SelectTrigger>
|
|
<SelectValue placeholder="Todos" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="all">Todos</SelectItem>
|
|
{OSP_TYPES.map((type) => (
|
|
<SelectItem key={type} value={type}>
|
|
{type}
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
<div className="flex items-end">
|
|
<Button variant="outline" onClick={handleClearFilters}>
|
|
Limpiar Filtros
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Statistics Cards */}
|
|
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
|
|
<Card>
|
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
<CardTitle className="text-sm font-medium">
|
|
Total de OSP Registradas
|
|
</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="text-2xl font-bold">{totalOsps}</div>
|
|
<p className="text-xs text-muted-foreground">
|
|
Organizaciones Socioproductivas
|
|
</p>
|
|
</CardContent>
|
|
</Card>
|
|
<Card>
|
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
<CardTitle className="text-sm font-medium">
|
|
Total de Productores
|
|
</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="text-2xl font-bold">{totalProducers}</div>
|
|
<p className="text-xs text-muted-foreground">
|
|
Productores asociados
|
|
</p>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card className="col-span-full">
|
|
<CardHeader>
|
|
<CardTitle>Actividad Productiva</CardTitle>
|
|
<CardDescription>
|
|
Distribución por tipo de actividad
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="h-[400px]">
|
|
<ResponsiveContainer width="100%" height="100%">
|
|
<BarChart
|
|
data={activityDistribution}
|
|
layout="vertical"
|
|
margin={{ top: 5, right: 30, left: 20, bottom: 5 }}
|
|
>
|
|
<CartesianGrid strokeDasharray="3 3" />
|
|
<XAxis type="number" />
|
|
<YAxis dataKey="name" type="category" width={150} />
|
|
<Tooltip wrapperStyle={{ color: '#000' }} />
|
|
<Legend />
|
|
<Bar dataKey="value" fill="#8884d8" name="Cantidad" />
|
|
</BarChart>
|
|
</ResponsiveContainer>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* State Distribution */}
|
|
{/* <Card className="col-span-full">
|
|
<CardHeader>
|
|
<CardTitle>Distribución por Estado</CardTitle>
|
|
<CardDescription>OSP registradas por estado</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="h-[400px]">
|
|
<ResponsiveContainer width="100%" height="100%">
|
|
<BarChart
|
|
data={stateDistribution}
|
|
margin={{ top: 5, right: 30, left: 20, bottom: 5 }}
|
|
>
|
|
<CartesianGrid strokeDasharray="3 3" />
|
|
<XAxis dataKey="name" />
|
|
<YAxis />
|
|
<Tooltip wrapperStyle={{ color: '#000' }} />
|
|
<Legend />
|
|
<Bar dataKey="value" fill="#00C49F" name="Cantidad" />
|
|
</BarChart>
|
|
</ResponsiveContainer>
|
|
</CardContent>
|
|
</Card> */}
|
|
|
|
{/* Year Distribution */}
|
|
<Card className="col-span-full lg:col-span-1">
|
|
<CardHeader>
|
|
<CardTitle>Año de Constitución</CardTitle>
|
|
<CardDescription>Año de registro de la empresa</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="h-[400px]">
|
|
<ResponsiveContainer width="100%" height="100%">
|
|
<BarChart
|
|
data={yearDistribution}
|
|
margin={{ top: 5, right: 30, left: 20, bottom: 5 }}
|
|
>
|
|
<CartesianGrid strokeDasharray="3 3" />
|
|
<XAxis dataKey="name" />
|
|
<YAxis />
|
|
<Tooltip wrapperStyle={{ color: '#000' }} />
|
|
<Legend />
|
|
<Bar dataKey="value" fill="#FFBB28" name="Cantidad" />
|
|
</BarChart>
|
|
</ResponsiveContainer>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card className="col-span-1 md:col-span-2 lg:col-span-1">
|
|
<CardHeader>
|
|
<CardTitle>Estatus Actual</CardTitle>
|
|
<CardDescription>Estado operativo de las OSP</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="h-[300px]">
|
|
<ResponsiveContainer width="100%" height="100%">
|
|
<PieChart>
|
|
<Pie
|
|
data={statusDistribution}
|
|
cx="50%"
|
|
cy="50%"
|
|
innerRadius={60}
|
|
outerRadius={80}
|
|
fill="#8884d8"
|
|
paddingAngle={5}
|
|
dataKey="value"
|
|
>
|
|
{statusDistribution.map((entry, index) => (
|
|
<Cell
|
|
key={`cell-${index}`}
|
|
fill={COLORS[index % COLORS.length]}
|
|
/>
|
|
))}
|
|
</Pie>
|
|
<Tooltip wrapperStyle={{ color: '#000' }} />
|
|
<Legend />
|
|
</PieChart>
|
|
</ResponsiveContainer>
|
|
</CardContent>
|
|
</Card>
|
|
<Card className="col-span-1 md:col-span-2 lg:col-span-1">
|
|
<CardHeader>
|
|
<CardTitle>Tipo de Organización</CardTitle>
|
|
<CardDescription>Clasificación de las OSP</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="h-[300px]">
|
|
<ResponsiveContainer width="100%" height="100%">
|
|
<BarChart
|
|
data={typeDistribution}
|
|
margin={{ top: 5, right: 30, left: 20, bottom: 5 }}
|
|
>
|
|
<CartesianGrid strokeDasharray="3 3" />
|
|
<XAxis dataKey="name" />
|
|
<YAxis />
|
|
<Tooltip wrapperStyle={{ color: '#000' }} />
|
|
<Legend />
|
|
<Bar dataKey="value" fill="#82ca9d" name="Cantidad" />
|
|
</BarChart>
|
|
</ResponsiveContainer>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|