UNPKG

analytica-frontend-lib

Version:

Repositório público dos componentes utilizados nas plataformas da Analytica Ensino

496 lines (478 loc) 17.7 kB
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } var _chunkOSTHYDKMjs = require('./chunk-OSTHYDKM.js'); var _chunkYCIBW5F4js = require('./chunk-YCIBW5F4.js'); var _chunkANT66KVKjs = require('./chunk-ANT66KVK.js'); var _chunkTN3AYOMVjs = require('./chunk-TN3AYOMV.js'); // src/components/TimeChart/TimeChart.tsx var _react = require('react'); var _jsxruntime = require('react/jsx-runtime'); var TIME_CHART_CATEGORY_KEY = /* @__PURE__ */ ((TIME_CHART_CATEGORY_KEY2) => { TIME_CHART_CATEGORY_KEY2["ACTIVITIES"] = "activities"; TIME_CHART_CATEGORY_KEY2["CONTENT"] = "content"; TIME_CHART_CATEGORY_KEY2["SIMULATIONS"] = "simulations"; TIME_CHART_CATEGORY_KEY2["QUESTIONNAIRES"] = "questionnaires"; TIME_CHART_CATEGORY_KEY2["RECOMMENDED_LESSONS"] = "recommendedLessons"; return TIME_CHART_CATEGORY_KEY2; })(TIME_CHART_CATEGORY_KEY || {}); var STUDENT_CATEGORIES = [ { key: "activities" /* ACTIVITIES */, label: "Atividades", colorClass: "bg-success-700" }, { key: "simulations" /* SIMULATIONS */, label: "Simulados", colorClass: "bg-warning-300" }, { key: "questionnaires" /* QUESTIONNAIRES */, label: "Question\xE1rios", colorClass: "bg-indicator-info" }, { key: "content" /* CONTENT */, label: "Videoaulas", colorClass: "bg-success-300" }, { key: "recommendedLessons" /* RECOMMENDED_LESSONS */, label: "Aulas recomendadas", colorClass: "bg-indicator-positive" } ]; var DEFAULT_CATEGORIES = [ { key: "activities" /* ACTIVITIES */, label: "Atividades", colorClass: "bg-success-700" }, { key: "recommendedLessons" /* RECOMMENDED_LESSONS */, label: "Aulas recomendadas", colorClass: "bg-indicator-positive" } ]; var calculateHourTicks = (maxHours) => { if (maxHours <= 0) return [0]; const niceMax = Math.ceil(maxHours / 4) * 4; const step = niceMax / 4; return [niceMax, step * 3, step * 2, step, 0]; }; var getDayValue = (day, key) => Number(day[key]) || 0; var LegendItem = ({ color, label }) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-row items-center gap-2", children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: _chunkTN3AYOMVjs.cn.call(void 0, "w-2 h-2 rounded-full", color) }), /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkANT66KVKjs.Text_default, { size: "sm", weight: "medium", className: "text-text-600", children: label }) ] }); var ChartCard = ({ title, categories, children, className, contentGapClassName = "gap-4", ...props }) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunkTN3AYOMVjs.cn.call(void 0, "flex flex-col p-5 bg-background border border-border-50 rounded-xl", contentGapClassName, className ), ...props, children: [ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-4", children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkANT66KVKjs.Text_default, { as: "h3", size: "lg", weight: "bold", className: "text-text-950 tracking-[0.2px]", children: title } ), /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex flex-row flex-wrap justify-between gap-x-6 gap-y-2", children: categories.map((cat) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, LegendItem, { color: cat.colorClass, label: cat.label }, cat.key)) }) ] }), children ] } ); var YAxis = ({ ticks, chartHeight, unitSuffix }) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex flex-col justify-between items-end pr-3", style: { height: chartHeight }, "aria-hidden": "true", children: ticks.map((tick, index) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkANT66KVKjs.Text_default, { size: "md", weight: "normal", className: "text-text-700", children: tick === 0 ? "0" : `${tick}${unitSuffix}` }, `${tick}-${index}` )) } ); var GridLines = ({ ticks, chartHeight }) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "absolute inset-0 flex flex-col justify-between pointer-events-none", style: { height: chartHeight }, children: ticks.map((tick, index) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "w-full border-t border-dashed border-border-200" }, `grid-${tick}-${index}` )) } ); var StackedBar = ({ day, categories, maxValue, chartHeight, unitSuffix }) => { const nonZeroCategories = categories.filter( (cat) => getDayValue(day, cat.key) > 0 ); const tooltipContent = nonZeroCategories.length > 0 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex flex-col gap-1", children: nonZeroCategories.map((cat) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-2", children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "w-2 h-2 rounded-full shrink-0", style: { background: _chunkYCIBW5F4js.bgClassToCssVar.call(void 0, cat.colorClass) } } ), /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkANT66KVKjs.Text_default, { as: "span", size: "xs", weight: "medium", color: "text-white", children: [ cat.label, ": ", getDayValue(day, cat.key), unitSuffix ] }) ] }, cat.key)) }) : null; return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkOSTHYDKMjs.Tooltip, { content: _nullishCoalesce(tooltipContent, () => ( "")), disabled: !tooltipContent, position: "top", className: "flex-1", contentClassName: "whitespace-normal", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col items-center gap-2 w-full cursor-pointer group/bar", children: [ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "w-full flex flex-col-reverse items-center justify-start relative", style: { height: chartHeight }, children: [ categories.map((cat) => { const value = getDayValue(day, cat.key); const segmentHeight = maxValue === 0 ? 0 : value / maxValue * chartHeight; if (segmentHeight === 0) return null; const isFirst = cat === nonZeroCategories[0]; const isLast = cat === nonZeroCategories[nonZeroCategories.length - 1]; return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { "data-testid": `bar-segment-${day.label}-${cat.key}`, className: _chunkTN3AYOMVjs.cn.call(void 0, "w-9", cat.colorClass, isFirst && "rounded-b", isLast && "rounded-t", isFirst && isLast && "rounded" ), style: { height: `${segmentHeight}px` }, "aria-label": `${cat.label}: ${value}${unitSuffix}` }, cat.key ); }), nonZeroCategories.length > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "absolute inset-0 bg-white/50 opacity-0 group-hover/bar:opacity-100 transition-opacity duration-200 rounded-md pointer-events-none z-20" }) ] } ), /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkANT66KVKjs.Text_default, { size: "md", weight: "normal", className: "text-text-700 text-center", "data-testid": `day-label-${day.label}`, children: day.label } ) ] }) } ); }; var PieChart = ({ categories, totals, size }) => { const [hoveredSlice, setHoveredSlice] = _react.useState.call(void 0, null); const grandTotal = categories.reduce( // istanbul ignore next -- defensive: parent always provides all keys (sum, cat) => sum + (_nullishCoalesce(totals[cat.key], () => ( 0))), 0 ); if (grandTotal === 0) { const radius2 = size * 0.4; const center2 = size / 2; return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { width: size, height: size, viewBox: `0 0 ${size} ${size}`, "aria-hidden": "true", "data-testid": "pie-chart", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "circle", { cx: center2, cy: center2, r: radius2, className: "fill-background-300" } ) } ); } const radius = size * 0.4; const center = size / 2; let cumulativeAngle = 0; const slices = categories.map((cat) => { const value = _nullishCoalesce(totals[cat.key], () => ( 0)); const percentage = value / grandTotal * 100; const angle = percentage / 100 * 360; const startAngle = cumulativeAngle; const endAngle = cumulativeAngle + angle; const midAngle = startAngle + angle / 2; cumulativeAngle = endAngle; return { cat, percentage, startAngle, endAngle, midAngle }; }).filter((s) => s.percentage > 0); const hoveredData = hoveredSlice ? slices.find((s) => s.cat.key === hoveredSlice) : null; const tooltipPos = hoveredData ? _chunkYCIBW5F4js.polarToCartesian.call(void 0, center, center, radius * 0.6, hoveredData.midAngle) : { x: 0, y: 0 }; return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "relative inline-block", children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { width: size, height: size, viewBox: `0 0 ${size} ${size}`, "aria-hidden": "true", "data-testid": "pie-chart", onMouseLeave: () => setHoveredSlice(null), children: slices.map((slice) => { const path = slice.percentage >= 99.99 ? void 0 : _chunkYCIBW5F4js.describeArc.call(void 0, center, center, radius, slice.startAngle, slice.endAngle ); const labelPos = _chunkYCIBW5F4js.polarToCartesian.call(void 0, center, center, radius * 0.6, slice.midAngle ); return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "g", { "data-testid": `pie-slice-${slice.cat.key}`, onMouseEnter: () => setHoveredSlice(slice.cat.key), className: "cursor-pointer", children: [ slice.percentage >= 99.99 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "circle", { cx: center, cy: center, r: radius, style: { fill: _chunkYCIBW5F4js.bgClassToCssVar.call(void 0, slice.cat.colorClass) } } ) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: path, style: { fill: _chunkYCIBW5F4js.bgClassToCssVar.call(void 0, slice.cat.colorClass) } } ), hoveredSlice === slice.cat.key && (slice.percentage >= 99.99 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "circle", { cx: center, cy: center, r: radius, fill: "white", opacity: 0.5, style: { pointerEvents: "none" } } ) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: path, fill: "white", opacity: 0.5, style: { pointerEvents: "none" } } )), slice.percentage >= 5 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "text", { x: labelPos.x, y: labelPos.y, textAnchor: "middle", dominantBaseline: "central", className: "fill-white text-xs font-bold", style: { fontSize: "12px", pointerEvents: "none" }, children: `${Math.round(slice.percentage)}%` } ) ] }, slice.cat.key ); }) } ), hoveredData && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "absolute bg-background-900 text-white px-4 py-2 rounded-lg shadow-[0px_3px_10px_0px_rgba(38,38,38,0.2)] pointer-events-none z-10", style: { left: tooltipPos.x, top: tooltipPos.y, transform: "translate(-50%, calc(-100% - 8px))" }, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-2", children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "w-2 h-2 rounded-full shrink-0", style: { background: _chunkYCIBW5F4js.bgClassToCssVar.call(void 0, hoveredData.cat.colorClass) } } ), /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkANT66KVKjs.Text_default, { as: "span", size: "xs", weight: "bold", color: "text-white", className: "whitespace-nowrap", children: [ hoveredData.cat.label, ": ", Math.round(hoveredData.percentage), "%" ] } ) ] }) } ) ] }); }; var TimeChart = ({ data, barChartTitle = "Dados de horas por semana", pieChartTitle = "Dados de horas por item", chartHeight = 180, pieSize = 200, unitSuffix = "h", className, ...props }) => { const { categories, hoursByPeriod, hoursByItem } = data; const periodTotals = hoursByPeriod.map( (day) => categories.reduce((sum, cat) => sum + getDayValue(day, cat.key), 0) ); const maxPeriodTotal = Math.max(...periodTotals, 0); const yAxisTicks = calculateHourTicks(maxPeriodTotal); const adjustedMax = yAxisTicks[0]; const categoryTotals = {}; if (hoursByItem) { for (const cat of categories) { categoryTotals[cat.key] = _nullishCoalesce(hoursByItem[cat.key], () => ( 0)); } } else { for (const cat of categories) { categoryTotals[cat.key] = hoursByPeriod.reduce( (sum, day) => sum + getDayValue(day, cat.key), 0 ); } } return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunkTN3AYOMVjs.cn.call(void 0, "grid grid-cols-1 lg:grid-cols-2 gap-4", className), "aria-label": "Gr\xE1ficos de dados de horas por semana e por categoria", ...props, children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ChartCard, { title: barChartTitle, categories, contentGapClassName: "gap-8", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-row", children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, YAxis, { ticks: yAxisTicks, chartHeight, unitSuffix } ), /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "w-4" }), /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex-1 relative", children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, GridLines, { ticks: yAxisTicks, chartHeight }), /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex flex-row flex-1 gap-2 relative z-10", children: hoursByPeriod.map((day, index) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StackedBar, { day, categories, maxValue: adjustedMax, chartHeight, unitSuffix }, `${day.label}-${index}` )) }) ] }) ] }) } ), /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ChartCard, { title: pieChartTitle, categories, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex items-center justify-center py-4", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, PieChart, { categories, totals: categoryTotals, size: pieSize } ) }) }) ] } ); }; var TimeChart_default = TimeChart; exports.TIME_CHART_CATEGORY_KEY = TIME_CHART_CATEGORY_KEY; exports.STUDENT_CATEGORIES = STUDENT_CATEGORIES; exports.DEFAULT_CATEGORIES = DEFAULT_CATEGORIES; exports.calculateHourTicks = calculateHourTicks; exports.TimeChart = TimeChart; exports.TimeChart_default = TimeChart_default; //# sourceMappingURL=chunk-IALYXAFQ.js.map