UNPKG

analytica-frontend-lib

Version:

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

1,372 lines (1,361 loc) 62 kB
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