Files
motor-de-encuestas/components/dashboard/kpi-cards.tsx

97 lines
3.0 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client'
import { useEffect, useState } from 'react'
import { isSuppressed, type KpiData, type SuppressedPayload } from '@/lib/dashboard-types'
import { queries } from '@/lib/dashboard-queries'
import type { DashboardFilters } from '@/lib/dashboard-types'
const KPI_DEFS = [
{
title: 'CUIDADORES ACTIVOS',
subtitle: '1.6 + 1.13 · % de la plantilla con responsabilidades de cuidado de otros',
getValue: (d: KpiData) => `${d.pct_cuidadores}%`,
getN: (d: KpiData) => `n = ${d.n}`,
},
{
title: 'FRECUENCIA DE AUSENTISMO',
subtitle: '5.2 · % con ausencias laborales recurrentes (4 o más veces al año)',
getValue: (d: KpiData) => `${d.pct_ausencias}%`,
getN: () => 'ausencias frecuentes',
},
{
title: 'BIENESTAR',
subtitle: '4.3 · autorreporte de bienestar general · escala 15',
getValue: (d: KpiData) => d.score_bienestar !== null ? d.score_bienestar.toFixed(1) : '—',
getN: () => '/ 5',
},
] as const
interface KpiCardProps {
title: string
subtitle: string
value: string
valueNote: string
suppressed: boolean
loading: boolean
}
function KpiCard({ title, subtitle, value, valueNote, suppressed, loading }: KpiCardProps) {
return (
<div className="db-kpi-card">
<span className="db-kpi-title">{title}</span>
<span className="db-kpi-subtitle">{subtitle}</span>
{loading && (
<div className="db-skeleton-block" style={{ height: 36, margin: '10px 0 4px', borderRadius: 6 }} />
)}
{!loading && suppressed && (
<div className="db-kpi-suppressed-block" role="status">
<span className="db-suppressed-icon" aria-hidden="true">🔒</span>
<span className="db-kpi-value db-kpi-value-suppressed">n &lt; 5</span>
</div>
)}
{!loading && !suppressed && (
<>
<span className="db-kpi-value" aria-live="polite">{value}</span>
<span className="db-kpi-note">{valueNote}</span>
</>
)}
</div>
)
}
interface Props { surveyId: string; filters: DashboardFilters }
export function KpiCards({ surveyId, filters }: Props) {
const [data, setData] = useState<KpiData | SuppressedPayload | null>(null)
const [error, setError] = useState(false)
useEffect(() => {
setData(null); setError(false)
queries.kpis(surveyId, filters)
.then(d => setData(d as KpiData | SuppressedPayload))
.catch(() => setError(true))
}, [surveyId, JSON.stringify(filters)])
if (error) return <p className="db-error">Error al cargar KPIs</p>
const loading = data === null
const suppressed = !loading && isSuppressed(data)
const ok = !loading && !suppressed
return (
<div className="db-kpi-row">
{KPI_DEFS.map((def) => (
<KpiCard
key={def.title}
title={def.title}
subtitle={def.subtitle}
value={ok ? def.getValue(data as KpiData) : '—'}
valueNote={ok ? def.getN(data as KpiData) : ''}
suppressed={suppressed}
loading={loading}
/>
))}
</div>
)
}