analytica-frontend-lib
Version:
Repositório público dos componentes utilizados nas plataformas da Analytica Ensino
224 lines (222 loc) • 7.76 kB
JavaScript
import {
Text_default
} from "./chunk-IMCIR6TJ.mjs";
import {
cn
} from "./chunk-53ICLDGS.mjs";
// src/components/ProficiencyChart/ProficiencyChart.tsx
import { useMemo, useState } from "react";
import { jsx, jsxs } from "react/jsx-runtime";
var buildSlices = (counters, total) => {
if (total === 0) return [];
return [
{
key: "attentionPoint",
label: "Ponto de aten\xE7\xE3o",
value: counters.attentionPoint,
percentage: counters.attentionPoint / total * 100,
colorClass: "bg-error-600",
fillColor: "#dc2626"
// error-600
},
{
key: "belowAverage",
label: "Abaixo da m\xE9dia",
value: counters.belowAverage,
percentage: counters.belowAverage / total * 100,
colorClass: "bg-warning-400",
fillColor: "#fbbf24"
// warning-400
},
{
key: "aboveAverage",
label: "Acima da m\xE9dia",
value: counters.aboveAverage,
percentage: counters.aboveAverage / total * 100,
colorClass: "bg-success-400",
fillColor: "#4ade80"
// success-400
},
{
key: "highlight",
label: "Destaque da turma",
value: counters.highlight,
percentage: counters.highlight / total * 100,
colorClass: "bg-success-700",
fillColor: "#15803d"
// success-700
}
];
};
var CHART_SIZE = 180;
var PieChart = ({
slices,
hoveredSlice,
onSliceHover
}) => {
const total = slices.reduce((sum, s) => sum + s.value, 0);
if (total === 0) {
return /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center w-[180px] h-[180px] bg-background-50 rounded-full", children: /* @__PURE__ */ jsx(Text_default, { size: "sm", className: "text-text-500", children: "Sem dados" }) });
}
const cx = CHART_SIZE / 2;
const cy = CHART_SIZE / 2;
const radius = CHART_SIZE / 2 - 5;
let cumulativePercent = 0;
const paths = slices.map((slice) => {
const percent = slice.percentage;
const startPercent = cumulativePercent;
cumulativePercent += percent;
if (percent === 0) return null;
const startAngle = startPercent / 100 * 360 - 90;
const endAngle = (startPercent + percent) / 100 * 360 - 90;
const startRad = startAngle * Math.PI / 180;
const endRad = endAngle * Math.PI / 180;
const x1 = cx + radius * Math.cos(startRad);
const y1 = cy + radius * Math.sin(startRad);
const x2 = cx + radius * Math.cos(endRad);
const y2 = cy + radius * Math.sin(endRad);
const largeArc = percent > 50 ? 1 : 0;
const d = percent >= 100 ? `M ${cx - radius} ${cy} A ${radius} ${radius} 0 1 1 ${cx + radius} ${cy} A ${radius} ${radius} 0 1 1 ${cx - radius} ${cy}` : `M ${cx} ${cy} L ${x1} ${y1} A ${radius} ${radius} 0 ${largeArc} 1 ${x2} ${y2} Z`;
const midAngle = (startPercent + percent / 2) / 100 * 360 - 90;
const midRad = midAngle * Math.PI / 180;
const labelRadius = radius * 0.65;
const labelX = cx + labelRadius * Math.cos(midRad);
const labelY = cy + labelRadius * Math.sin(midRad);
const isOtherHovered = hoveredSlice && hoveredSlice !== slice.key;
return /* @__PURE__ */ jsxs("g", { children: [
/* @__PURE__ */ jsx(
"path",
{
d,
className: "cursor-pointer transition-opacity",
style: { fill: slice.fillColor, opacity: isOtherHovered ? 0.3 : 1 },
onMouseEnter: () => onSliceHover(slice.key),
onMouseLeave: () => onSliceHover(null)
}
),
percent >= 8 && /* @__PURE__ */ jsxs(
"text",
{
x: labelX,
y: labelY,
textAnchor: "middle",
dominantBaseline: "middle",
className: "fill-white text-xs font-semibold pointer-events-none",
style: {
textShadow: "0 1px 2px rgba(0,0,0,0.3)",
opacity: isOtherHovered ? 0.3 : 1
},
children: [
slice.percentage.toFixed(0),
"%"
]
}
)
] }, slice.key);
});
return /* @__PURE__ */ jsx(
"svg",
{
viewBox: `0 0 ${CHART_SIZE} ${CHART_SIZE}`,
className: "w-[180px] h-[180px]",
children: paths
}
);
};
var ProficiencyChart = ({
counters,
totalStudents,
className,
...props
}) => {
const [hoveredSlice, setHoveredSlice] = useState(null);
const total = totalStudents ?? 0;
const slices = useMemo(() => {
if (!counters) return [];
return buildSlices(counters, total);
}, [counters, total]);
if (!counters || total === 0) {
return /* @__PURE__ */ jsx(
"div",
{
className: cn(
"flex items-center justify-center h-[200px] bg-background border border-border-50 rounded-xl",
className
),
...props,
children: /* @__PURE__ */ jsx(Text_default, { size: "sm", className: "text-text-500", children: "Sem dados de profici\xEAncia dispon\xEDveis" })
}
);
}
return /* @__PURE__ */ jsxs(
"div",
{
className: cn(
"w-full bg-background border border-border-50 rounded-xl p-5",
className
),
...props,
children: [
/* @__PURE__ */ jsx(Text_default, { as: "h3", size: "md", weight: "semibold", className: "text-text-950 mb-4", children: "Profici\xEAncia por quantidade de estudante" }),
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-6", children: [
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
slices.map((slice) => /* @__PURE__ */ jsxs(
"div",
{
className: cn(
"flex items-center gap-3 cursor-pointer transition-opacity",
hoveredSlice && hoveredSlice !== slice.key && "opacity-50"
),
onMouseEnter: () => setHoveredSlice(slice.key),
onMouseLeave: () => setHoveredSlice(null),
children: [
/* @__PURE__ */ jsx(
"span",
{
className: cn(
"w-3 h-3 rounded-full shrink-0",
slice.colorClass
)
}
),
/* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
/* @__PURE__ */ jsx(Text_default, { size: "sm", weight: "medium", className: "text-text-950", children: slice.label }),
/* @__PURE__ */ jsxs(Text_default, { size: "xs", className: "text-text-500", children: [
slice.value.toLocaleString("pt-BR"),
" ",
slice.value === 1 ? "aluno" : "alunos",
" (",
slice.percentage.toFixed(1),
"%)"
] })
] })
]
},
slice.key
)),
/* @__PURE__ */ jsx("div", { className: "pt-2 border-t border-border-100", children: /* @__PURE__ */ jsxs(Text_default, { size: "sm", weight: "semibold", className: "text-text-950", children: [
"Total: ",
total.toLocaleString("pt-BR"),
" ",
total === 1 ? "aluno" : "alunos"
] }) })
] }),
/* @__PURE__ */ jsx("div", { className: "shrink-0", children: /* @__PURE__ */ jsx(
PieChart,
{
slices,
hoveredSlice,
onSliceHover: setHoveredSlice
}
) })
] })
]
}
);
};
var ProficiencyChart_default = ProficiencyChart;
export {
ProficiencyChart,
ProficiencyChart_default
};
//# sourceMappingURL=chunk-G3RX4ZC5.mjs.map