analytica-frontend-lib
Version:
Repositório público dos componentes utilizados nas plataformas da Analytica Ensino
1,372 lines (1,361 loc) • 62 kB
JavaScript
import {
DEFAULT_ACTIVITY_PERFORMANCE_LABELS,
DEFAULT_LABELS,
DEFAULT_PERFORMANCE_LABELS
} from "./chunk-UAT7LJVY.mjs";
import {
deriveStudentStatus,
formatDaysToComplete,
getStudentStatusBadgeAction
} from "./chunk-FD4UD2X5.mjs";
import {
VideoPlayer_default
} from "./chunk-5XJWMPI4.mjs";
import {
Whiteboard_default
} from "./chunk-6TUOCZ7Y.mjs";
import {
StatCard
} from "./chunk-3ZYHNRVG.mjs";
import {
AccordionGroup
} from "./chunk-ILCBSWZF.mjs";
import {
ToastStore_default
} from "./chunk-OAP6DJKU.mjs";
import {
CardAccordation
} from "./chunk-2ACDTDO4.mjs";
import {
AlternativesList
} from "./chunk-TUJ3CWS2.mjs";
import {
HtmlMathRenderer_default
} from "./chunk-FN4G43WK.mjs";
import {
CardAudio,
CardBase
} from "./chunk-R7FP73MH.mjs";
import {
TextArea_default
} from "./chunk-LI2FS7M2.mjs";
import {
TruncatedText
} from "./chunk-2P7LJCTW.mjs";
import {
Radio_default
} from "./chunk-NLK3GG73.mjs";
import {
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
Table_default,
useTableSort
} from "./chunk-66F2QDAX.mjs";
import {
Skeleton,
SkeletonRounded,
SkeletonTable,
SkeletonText
} from "./chunk-NKVUUWCA.mjs";
import {
ProgressCircle_default
} from "./chunk-5ZVOSDX4.mjs";
import {
ProgressBar_default
} from "./chunk-LDBWF6EA.mjs";
import {
getSubjectInfo
} from "./chunk-3ERLYM6Y.mjs";
import {
Alert_default
} from "./chunk-YQTOSHD5.mjs";
import {
Badge_default
} from "./chunk-OEW3ST4F.mjs";
import {
useTheme
} from "./chunk-HYVBZ5EV.mjs";
import {
Modal_default
} from "./chunk-TNLGS7SB.mjs";
import {
Button_default
} from "./chunk-LAYB7IKW.mjs";
import {
Text_default
} from "./chunk-IMCIR6TJ.mjs";
import {
cn,
getSubjectColorWithOpacity
} from "./chunk-53ICLDGS.mjs";
import {
getStatusBadgeAction
} from "./chunk-DG76FRXG.mjs";
// src/components/RecommendedLessonDetails/RecommendedLessonDetails.tsx
import { useMemo as useMemo3, useState as useState3, useCallback as useCallback3 } from "react";
// src/components/RecommendedLessonDetails/components/Breadcrumb.tsx
import { CaretRightIcon } from "@phosphor-icons/react";
import { jsx, jsxs } from "react/jsx-runtime";
var Breadcrumb = ({ items, onItemClick }) => /* @__PURE__ */ jsx("nav", { className: "flex items-center gap-2 text-sm", "aria-label": "Breadcrumb", children: items.map((item, index) => /* @__PURE__ */ jsxs(
Text_default,
{
as: "span",
className: "flex items-center gap-2",
children: [
index > 0 && /* @__PURE__ */ jsx(CaretRightIcon, { size: 14, className: "text-text-500" }),
item.path ? /* @__PURE__ */ jsx(
"button",
{
type: "button",
onClick: () => onItemClick?.(item.path),
className: "text-text-600 hover:text-primary-700 transition-colors",
children: item.label
}
) : /* @__PURE__ */ jsx(Text_default, { as: "span", className: "text-text-950 font-medium", children: item.label })
]
},
item.path ?? item.label
)) });
// src/components/RecommendedLessonDetails/components/LessonHeader.tsx
import { BookBookmarkIcon } from "@phosphor-icons/react";
// src/components/RecommendedLessonDetails/utils/lessonDetailsUtils.ts
var formatDate = (dateString) => {
if (!dateString) return "-";
const date = new Date(dateString);
if (Number.isNaN(date.getTime())) return "-";
return date.toLocaleDateString("pt-BR", {
day: "2-digit",
month: "2-digit",
year: "numeric"
});
};
var transformStudentForDisplay = (student, deadline) => ({
id: student.userInstitutionId,
name: student.name,
status: deriveStudentStatus(student.progress, student.completedAt, deadline),
completionPercentage: student.progress,
duration: formatDaysToComplete(student.daysToComplete)
});
// src/components/RecommendedLessonDetails/components/LessonHeader.tsx
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
var LessonHeader = ({
data,
onViewLesson,
mapSubjectNameToEnum,
viewLessonLabel
}) => {
const { recommendedClass, breakdown } = data;
const subjectName = recommendedClass.lessons[0]?.supLessonsProgress?.lesson?.subject?.name || "";
const subjectEnum = mapSubjectNameToEnum?.(subjectName);
const subjectInfo = subjectEnum ? getSubjectInfo(subjectEnum) : null;
return /* @__PURE__ */ jsx2("div", { className: "bg-background rounded-xl border border-border-50 p-6", children: /* @__PURE__ */ jsxs2("div", { className: "flex flex-col lg:flex-row lg:items-start lg:justify-between gap-4", children: [
/* @__PURE__ */ jsxs2("div", { className: "flex flex-col gap-2", children: [
/* @__PURE__ */ jsx2(
Text_default,
{
as: "h1",
size: "xl",
weight: "bold",
className: "text-text-950 lg:text-2xl",
children: recommendedClass.title
}
),
/* @__PURE__ */ jsxs2("div", { className: "flex flex-wrap items-center gap-2 text-sm text-text-600", children: [
/* @__PURE__ */ jsxs2(Text_default, { as: "span", size: "sm", className: "text-text-600", children: [
"In\xEDcio em ",
formatDate(recommendedClass.startDate)
] }),
/* @__PURE__ */ jsx2(Text_default, { as: "span", size: "sm", className: "text-text-400", children: "\u2022" }),
/* @__PURE__ */ jsxs2(Text_default, { as: "span", size: "sm", className: "text-text-600", children: [
"Prazo final ",
formatDate(recommendedClass.finalDate)
] }),
breakdown?.schoolName && /* @__PURE__ */ jsxs2(Fragment, { children: [
/* @__PURE__ */ jsx2(Text_default, { as: "span", size: "sm", className: "text-text-400", children: "\u2022" }),
/* @__PURE__ */ jsx2(Text_default, { as: "span", size: "sm", className: "text-text-600", children: breakdown.schoolName })
] }),
subjectName && /* @__PURE__ */ jsxs2(Fragment, { children: [
/* @__PURE__ */ jsx2(Text_default, { as: "span", size: "sm", className: "text-text-400", children: "\u2022" }),
/* @__PURE__ */ jsxs2(Text_default, { as: "span", size: "sm", className: "flex items-center gap-1", children: [
subjectInfo && /* @__PURE__ */ jsx2(
Text_default,
{
as: "span",
className: cn(
"size-5 rounded flex items-center justify-center text-white",
subjectInfo.colorClass
),
children: subjectInfo.icon
}
),
subjectName
] })
] }),
breakdown?.className && /* @__PURE__ */ jsxs2(Fragment, { children: [
/* @__PURE__ */ jsx2(Text_default, { as: "span", size: "sm", className: "text-text-400", children: "\u2022" }),
/* @__PURE__ */ jsx2(Text_default, { as: "span", size: "sm", className: "text-text-600", children: breakdown.className })
] })
] })
] }),
onViewLesson && /* @__PURE__ */ jsx2(
Button_default,
{
variant: "solid",
action: "primary",
size: "small",
iconLeft: /* @__PURE__ */ jsx2(BookBookmarkIcon, { size: 16 }),
onClick: onViewLesson,
children: viewLessonLabel
}
)
] }) });
};
// src/components/RecommendedLessonDetails/components/LoadingSkeleton.tsx
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
var LoadingSkeleton = () => /* @__PURE__ */ jsxs3("div", { className: "flex flex-col gap-6", children: [
/* @__PURE__ */ jsx3(SkeletonText, { width: 256 }),
/* @__PURE__ */ jsx3("div", { className: "bg-background rounded-xl border border-border-50 p-6", children: /* @__PURE__ */ jsxs3("div", { className: "flex flex-col gap-3", children: [
/* @__PURE__ */ jsx3(SkeletonText, { width: "75%", height: 28 }),
/* @__PURE__ */ jsx3(SkeletonText, { width: "50%" })
] }) }),
/* @__PURE__ */ jsxs3("div", { className: "flex flex-col gap-4", children: [
/* @__PURE__ */ jsx3(SkeletonText, { width: 192, height: 20 }),
/* @__PURE__ */ jsxs3("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-4", children: [
/* @__PURE__ */ jsx3(SkeletonRounded, { height: 140 }),
/* @__PURE__ */ jsx3(SkeletonRounded, { height: 140 }),
/* @__PURE__ */ jsx3(SkeletonRounded, { height: 140 })
] })
] }),
/* @__PURE__ */ jsx3("div", { className: "bg-background rounded-xl border border-border-50 p-4", children: /* @__PURE__ */ jsx3(SkeletonTable, { rows: 4, columns: 5 }) })
] });
// src/components/RecommendedLessonDetails/components/ResultsSection.tsx
import { TrophyIcon, WarningIcon } from "@phosphor-icons/react";
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
var ResultsSection = ({ data, labels }) => {
const { details } = data;
const { aggregated, contentPerformance } = details;
return /* @__PURE__ */ jsxs4("div", { className: "flex flex-col gap-4", children: [
/* @__PURE__ */ jsx4(Text_default, { as: "h2", size: "md", weight: "semibold", className: "text-text-950", children: labels.resultsTitle }),
/* @__PURE__ */ jsx4("div", { className: "bg-background rounded-xl border border-border-50 p-4", children: /* @__PURE__ */ jsxs4("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-4", children: [
/* @__PURE__ */ jsx4("div", { className: "flex flex-col items-center justify-center rounded-xl p-4 min-h-28 bg-primary-50", children: /* @__PURE__ */ jsx4(
ProgressCircle_default,
{
value: aggregated.completionPercentage,
size: "small",
variant: "blue",
label: labels.completedLabel,
showPercentage: true
}
) }),
/* @__PURE__ */ jsxs4("div", { className: "flex flex-col items-center justify-center rounded-xl p-4 min-h-28 bg-success-200", children: [
/* @__PURE__ */ jsx4(
Text_default,
{
as: "span",
className: "size-8 rounded-full flex items-center justify-center bg-warning-300 mb-2",
children: /* @__PURE__ */ jsx4(TrophyIcon, { size: 18, weight: "fill", className: "text-white" })
}
),
/* @__PURE__ */ jsx4(
Text_default,
{
size: "2xs",
weight: "bold",
className: "text-text-700 uppercase text-center leading-none mb-1",
children: labels.bestResultLabel
}
),
/* @__PURE__ */ jsx4(
Text_default,
{
size: "xl",
weight: "bold",
className: "text-success-700 text-center leading-none tracking-wide",
children: contentPerformance.best?.contentName || "-"
}
)
] }),
/* @__PURE__ */ jsxs4("div", { className: "flex flex-col items-center justify-center rounded-xl p-4 min-h-28 bg-error-100", children: [
/* @__PURE__ */ jsx4(
Text_default,
{
as: "span",
className: "size-8 rounded-full flex items-center justify-center bg-error-300 mb-2",
children: /* @__PURE__ */ jsx4(WarningIcon, { size: 18, weight: "fill", className: "text-error-700" })
}
),
/* @__PURE__ */ jsx4(
Text_default,
{
size: "2xs",
weight: "bold",
className: "text-text-700 uppercase text-center leading-none mb-1",
children: labels.hardestTopicLabel
}
),
/* @__PURE__ */ jsx4(
Text_default,
{
size: "xl",
weight: "bold",
className: "text-error-700 text-center leading-none tracking-wide",
children: contentPerformance.worst?.contentName || "-"
}
)
] })
] }) })
] });
};
// src/components/RecommendedLessonDetails/components/StudentsTable.tsx
import { UserIcon } from "@phosphor-icons/react";
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
var StudentsTable = ({
students,
onCorrectActivity,
labels,
emptyMessage = "Nenhum aluno encontrado"
}) => {
const { sortedData, sortColumn, sortDirection, handleSort } = useTableSort(students);
return /* @__PURE__ */ jsx5("div", { className: "bg-background rounded-xl border border-border-50 overflow-hidden", children: /* @__PURE__ */ jsxs5(Table_default, { children: [
/* @__PURE__ */ jsx5(TableHeader, { children: /* @__PURE__ */ jsxs5(TableRow, { children: [
/* @__PURE__ */ jsx5(
TableHead,
{
sortable: true,
sortDirection: sortColumn === "name" ? sortDirection : void 0,
onSort: () => handleSort("name"),
children: labels.studentColumn
}
),
/* @__PURE__ */ jsx5(
TableHead,
{
sortable: true,
sortDirection: sortColumn === "status" ? sortDirection : void 0,
onSort: () => handleSort("status"),
children: labels.statusColumn
}
),
/* @__PURE__ */ jsx5(
TableHead,
{
sortable: true,
sortDirection: sortColumn === "completionPercentage" ? sortDirection : void 0,
onSort: () => handleSort("completionPercentage"),
children: labels.completionColumn
}
),
/* @__PURE__ */ jsx5(TableHead, { children: labels.durationColumn }),
/* @__PURE__ */ jsx5(TableHead, { className: "w-[160px]" })
] }) }),
/* @__PURE__ */ jsx5(TableBody, { children: sortedData.length === 0 ? /* @__PURE__ */ jsx5(TableRow, { children: /* @__PURE__ */ jsx5(TableCell, { colSpan: 5, className: "text-center py-8", children: /* @__PURE__ */ jsx5(Text_default, { size: "sm", className: "text-text-500", children: emptyMessage }) }) }) : sortedData.map((student) => /* @__PURE__ */ jsxs5(TableRow, { children: [
/* @__PURE__ */ jsx5(TableCell, { className: "max-w-[220px]", children: /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2 min-w-0", children: [
/* @__PURE__ */ jsx5(
Text_default,
{
as: "span",
className: "size-8 rounded-full bg-background-100 flex items-center justify-center shrink-0",
children: /* @__PURE__ */ jsx5(UserIcon, { size: 16, className: "text-text-500" })
}
),
/* @__PURE__ */ jsx5(TruncatedText, { size: "sm", color: "text-text-950", children: student.name })
] }) }),
/* @__PURE__ */ jsx5(TableCell, { children: /* @__PURE__ */ jsx5(
Badge_default,
{
variant: "solid",
action: getStudentStatusBadgeAction(student.status),
size: "small",
children: student.status
}
) }),
/* @__PURE__ */ jsx5(TableCell, { children: /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-1 min-w-[120px]", children: [
/* @__PURE__ */ jsxs5(Text_default, { size: "sm", className: "text-primary-700 font-medium", children: [
student.completionPercentage,
"%"
] }),
/* @__PURE__ */ jsx5(
ProgressBar_default,
{
value: student.completionPercentage,
size: "small",
variant: "blue",
className: "w-full max-w-[100px]"
}
)
] }) }),
/* @__PURE__ */ jsx5(TableCell, { children: /* @__PURE__ */ jsx5(Text_default, { size: "sm", className: "text-text-700", children: student.duration ?? "-" }) }),
/* @__PURE__ */ jsx5(TableCell, { children: onCorrectActivity && /* @__PURE__ */ jsx5(
Button_default,
{
variant: "outline",
size: "extra-small",
onClick: () => onCorrectActivity(student.id),
children: labels.correctActivity
}
) })
] }, student.id)) })
] }) });
};
// src/components/RecommendedLessonDetails/components/StudentPerformanceModal.tsx
import { useMemo } from "react";
import { LightbulbFilamentIcon } from "@phosphor-icons/react/dist/csr/LightbulbFilament";
import { WarningCircleIcon } from "@phosphor-icons/react/dist/csr/WarningCircle";
import { UserIcon as UserIcon2 } from "@phosphor-icons/react/dist/csr/User";
import { CheckCircleIcon } from "@phosphor-icons/react/dist/csr/CheckCircle";
import { XCircleIcon } from "@phosphor-icons/react/dist/csr/XCircle";
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
var PerformanceCard = ({
icon,
label,
value,
secondaryLabel,
secondaryValue,
variant
}) => {
const headerBgColor = {
success: "bg-success-200",
error: "bg-error-100"
}[variant];
const valueColor = {
success: "text-success-700",
error: "text-error-700"
}[variant];
const iconBgColor = {
success: "bg-warning-300",
error: "bg-error-300"
}[variant];
const secondaryLabelColor = {
success: "text-success-600",
error: "text-error-600"
}[variant];
return /* @__PURE__ */ jsxs6("div", { className: "flex flex-col rounded-xl border border-border-50 bg-background overflow-hidden", children: [
/* @__PURE__ */ jsxs6(
"div",
{
className: `flex flex-col items-center justify-center p-4 gap-1 ${headerBgColor}`,
children: [
/* @__PURE__ */ jsx6(
Text_default,
{
as: "span",
className: `size-8 rounded-full flex items-center justify-center ${iconBgColor}`,
children: icon
}
),
/* @__PURE__ */ jsx6(
Text_default,
{
size: "2xs",
weight: "medium",
className: "text-text-800 uppercase text-center leading-none",
children: label
}
),
/* @__PURE__ */ jsx6(Text_default, { size: "xl", weight: "bold", className: `${valueColor} text-center`, children: value })
]
}
),
/* @__PURE__ */ jsxs6("div", { className: "flex flex-col items-center gap-2 px-4 py-3", children: [
/* @__PURE__ */ jsx6(
Text_default,
{
size: "2xs",
weight: "medium",
className: `${secondaryLabelColor} uppercase text-center`,
children: secondaryLabel
}
),
/* @__PURE__ */ jsx6(Badge_default, { size: "large", action: "info", children: secondaryValue || "-" })
] })
] });
};
var getAlternativeStatus = (isCorrect, isSelected) => {
if (isCorrect) {
return "correct" /* CORRECT */;
}
if (isSelected) {
return "incorrect" /* INCORRECT */;
}
return void 0;
};
var mapAlternatives = (question) => {
return question.alternatives.map((alt) => ({
value: alt.id,
label: alt.text,
status: getAlternativeStatus(alt.isCorrect, alt.isSelected)
}));
};
var getSelectedValue = (question) => {
const selected = question.alternatives.find((alt) => alt.isSelected);
return selected?.id;
};
var QuestionAccordionItem = ({
question,
index
}) => /* @__PURE__ */ jsx6(
CardAccordation,
{
value: question.id,
className: "bg-background rounded-xl border border-border-50",
triggerClassName: "py-5 px-5",
contentClassName: "px-5 pb-5",
trigger: /* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-between flex-1", children: [
/* @__PURE__ */ jsxs6(Text_default, { size: "sm", weight: "semibold", className: "text-text-950", children: [
"Quest\xE3o ",
index + 1
] }),
/* @__PURE__ */ jsx6(
Badge_default,
{
size: "small",
action: question.isCorrect ? "success" : "error",
variant: "solid",
iconLeft: question.isCorrect ? /* @__PURE__ */ jsx6(CheckCircleIcon, {}) : /* @__PURE__ */ jsx6(XCircleIcon, {}),
children: question.isCorrect ? "Correta" : "Incorreta"
}
)
] }),
children: /* @__PURE__ */ jsxs6("div", { className: "flex flex-col gap-3", children: [
/* @__PURE__ */ jsx6(
HtmlMathRenderer_default,
{
content: question.statement,
className: "text-sm text-text-700"
}
),
/* @__PURE__ */ jsx6(
CardAccordation,
{
value: `${question.id}-alternatives`,
className: "bg-background rounded-lg border border-border-50",
triggerClassName: "py-5 px-5",
contentClassName: "px-5 py-5",
trigger: /* @__PURE__ */ jsx6(Text_default, { size: "sm", weight: "medium", className: "text-text-800", children: "Alternativas" }),
children: /* @__PURE__ */ jsx6(
AlternativesList,
{
mode: "readonly",
alternatives: mapAlternatives(question),
selectedValue: getSelectedValue(question),
layout: "default"
}
)
}
)
] })
}
);
var LessonAccordionItem = ({ lesson }) => /* @__PURE__ */ jsx6(
CardAccordation,
{
value: lesson.id,
className: "bg-background rounded-xl border border-border-50",
triggerClassName: "py-5 px-5",
contentClassName: "px-5 pb-5",
trigger: /* @__PURE__ */ jsxs6("div", { className: "flex flex-col gap-1 flex-1", children: [
/* @__PURE__ */ jsx6(Text_default, { size: "sm", weight: "semibold", className: "text-text-950", children: lesson.title }),
/* @__PURE__ */ jsx6(
ProgressBar_default,
{
value: lesson.progress,
variant: "blue",
size: "medium",
showPercentage: true,
layout: "default"
}
)
] }),
children: /* @__PURE__ */ jsx6("div", { className: "flex flex-col gap-2", children: lesson.questions.map((question, index) => /* @__PURE__ */ jsx6(
QuestionAccordionItem,
{
question,
index
},
question.id
)) })
}
);
var LoadingSkeleton2 = () => /* @__PURE__ */ jsxs6("div", { className: "flex flex-col gap-4 animate-pulse", children: [
/* @__PURE__ */ jsx6("div", { className: "h-6 bg-background-200 rounded w-48" }),
/* @__PURE__ */ jsxs6("div", { className: "grid grid-cols-2 gap-3", children: [
/* @__PURE__ */ jsx6("div", { className: "h-44 bg-background-200 rounded-xl" }),
/* @__PURE__ */ jsx6("div", { className: "h-44 bg-background-200 rounded-xl" })
] })
] });
var ErrorContent = ({ message }) => /* @__PURE__ */ jsxs6("div", { className: "flex flex-col items-center justify-center py-8 gap-3", children: [
/* @__PURE__ */ jsx6(
Text_default,
{
as: "span",
className: "size-12 rounded-full bg-error-100 flex items-center justify-center",
children: /* @__PURE__ */ jsx6(WarningCircleIcon, { size: 24, className: "text-error-700" })
}
),
/* @__PURE__ */ jsx6(Text_default, { size: "md", className: "text-error-700 text-center", children: message })
] });
var PerformanceContent = ({
data,
labels
}) => /* @__PURE__ */ jsxs6("div", { className: "flex flex-col gap-5", children: [
/* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2", children: [
/* @__PURE__ */ jsx6(
Text_default,
{
as: "span",
className: "size-8 rounded-full bg-background-100 flex items-center justify-center",
children: /* @__PURE__ */ jsx6(UserIcon2, { size: 16, className: "text-text-500" })
}
),
/* @__PURE__ */ jsx6(Text_default, { size: "md", weight: "medium", className: "text-text-950", children: data.studentName })
] }),
/* @__PURE__ */ jsxs6("div", { className: "grid grid-cols-2 gap-3", children: [
/* @__PURE__ */ jsx6(
PerformanceCard,
{
icon: /* @__PURE__ */ jsx6(
LightbulbFilamentIcon,
{
size: 18,
weight: "fill",
className: "text-white"
}
),
label: labels.correctAnswersLabel,
value: data.correctAnswers,
secondaryLabel: labels.bestResultLabel,
secondaryValue: data.bestResult,
variant: "success"
}
),
/* @__PURE__ */ jsx6(
PerformanceCard,
{
icon: /* @__PURE__ */ jsx6(
WarningCircleIcon,
{
size: 18,
weight: "fill",
className: "text-error-700"
}
),
label: labels.incorrectAnswersLabel,
value: data.incorrectAnswers,
secondaryLabel: labels.hardestTopicLabel,
secondaryValue: data.hardestTopic,
variant: "error"
}
)
] }),
data.lessons.length > 0 && /* @__PURE__ */ jsxs6("div", { className: "flex flex-col gap-3", children: [
/* @__PURE__ */ jsx6(Text_default, { size: "md", weight: "semibold", className: "text-text-950", children: labels.lessonsTitle }),
/* @__PURE__ */ jsx6("div", { className: "flex flex-col gap-2", children: data.lessons.map((lesson) => /* @__PURE__ */ jsx6(LessonAccordionItem, { lesson }, lesson.id)) })
] })
] });
var renderModalContent = (loading, error, data, labels) => {
if (loading) {
return /* @__PURE__ */ jsx6(LoadingSkeleton2, {});
}
if (error) {
return /* @__PURE__ */ jsx6(ErrorContent, { message: error });
}
if (data) {
return /* @__PURE__ */ jsx6(PerformanceContent, { data, labels });
}
return null;
};
var StudentPerformanceModal = ({
isOpen,
onClose,
data,
loading = false,
error = null,
labels: customLabels
}) => {
const labels = useMemo(
() => ({ ...DEFAULT_PERFORMANCE_LABELS, ...customLabels }),
[customLabels]
);
if (!data && !loading && !error) {
return null;
}
return /* @__PURE__ */ jsx6(
Modal_default,
{
isOpen,
onClose,
title: labels.title,
size: "lg",
contentClassName: "max-h-[70vh] overflow-y-auto",
children: renderModalContent(loading, error, data, labels)
}
);
};
// src/components/RecommendedLessonDetails/components/StudentActivityPerformanceModal.tsx
import {
useMemo as useMemo2,
useState,
useCallback,
useEffect
} from "react";
import { TimerIcon } from "@phosphor-icons/react/dist/csr/Timer";
import { TrophyIcon as TrophyIcon2 } from "@phosphor-icons/react/dist/csr/Trophy";
import { WarningIcon as WarningIcon2 } from "@phosphor-icons/react/dist/csr/Warning";
import { UserIcon as UserIcon3 } from "@phosphor-icons/react/dist/csr/User";
import { WarningCircleIcon as WarningCircleIcon2 } from "@phosphor-icons/react/dist/csr/WarningCircle";
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
var EssayCorrectionField = {
IsCorrect: "isCorrect",
TeacherFeedback: "teacherFeedback"
};
var infoVariantConfig = {
time: {
borderColor: "border-primary-200",
labelColor: "text-primary-600",
IconComponent: TimerIcon,
iconColor: "text-primary-600"
},
best: {
borderColor: "border-success-200",
labelColor: "text-success-600",
IconComponent: TrophyIcon2,
iconColor: "text-success-600"
},
hardest: {
borderColor: "border-error-200",
labelColor: "text-error-600",
IconComponent: WarningIcon2,
iconColor: "text-error-600"
}
};
var InfoCard = ({
label,
value,
variant
}) => {
const config = infoVariantConfig[variant];
return /* @__PURE__ */ jsxs7(
"div",
{
className: cn(
"border rounded-xl py-3 px-4 flex flex-col items-center justify-center gap-2",
config.borderColor
),
children: [
/* @__PURE__ */ jsx7(Text_default, { className: cn("text-2xs font-medium uppercase", config.labelColor), children: label }),
/* @__PURE__ */ jsx7(Badge_default, { size: "large", action: "info", children: value || "-" })
]
}
);
};
var getAlternativeStatus2 = (isCorrect, isSelected) => {
if (isCorrect) return "correct" /* CORRECT */;
if (isSelected) return "incorrect" /* INCORRECT */;
return void 0;
};
var mapAlternatives2 = (question) => {
return question.alternatives.map((alt) => ({
value: alt.id,
label: alt.text,
status: getAlternativeStatus2(alt.isCorrect, alt.isSelected)
}));
};
var getSelectedValue2 = (question) => {
const selected = question.alternatives.find((alt) => alt.isSelected);
return selected?.id;
};
var getBadgeAction = (isCorrect) => {
if (isCorrect === true) return "success";
if (isCorrect === false) return "error";
return "info";
};
var getBadgeLabel = (isCorrect, labels) => {
if (isCorrect === true) return labels.markCorrect;
if (isCorrect === false) return labels.markIncorrect;
return labels.pending;
};
var getQuestionKey = (question) => {
if (question.answerId) {
return question.answerId;
}
return `${question.activityId}-${question.id}`;
};
var LessonItem = ({ lesson }) => /* @__PURE__ */ jsxs7("div", { className: "bg-background rounded-xl border border-border-50 py-4 px-4 flex flex-col gap-2", children: [
/* @__PURE__ */ jsx7(Text_default, { size: "sm", weight: "semibold", className: "text-text-950", children: lesson.title }),
/* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-2", children: [
/* @__PURE__ */ jsx7(
ProgressBar_default,
{
value: lesson.progress,
size: "small",
variant: "blue",
className: "flex-1"
}
),
/* @__PURE__ */ jsxs7(
Text_default,
{
size: "xs",
className: "text-primary-700 font-medium min-w-[40px] text-right",
children: [
lesson.progress,
"%"
]
}
)
] })
] });
var LoadingSkeleton3 = () => /* @__PURE__ */ jsxs7(
"div",
{
"data-testid": "loading-skeleton",
className: "flex flex-col gap-4 animate-pulse",
children: [
/* @__PURE__ */ jsx7("div", { className: "h-6 bg-background-200 rounded w-48" }),
/* @__PURE__ */ jsxs7("div", { className: "grid grid-cols-3 gap-3", children: [
/* @__PURE__ */ jsx7("div", { className: "h-28 bg-background-200 rounded-xl" }),
/* @__PURE__ */ jsx7("div", { className: "h-28 bg-background-200 rounded-xl" }),
/* @__PURE__ */ jsx7("div", { className: "h-28 bg-background-200 rounded-xl" })
] }),
/* @__PURE__ */ jsxs7("div", { className: "grid grid-cols-3 gap-3", children: [
/* @__PURE__ */ jsx7("div", { className: "h-20 bg-background-200 rounded-xl" }),
/* @__PURE__ */ jsx7("div", { className: "h-20 bg-background-200 rounded-xl" }),
/* @__PURE__ */ jsx7("div", { className: "h-20 bg-background-200 rounded-xl" })
] })
]
}
);
var ErrorContent2 = ({ message }) => /* @__PURE__ */ jsxs7("div", { className: "flex flex-col items-center justify-center py-8 gap-3", children: [
/* @__PURE__ */ jsx7(
Text_default,
{
as: "span",
className: "size-12 rounded-full bg-error-100 flex items-center justify-center",
children: /* @__PURE__ */ jsx7(WarningCircleIcon2, { size: 24, className: "text-error-700" })
}
),
/* @__PURE__ */ jsx7(Text_default, { size: "md", className: "text-error-700 text-center", children: message })
] });
var StudentActivityPerformanceModal = ({
isOpen,
onClose,
data,
loading = false,
error = null,
apiClient,
labels: customLabels
}) => {
const labels = useMemo2(
() => ({ ...DEFAULT_ACTIVITY_PERFORMANCE_LABELS, ...customLabels }),
[customLabels]
);
const addToast = ToastStore_default((state) => state.addToast);
const [essayCorrections, setEssayCorrections] = useState({});
useEffect(() => {
if (isOpen && data) {
const initialCorrections = {};
data.activities.forEach((activity) => {
activity.questions.forEach((question) => {
const questionKey = getQuestionKey(question);
initialCorrections[questionKey] = {
isCorrect: question.isCorrect,
teacherFeedback: question.teacherFeedback || "",
isSaving: false,
isSaved: question.isCorrect != null
};
});
});
setEssayCorrections(initialCorrections);
}
}, [isOpen, data]);
const updateEssayCorrection = useCallback(
(questionId, field, value) => {
setEssayCorrections((prev) => ({
...prev,
[questionId]: {
...prev[questionId],
[field]: value,
// Reset isSaved when any field changes so badge doesn't update until saved
isSaved: false
}
}));
},
[]
);
const handleSaveEssayCorrection = useCallback(
async (question) => {
if (!apiClient || !data) return;
const questionKey = getQuestionKey(question);
const correction = essayCorrections[questionKey];
if (correction?.isCorrect == null) {
return;
}
setEssayCorrections((prev) => ({
...prev,
[questionKey]: { ...prev[questionKey], isSaving: true }
}));
try {
await apiClient.post(
`/activities/${question.activityId}/students/${data.userId}/questions/correction`,
{
questionId: question.id,
isCorrect: correction.isCorrect,
teacherFeedback: correction.teacherFeedback
}
);
setEssayCorrections((prev) => ({
...prev,
[questionKey]: {
...prev[questionKey],
isSaving: false,
isSaved: true
}
}));
addToast({
title: "Corre\xE7\xE3o salva",
description: `A corre\xE7\xE3o da quest\xE3o foi salva com sucesso.`,
variant: "solid",
action: "success",
position: "top-right"
});
} catch (err) {
console.error("Erro ao salvar corre\xE7\xE3o da quest\xE3o:", err);
setEssayCorrections((prev) => ({
...prev,
[questionKey]: { ...prev[questionKey], isSaving: false }
}));
addToast({
title: "Erro ao salvar corre\xE7\xE3o",
description: "N\xE3o foi poss\xEDvel salvar a corre\xE7\xE3o. Tente novamente.",
variant: "solid",
action: "warning",
position: "top-right"
});
}
},
[apiClient, data, essayCorrections, addToast]
);
const handleClose = useCallback(() => {
setEssayCorrections({});
onClose();
}, [onClose]);
const renderCorrectionFields = (question) => {
const questionKey = getQuestionKey(question);
const correction = essayCorrections[questionKey] || {
isCorrect: null,
teacherFeedback: "",
isSaving: false,
isSaved: false
};
let radioValue;
if (correction.isCorrect === null) {
radioValue = void 0;
} else if (correction.isCorrect) {
radioValue = "true";
} else {
radioValue = "false";
}
return /* @__PURE__ */ jsxs7("div", { className: "space-y-4 border-t border-border-100 pt-4 mt-4", children: [
/* @__PURE__ */ jsxs7("div", { className: "space-y-2", children: [
/* @__PURE__ */ jsx7(Text_default, { className: "text-sm font-semibold text-text-950", children: labels.isCorrectQuestionLabel }),
/* @__PURE__ */ jsxs7("div", { className: "flex gap-4", children: [
/* @__PURE__ */ jsx7(
Radio_default,
{
name: `isCorrect-${questionKey}`,
value: "true",
id: `correct-yes-${questionKey}`,
label: labels.correctYes,
size: "medium",
checked: radioValue === "true",
disabled: correction.isSaving,
onChange: (e) => {
if (e.target.checked) {
updateEssayCorrection(
questionKey,
EssayCorrectionField.IsCorrect,
true
);
}
}
}
),
/* @__PURE__ */ jsx7(
Radio_default,
{
name: `isCorrect-${questionKey}`,
value: "false",
id: `correct-no-${questionKey}`,
label: labels.correctNo,
size: "medium",
checked: radioValue === "false",
disabled: correction.isSaving,
onChange: (e) => {
if (e.target.checked) {
updateEssayCorrection(
questionKey,
EssayCorrectionField.IsCorrect,
false
);
}
}
}
)
] })
] }),
/* @__PURE__ */ jsxs7("div", { className: "space-y-2", children: [
/* @__PURE__ */ jsx7(Text_default, { className: "text-sm font-semibold text-text-950", children: labels.observationLabel }),
/* @__PURE__ */ jsx7(
TextArea_default,
{
value: correction.teacherFeedback,
onChange: (e) => {
updateEssayCorrection(
questionKey,
EssayCorrectionField.TeacherFeedback,
e.target.value
);
},
placeholder: labels.feedbackPlaceholder,
rows: 4,
size: "medium",
disabled: correction.isSaving
}
)
] }),
/* @__PURE__ */ jsx7(
Button_default,
{
size: "small",
onClick: () => handleSaveEssayCorrection(question),
disabled: correction.isCorrect === null || correction.isSaving,
children: correction.isSaving ? labels.saving : labels.saveCorrection
}
)
] });
};
const renderQuestionAccordionItem = (question, index) => {
const questionKey = getQuestionKey(question);
const localCorrection = essayCorrections[questionKey];
const hasLocalSavedCorrection = localCorrection?.isSaved && localCorrection?.isCorrect != null;
const displayIsCorrect = hasLocalSavedCorrection ? localCorrection.isCorrect : question.isCorrect;
return /* @__PURE__ */ jsx7(
CardAccordation,
{
value: questionKey,
className: "bg-background rounded-xl border border-border-50",
triggerClassName: "py-4 px-4",
contentClassName: "px-4 pb-4",
trigger: /* @__PURE__ */ jsxs7("div", { className: "flex items-center justify-between flex-1", children: [
/* @__PURE__ */ jsxs7(Text_default, { size: "sm", weight: "semibold", className: "text-text-950", children: [
"Quest\xE3o ",
index + 1
] }),
/* @__PURE__ */ jsx7(
Badge_default,
{
size: "small",
action: getBadgeAction(displayIsCorrect),
variant: "solid",
children: getBadgeLabel(displayIsCorrect, labels)
}
)
] }),
children: /* @__PURE__ */ jsxs7("div", { className: "flex flex-col gap-4", children: [
/* @__PURE__ */ jsx7(
HtmlMathRenderer_default,
{
content: question.statement,
className: "text-sm text-text-700"
}
),
question.alternatives.length > 0 && /* @__PURE__ */ jsx7(
CardAccordation,
{
value: `${questionKey}-alternatives`,
className: "bg-background rounded-lg border border-border-50",
triggerClassName: "py-4 px-4",
contentClassName: "px-4 py-4",
trigger: /* @__PURE__ */ jsx7(Text_default, { size: "sm", weight: "medium", className: "text-text-800", children: "Alternativas" }),
children: /* @__PURE__ */ jsx7(
AlternativesList,
{
mode: "readonly",
alternatives: mapAlternatives2(question),
selectedValue: getSelectedValue2(question),
layout: "default"
}
)
}
),
apiClient && question.questionType === "DISSERTATIVA" && renderCorrectionFields(question)
] })
},
questionKey
);
};
const renderActivityAccordionItem = (activity) => /* @__PURE__ */ jsx7(
CardAccordation,
{
value: activity.id,
className: "bg-background rounded-xl border border-border-50",
triggerClassName: "py-4 px-4",
contentClassName: "px-4 pb-4",
trigger: /* @__PURE__ */ jsx7(Text_default, { size: "sm", weight: "semibold", className: "text-text-950", children: activity.title }),
children: /* @__PURE__ */ jsx7(AccordionGroup, { type: "multiple", className: "flex flex-col gap-2", children: activity.questions.map(
(question, index) => renderQuestionAccordionItem(question, index)
) })
},
activity.id
);
if (!data && !loading && !error) {
return null;
}
const renderContent = () => {
if (loading) {
return /* @__PURE__ */ jsx7(LoadingSkeleton3, {});
}
if (error) {
return /* @__PURE__ */ jsx7(ErrorContent2, { message: error });
}
if (data) {
const formattedScore = data.score == null ? "-" : data.score.toFixed(1);
return /* @__PURE__ */ jsxs7("div", { className: "flex flex-col gap-5", children: [
/* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-2", children: [
/* @__PURE__ */ jsx7(
Text_default,
{
as: "span",
className: "size-8 rounded-full bg-background-100 flex items-center justify-center",
children: /* @__PURE__ */ jsx7(UserIcon3, { size: 16, className: "text-text-500" })
}
),
/* @__PURE__ */ jsx7(Text_default, { size: "md", weight: "medium", className: "text-text-950", children: data.studentName })
] }),
/* @__PURE__ */ jsx7(Text_default, { size: "md", weight: "semibold", className: "text-text-950", children: labels.resultTitle }),
/* @__PURE__ */ jsxs7("div", { className: "grid grid-cols-3 gap-3", children: [
/* @__PURE__ */ jsx7(
StatCard,
{
label: labels.scoreLabel,
value: formattedScore,
variant: "score"
}
),
/* @__PURE__ */ jsx7(
StatCard,
{
label: labels.correctAnswersLabel,
value: data.correctAnswers,
variant: "correct"
}
),
/* @__PURE__ */ jsx7(
StatCard,
{
label: labels.incorrectAnswersLabel,
value: data.incorrectAnswers,
variant: "incorrect"
}
)
] }),
/* @__PURE__ */ jsxs7("div", { className: "grid grid-cols-3 gap-3", children: [
/* @__PURE__ */ jsx7(
InfoCard,
{
label: labels.completionTimeLabel,
value: data.completionTime,
variant: "time"
}
),
/* @__PURE__ */ jsx7(
InfoCard,
{
label: labels.bestResultLabel,
value: data.bestResult,
variant: "best"
}
),
/* @__PURE__ */ jsx7(
InfoCard,
{
label: labels.hardestTopicLabel,
value: data.hardestTopic,
variant: "hardest"
}
)
] }),
data.activities.length > 0 && /* @__PURE__ */ jsxs7("div", { className: "flex flex-col gap-3", children: [
/* @__PURE__ */ jsx7(Text_default, { size: "md", weight: "semibold", className: "text-text-950", children: labels.activitiesTitle }),
/* @__PURE__ */ jsx7(AccordionGroup, { type: "single", className: "flex flex-col gap-2", children: data.activities.map(
(activity) => renderActivityAccordionItem(activity)
) })
] }),
data.lessons && data.lessons.length > 0 && /* @__PURE__ */ jsxs7("div", { className: "flex flex-col gap-3", children: [
/* @__PURE__ */ jsx7(Text_default, { size: "md", weight: "semibold", className: "text-text-950", children: labels.lessonsTitle }),
/* @__PURE__ */ jsx7("div", { className: "flex flex-col gap-2", children: data.lessons.map((lesson) => /* @__PURE__ */ jsx7(LessonItem, { lesson }, lesson.id)) })
] })
] });
}
return null;
};
return /* @__PURE__ */ jsx7(
Modal_default,
{
isOpen,
onClose: handleClose,
title: labels.title,
size: "lg",
contentClassName: "max-h-[70vh] overflow-y-auto",
children: renderContent()
}
);
};
// src/components/RecommendedLessonDetails/components/RecommendedLessonViewModal.tsx
import { useState as useState2, useCallback as useCallback2, useEffect as useEffect2 } from "react";
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
var deriveRecommendedClassStatus = (startDate, finalDate, progress) => {
if (progress >= 100) return "CONCLU\xCDDA" /* CONCLUIDA */;
if (finalDate) {
const deadline = new Date(finalDate);
if (deadline < /* @__PURE__ */ new Date()) {
return "VENCIDA" /* VENCIDA */;
}
}
return "ATIVA" /* ATIVA */;
};
var LessonContentSkeleton = () => /* @__PURE__ */ jsxs8("div", { className: "flex flex-col gap-4 p-4", children: [
/* @__PURE__ */ jsx8(SkeletonRounded, { height: 200, className: "w-full" }),
/* @__PURE__ */ jsx8(Skeleton, { variant: "text", width: "80%", height: 20 }),
/* @__PURE__ */ jsx8(SkeletonRounded, { height: 60, className: "w-full" })
] });
var LessonContent = ({
lessonId,
apiClient,
cachedLessons,
onLessonLoaded
}) => {
const [loading, setLoading] = useState2(!cachedLessons[lessonId]);
const [error, setError] = useState2(null);
const lesson = cachedLessons[lessonId];
useEffect2(() => {
if (lesson || !apiClient) return;
const fetchLesson = async () => {
setLoading(true);
setError(null);
try {
const response = await apiClient.get(
`/lesson/${lessonId}`
);
onLessonLoaded(lessonId, response.data.data);
} catch {
setError("Erro ao carregar dados da aula");
} finally {
setLoading(false);
}
};
fetchLesson();
}, [lessonId, apiClient, lesson, onLessonLoaded]);
if (loading) {
return /* @__PURE__ */ jsx8(LessonContentSkeleton, {});
}
if (error) {
return /* @__PURE__ */ jsx8("div", { className: "p-4", children: /* @__PURE__ */ jsx8(Text_default, { size: "sm", className: "text-error-700", children: error }) });
}
if (!lesson) {
return /* @__PURE__ */ jsx8("div", { className: "p-4", children: /* @__PURE__ */ jsx8(Text_default, { size: "sm", className: "text-text-500", children: "Dados da aula n\xE3o dispon\xEDveis" }) });
}
const hasVideo = Boolean(lesson.urlVideo);
const hasPodcast = Boolean(lesson.urlPodCast);
const boardImages = [];
if (lesson.urlInitialFrame) {
boardImages.push({ id: "initial", imageUrl: lesson.urlInitialFrame });
}
if (lesson.urlFinalFrame) {
boardImages.push({ id: "final", imageUrl: lesson.urlFinalFrame });
}
const hasBoards = boardImages.length > 0;
return /* @__PURE__ */ jsxs8("div", { className: "flex flex-col gap-4", children: [
hasVideo ? /* @__PURE__ */ jsx8(
VideoPlayer_default,
{
src: lesson.urlVideo,
poster: lesson.urlCover,
subtitles: lesson.urlSubtitle,
className: "w-full rounded-lg"
}
) : /* @__PURE__ */ jsx8("div", { className: "p-4 bg-background-50 rounded-lg", children: /* @__PURE__ */ jsx8(Text_default, { size: "sm", className: "text-text-500", children: "V\xEDdeo n\xE3o dispon\xEDvel para esta aula." }) }),
/* @__PURE__ */ jsx8(
Alert_default,
{
action: "info",
variant: "solid",
description: "Cada aula inclui question\xE1rios autom\xE1ticos para o aluno praticar o conte\xFAdo.",
className: "w-full"
}
),
hasPodcast && /* @__PURE__ */ jsxs8("div", { className: "w-full", children: [
/* @__PURE__ */ jsx8(Text_default, { size: "md", weight: "bold", className: "pb-2", children: "Podcast" }),
/* @__PURE__ */ jsx8(
CardAudio,
{
src: lesson.urlPodCast,
title: lesson.podCastTitle || "Podcast da aula"
}
)
] }),
hasBoards && /* @__PURE__ */ jsxs8("div", { className: "w-full", children: [
/* @__PURE__ */ jsx8(Text_default, { size: "md", weight: "bold", className: "pb-2", children: "Quadros da aula" }),
/* @__PURE__ */ jsx8("div", { className: "flex flex-wrap items-center justify-center gap-4", children: boardImages.map((image) => /* @__PURE__ */ jsx8(
"div",
{
className: "flex flex-row rounded-xl bg-background-50",
children: /* @__PURE__ */ jsx8(
Whiteboard_default,
{
images: [image],
showDownload: true,
imagesPerRow: 2,
className: "gap-4 w-full items-center border-border-50"
}
)
},
image.id
)) })
] })
] });
};
var LessonAccordionItem2 = ({
lessonItem,
apiClient,
cachedLessons,
onLessonLoaded
}) => {
const [isExpanded, setIsExpanded] = useState2(false);
const { isDark } = useTheme();
const lesson = lessonItem.supLessonsProgress.lesson;
const lessonId = lesson.id;
const subjectColor = lesson.subject?.color;
const trigger = /* @__PURE__ */ jsxs8("div", { className: "flex flex-col gap-1 py-3", children: [
/* @__PURE__ */ jsxs8(Text_default, { size: "xs", className: "text-text-500", children: [
lesson.topic?.name,
" \u2022 ",
lesson.subtopic?.name,
" \u2022 ",
lesson.content?.name
] }),
/* @__PURE__ */ jsx8(Text_default, { size: "md", weight: "medium", className: "text-text-950", children: lesson.content?.name || lesson.videoTitle })
] });
return /* @__PURE__ */ jsxs8("div", { className: "rounded-xl overflow-hidden border border-border-100", children: [
/* @__PURE__ */ jsx8(
"div",
{
className: cn(
"px-4 py-2",
subjectColor?.startsWith("bg-") && subjectColor
),
style: subjectColor && !subjectColor.startsWith("bg-") ? {
backgro