correciones al formulario osp
This commit is contained in:
@@ -1,225 +1,276 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@repo/shadcn/card';
|
||||
import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer, PieChart, Pie, Cell } from 'recharts';
|
||||
import { useTrainingStatsQuery } from '../hooks/use-training-statistics';
|
||||
import { Input } from '@repo/shadcn/input';
|
||||
import { Button } from '@repo/shadcn/button';
|
||||
import { SelectSearchable } from '@repo/shadcn/select-searchable';
|
||||
import { useStateQuery, useMunicipalityQuery, useParishQuery } from '@/feactures/location/hooks/use-query-location';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
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',
|
||||
'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>('');
|
||||
// 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);
|
||||
// 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' }];
|
||||
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,
|
||||
});
|
||||
// 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'];
|
||||
const handleClearFilters = () => {
|
||||
setStartDate('');
|
||||
setEndDate('');
|
||||
setStateId(0);
|
||||
setMunicipalityId(0);
|
||||
setParishId(0);
|
||||
setOspType('');
|
||||
};
|
||||
|
||||
if (isLoading) {
|
||||
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>
|
||||
<div className="flex justify-center p-8">Cargando estadísticas...</div>
|
||||
);
|
||||
}
|
||||
|
||||
{/* 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>
|
||||
if (!data) {
|
||||
return (
|
||||
<div className="flex justify-center p-8">No hay datos disponibles.</div>
|
||||
);
|
||||
}
|
||||
|
||||
<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>
|
||||
const {
|
||||
totalOsps,
|
||||
totalProducers,
|
||||
statusDistribution,
|
||||
activityDistribution,
|
||||
typeDistribution,
|
||||
stateDistribution,
|
||||
yearDistribution,
|
||||
} = data;
|
||||
|
||||
{/* State Distribution */}
|
||||
<Card className="col-span-full">
|
||||
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>
|
||||
@@ -239,81 +290,84 @@ export function TrainingStatistics() {
|
||||
</BarChart>
|
||||
</ResponsiveContainer>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</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>
|
||||
{/* 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>
|
||||
);
|
||||
<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>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user