Con marca y dashboards
This commit is contained in:
81
components/dashboard/donut-cuidados.tsx
Normal file
81
components/dashboard/donut-cuidados.tsx
Normal file
@@ -0,0 +1,81 @@
|
||||
'use client'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { isSuppressed, type DistribucionData } from '@/lib/dashboard-types'
|
||||
import { queries } from '@/lib/dashboard-queries'
|
||||
import type { DashboardFilters } from '@/lib/dashboard-types'
|
||||
import { WidgetShell } from './widget-shell'
|
||||
|
||||
const SEGMENTS = [
|
||||
{ key: 'disc_propia', label: 'Discapacidad propia', color: '#43BBC8' },
|
||||
{ key: 'familiar', label: 'Familiar con disc.', color: '#F8AD13' },
|
||||
{ key: 'adulto_mayor', label: 'Adulto mayor', color: '#EE761A' },
|
||||
{ key: 'ninguno', label: 'Sin rol de cuidado', color: '#3d506b' },
|
||||
] as const
|
||||
|
||||
export function DonutCuidados({ surveyId, filters }: { surveyId: string; filters: DashboardFilters }) {
|
||||
const [data, setData] = useState<DistribucionData | null>(null)
|
||||
const [sup, setSup] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
setData(null); setSup(false)
|
||||
queries.distribucion(surveyId, filters)
|
||||
.then(d => {
|
||||
if (isSuppressed(d)) setSup(true)
|
||||
else setData(d as DistribucionData)
|
||||
}).catch(() => {})
|
||||
}, [surveyId, JSON.stringify(filters)])
|
||||
|
||||
const status = !data && !sup ? 'loading' : sup ? 'suppressed' : 'ok'
|
||||
|
||||
// SVG donut
|
||||
const R = 60; const cx = 75; const cy = 75; const stroke = 22
|
||||
let offset = 0
|
||||
const circumference = 2 * Math.PI * R
|
||||
const arcs = data ? SEGMENTS.map(s => {
|
||||
const pct = (data[s.key as keyof DistribucionData] as number) ?? 0
|
||||
const dash = (pct / 100) * circumference
|
||||
const gap = circumference - dash
|
||||
const arc = { ...s, dash, gap, offset: circumference * (1 - offset / 100) }
|
||||
offset += pct
|
||||
return arc
|
||||
}) : []
|
||||
|
||||
return (
|
||||
<WidgetShell title="🍩 Tipo de cuidado" status={status} n={data?.n} colSpan={3}>
|
||||
{data && (
|
||||
<div className="db-donut-wrapper">
|
||||
<svg viewBox="0 0 150 150" className="db-donut-svg" aria-hidden="true">
|
||||
{arcs.map(arc => (
|
||||
<circle key={arc.key}
|
||||
cx={cx} cy={cy} r={R}
|
||||
fill="none"
|
||||
stroke={arc.color}
|
||||
strokeWidth={stroke}
|
||||
strokeDasharray={`${arc.dash} ${arc.gap}`}
|
||||
strokeDashoffset={arc.offset}
|
||||
transform="rotate(-90, 75, 75)"
|
||||
/>
|
||||
))}
|
||||
<text x={cx} y={cy-6} textAnchor="middle" fill="white" fontSize="14" fontWeight="bold">
|
||||
{data.disc_propia + data.familiar + data.adulto_mayor > 0
|
||||
? `${Math.round(data.disc_propia + data.familiar + data.adulto_mayor)}%`
|
||||
: '0%'}
|
||||
</text>
|
||||
<text x={cx} y={cy+12} textAnchor="middle" fill="#9ca3af" fontSize="8">cuidadores</text>
|
||||
</svg>
|
||||
<ul className="db-donut-legend" aria-label="Leyenda del donut">
|
||||
{SEGMENTS.map(s => (
|
||||
<li key={s.key} className="db-legend-item">
|
||||
<span className="db-legend-dot" style={{ background: s.color }} />
|
||||
<span>{s.label}</span>
|
||||
<span className="db-legend-val">
|
||||
{(data[s.key as keyof DistribucionData] as number ?? 0)}%
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
</WidgetShell>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user