Con marca y dashboards
This commit is contained in:
61
components/dashboard/gauge-organizacional.tsx
Normal file
61
components/dashboard/gauge-organizacional.tsx
Normal file
@@ -0,0 +1,61 @@
|
||||
'use client'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { isSuppressed, type ScoreData } from '@/lib/dashboard-types'
|
||||
import { queries } from '@/lib/dashboard-queries'
|
||||
import type { DashboardFilters } from '@/lib/dashboard-types'
|
||||
import { WidgetShell } from './widget-shell'
|
||||
|
||||
const ZONA_COLOR = { baja: '#ef4444', desarrollo: '#F8AD13', consciente: '#43BBC8' }
|
||||
const ZONA_LABEL = { baja: 'Baja madurez', desarrollo: 'En desarrollo', consciente: 'Consciente' }
|
||||
|
||||
export function GaugeOrganizacional({ surveyId, filters }: { surveyId: string; filters: DashboardFilters }) {
|
||||
const [data, setData] = useState<ScoreData | null>(null)
|
||||
const [sup, setSup] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
setData(null); setSup(false)
|
||||
queries.score(surveyId, filters)
|
||||
.then(d => { if (isSuppressed(d)) setSup(true); else setData(d as ScoreData) })
|
||||
.catch(() => {})
|
||||
}, [surveyId, JSON.stringify(filters)])
|
||||
|
||||
const status = !data && !sup ? 'loading' : sup ? 'suppressed' : 'ok'
|
||||
|
||||
// SVG semicircle gauge
|
||||
const score = data?.score ?? 0
|
||||
const angle = (score / 100) * 180 // 0° = left, 180° = right
|
||||
const rad = (angle - 90) * Math.PI / 180
|
||||
const r = 60; const cx = 75; const cy = 80
|
||||
const needleX = cx + r * Math.cos(rad)
|
||||
const needleY = cy + r * Math.sin(rad)
|
||||
const color = data ? ZONA_COLOR[data.zona] : '#43BBC8'
|
||||
|
||||
return (
|
||||
<WidgetShell title="🎯 Madurez organizacional" status={status} n={data?.n} colSpan={3}>
|
||||
{data && (
|
||||
<div className="db-gauge-wrapper">
|
||||
<svg viewBox="0 0 150 100" className="db-gauge-svg" aria-label={`Score: ${score}/100`}>
|
||||
{/* Fondo semicírculo */}
|
||||
<path d="M 15 80 A 60 60 0 0 1 135 80" fill="none" stroke="#2a3547" strokeWidth="18" strokeLinecap="round" />
|
||||
{/* Arco coloreado proporcional al score */}
|
||||
<path d="M 15 80 A 60 60 0 0 1 135 80" fill="none"
|
||||
stroke={color} strokeWidth="18" strokeLinecap="round"
|
||||
strokeDasharray={`${(score/100)*188.5} 188.5`} />
|
||||
{/* Aguja */}
|
||||
<line x1={cx} y1={cy} x2={needleX} y2={needleY} stroke="white" strokeWidth="2" strokeLinecap="round" />
|
||||
<circle cx={cx} cy={cy} r={4} fill="white" />
|
||||
{/* Score */}
|
||||
<text x={cx} y={cy-10} textAnchor="middle" fill="white" fontSize="18" fontWeight="bold">{score}</text>
|
||||
<text x={cx} y={cy+6} textAnchor="middle" fill="#9ca3af" fontSize="7">/ 100</text>
|
||||
</svg>
|
||||
<p className="db-gauge-zona" style={{ color }}>
|
||||
{ZONA_LABEL[data.zona]}
|
||||
</p>
|
||||
<p className="db-gauge-hint">
|
||||
0–33 baja · 34–66 desarrollo · 67–100 consciente
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</WidgetShell>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user