@hydralms/components 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +61 -0
  3. package/dist/assessment-toolbar/assessment-toolbar.d.ts +2 -0
  4. package/dist/assessment-toolbar/index.d.ts +4 -0
  5. package/dist/assessment-toolbar/question-navigator.d.ts +2 -0
  6. package/dist/assessment-toolbar/timer-display.d.ts +2 -0
  7. package/dist/assessment-toolbar/types.d.ts +89 -0
  8. package/dist/common/confirm-dialog.d.ts +2 -0
  9. package/dist/common/due-date-display.d.ts +2 -0
  10. package/dist/common/empty-state.d.ts +2 -0
  11. package/dist/common/index.d.ts +6 -0
  12. package/dist/common/search-input.d.ts +2 -0
  13. package/dist/common/status-badge.d.ts +2 -0
  14. package/dist/common/types.d.ts +124 -0
  15. package/dist/components.css +1 -0
  16. package/dist/content/content-block.d.ts +2 -0
  17. package/dist/content/file-upload-zone.d.ts +2 -0
  18. package/dist/content/index.d.ts +3 -0
  19. package/dist/content/types.d.ts +95 -0
  20. package/dist/curriculum/curriculum-item.d.ts +2 -0
  21. package/dist/curriculum/curriculum-tree.d.ts +2 -0
  22. package/dist/curriculum/index.d.ts +4 -0
  23. package/dist/curriculum/learning-object-icon.d.ts +2 -0
  24. package/dist/curriculum/types.d.ts +79 -0
  25. package/dist/feedback/feedback-banner.d.ts +2 -0
  26. package/dist/feedback/index.d.ts +4 -0
  27. package/dist/feedback/likert-scale.d.ts +2 -0
  28. package/dist/feedback/star-rating.d.ts +2 -0
  29. package/dist/feedback/types.d.ts +83 -0
  30. package/dist/flashcards/flashcard-deck.d.ts +2 -0
  31. package/dist/flashcards/flashcard.d.ts +2 -0
  32. package/dist/flashcards/index.d.ts +3 -0
  33. package/dist/flashcards/types.d.ts +58 -0
  34. package/dist/index.cjs +1 -0
  35. package/dist/index.d.ts +13 -0
  36. package/dist/index.js +159 -0
  37. package/dist/lib/utils.d.ts +2 -0
  38. package/dist/progress/grade-indicator.d.ts +2 -0
  39. package/dist/progress/index.d.ts +4 -0
  40. package/dist/progress/progress-ring.d.ts +2 -0
  41. package/dist/progress/stat-card.d.ts +2 -0
  42. package/dist/progress/types.d.ts +73 -0
  43. package/dist/provider/HydraProvider.d.ts +9 -0
  44. package/dist/provider/index.d.ts +2 -0
  45. package/dist/questions/choice.d.ts +11 -0
  46. package/dist/questions/essay.d.ts +11 -0
  47. package/dist/questions/fill-in-the-blank.d.ts +11 -0
  48. package/dist/questions/index.d.ts +7 -0
  49. package/dist/questions/multiple-choice.d.ts +11 -0
  50. package/dist/questions/question-renderer.d.ts +12 -0
  51. package/dist/questions/true-false.d.ts +11 -0
  52. package/dist/questions/types.d.ts +47 -0
  53. package/dist/sections/AnnouncementFeed/AnnouncementFeed.d.ts +2 -0
  54. package/dist/sections/AnnouncementFeed/types.d.ts +52 -0
  55. package/dist/sections/AssessmentReview/AssessmentReview.d.ts +2 -0
  56. package/dist/sections/AssessmentReview/types.d.ts +58 -0
  57. package/dist/sections/AssignmentSubmission/AssignmentSubmission.d.ts +2 -0
  58. package/dist/sections/AssignmentSubmission/types.d.ts +65 -0
  59. package/dist/sections/CertificateViewer/CertificateViewer.d.ts +2 -0
  60. package/dist/sections/CertificateViewer/types.d.ts +47 -0
  61. package/dist/sections/CourseOutline/CourseOutline.d.ts +2 -0
  62. package/dist/sections/CourseOutline/types.d.ts +49 -0
  63. package/dist/sections/DiscussionThread/DiscussionThread.d.ts +2 -0
  64. package/dist/sections/DiscussionThread/types.d.ts +74 -0
  65. package/dist/sections/ExamSession/ExamSession.d.ts +2 -0
  66. package/dist/sections/ExamSession/types.d.ts +62 -0
  67. package/dist/sections/FlashcardStudySession/FlashcardStudySession.d.ts +2 -0
  68. package/dist/sections/FlashcardStudySession/types.d.ts +40 -0
  69. package/dist/sections/GradebookTable/GradebookTable.d.ts +2 -0
  70. package/dist/sections/GradebookTable/types.d.ts +71 -0
  71. package/dist/sections/LecturePlayer/LecturePlayer.d.ts +2 -0
  72. package/dist/sections/LecturePlayer/types.d.ts +47 -0
  73. package/dist/sections/LessonPage/LessonPage.d.ts +2 -0
  74. package/dist/sections/LessonPage/types.d.ts +40 -0
  75. package/dist/sections/PracticeQuiz/PracticeQuiz.d.ts +2 -0
  76. package/dist/sections/PracticeQuiz/types.d.ts +42 -0
  77. package/dist/sections/ProgressDashboard/ProgressDashboard.d.ts +2 -0
  78. package/dist/sections/ProgressDashboard/types.d.ts +73 -0
  79. package/dist/sections/QuizSession/QuizSession.d.ts +2 -0
  80. package/dist/sections/QuizSession/types.d.ts +46 -0
  81. package/dist/sections/ResourceLibrary/ResourceLibrary.d.ts +2 -0
  82. package/dist/sections/ResourceLibrary/types.d.ts +58 -0
  83. package/dist/sections/ScrollableQuiz/ScrollableQuiz.d.ts +2 -0
  84. package/dist/sections/ScrollableQuiz/types.d.ts +42 -0
  85. package/dist/sections/SurveyForm/SurveyForm.d.ts +2 -0
  86. package/dist/sections/SurveyForm/types.d.ts +69 -0
  87. package/dist/sections/index.d.ts +34 -0
  88. package/dist/sections.cjs +1 -0
  89. package/dist/sections.js +1898 -0
  90. package/dist/social/index.d.ts +3 -0
  91. package/dist/social/post-card.d.ts +2 -0
  92. package/dist/social/types.d.ts +59 -0
  93. package/dist/social/user-avatar.d.ts +2 -0
  94. package/dist/table-CW4_BYny.js +9869 -0
  95. package/dist/table-DSBBqb9X.cjs +56 -0
  96. package/dist/ui/alert-dialog.d.ts +14 -0
  97. package/dist/ui/alert.d.ts +9 -0
  98. package/dist/ui/avatar.d.ts +5 -0
  99. package/dist/ui/badge.d.ts +9 -0
  100. package/dist/ui/button.d.ts +10 -0
  101. package/dist/ui/card.d.ts +9 -0
  102. package/dist/ui/index.d.ts +15 -0
  103. package/dist/ui/input.d.ts +3 -0
  104. package/dist/ui/progress.d.ts +13 -0
  105. package/dist/ui/separator.d.ts +6 -0
  106. package/dist/ui/skeleton.d.ts +3 -0
  107. package/dist/ui/slot.d.ts +8 -0
  108. package/dist/ui/table.d.ts +10 -0
  109. package/dist/ui/tabs.d.ts +7 -0
  110. package/dist/ui/textarea.d.ts +3 -0
  111. package/dist/ui/tooltip.d.ts +8 -0
  112. package/dist/utils/debounce.d.ts +1 -0
  113. package/dist/utils/format-duration.d.ts +2 -0
  114. package/dist/video/index.d.ts +2 -0
  115. package/dist/video/types.d.ts +37 -0
  116. package/dist/video/video-player.d.ts +2 -0
  117. package/package.json +94 -0
@@ -0,0 +1,40 @@
1
+ import { LessonBlock } from '../../content/types';
2
+ /**
3
+ * LessonPage section — a multi-content lesson experience.
4
+ *
5
+ * Sequences video, rich text, images, embedded quizzes, flashcards,
6
+ * and callouts into a single scrollable page with a sticky completion
7
+ * bar at the bottom.
8
+ *
9
+ * @example
10
+ * <LessonPage
11
+ * title="React Hooks Deep Dive"
12
+ * blocks={lessonBlocks}
13
+ * onMarkComplete={() => completeLesson()}
14
+ * onNextLesson={() => navigate(nextLesson)}
15
+ * />
16
+ */
17
+ export interface LessonPageProps {
18
+ /** Lesson title */
19
+ title: string;
20
+ /** Ordered content blocks */
21
+ blocks: LessonBlock[];
22
+ /** Whether the lesson is already marked complete */
23
+ isCompleted?: boolean;
24
+ /** Called when the user marks the lesson complete */
25
+ onMarkComplete?: () => void;
26
+ /** Called when the user clicks "Next Lesson" */
27
+ onNextLesson?: () => void;
28
+ /** Next lesson title shown on the completion bar */
29
+ nextLessonTitle?: string;
30
+ /** Estimated duration in seconds */
31
+ estimatedDuration?: number;
32
+ /** Whether to show estimated duration */
33
+ showDuration?: boolean;
34
+ /** When true, disables interactive elements */
35
+ readOnly?: boolean;
36
+ /** CSS class name for the root element */
37
+ className?: string;
38
+ /** Inline styles for the root element */
39
+ style?: React.CSSProperties;
40
+ }
@@ -0,0 +1,2 @@
1
+ import { PracticeQuizProps } from './types';
2
+ export declare function PracticeQuiz({ questions: questionsProp, instantFeedback, allowRetry, onComplete, shuffled, readOnly, className, style, }: PracticeQuizProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,42 @@
1
+ import { QuestionData } from '../../questions/types';
2
+ /**
3
+ * PracticeQuiz section — a low-stakes practice quiz with instant feedback.
4
+ *
5
+ * After each answer the correct answer is revealed with an explanation.
6
+ * Users can retry incorrect questions. A completion screen shows stats
7
+ * when all questions have been attempted.
8
+ *
9
+ * @example
10
+ * <PracticeQuiz
11
+ * questions={questions}
12
+ * onComplete={(stats) => trackPractice(stats)}
13
+ * instantFeedback
14
+ * allowRetry
15
+ * />
16
+ */
17
+ export interface PracticeQuizProps {
18
+ /** Ordered list of questions to practice */
19
+ questions: QuestionData[];
20
+ /** Whether to reveal the correct answer immediately after answering */
21
+ instantFeedback?: boolean;
22
+ /** Whether to allow retrying incorrect answers */
23
+ allowRetry?: boolean;
24
+ /** Called when the user completes all questions */
25
+ onComplete?: (stats: PracticeQuizStats) => void;
26
+ /** Whether to shuffle the question order */
27
+ shuffled?: boolean;
28
+ /** When true, all inputs are disabled */
29
+ readOnly?: boolean;
30
+ /** CSS class name for the root element */
31
+ className?: string;
32
+ /** Inline styles for the root element */
33
+ style?: React.CSSProperties;
34
+ }
35
+ export interface PracticeQuizStats {
36
+ /** Total number of questions */
37
+ totalQuestions: number;
38
+ /** Questions answered correctly on the first attempt */
39
+ correctOnFirstAttempt: number;
40
+ /** Total answer attempts across all questions */
41
+ totalAttempts: number;
42
+ }
@@ -0,0 +1,2 @@
1
+ import { ProgressDashboardProps } from './types';
2
+ export declare function ProgressDashboard({ overallProgress, totalTimeSpent, modules, recentActivity, streak, achievements, recentActivityLimit, onModuleClick, className, style, }: ProgressDashboardProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,73 @@
1
+ /**
2
+ * ProgressDashboard section — a visual course progress overview.
3
+ *
4
+ * Shows overall completion, time spent, streak data, per-module progress,
5
+ * recent activity log, and earned achievements.
6
+ *
7
+ * @example
8
+ * <ProgressDashboard
9
+ * overallProgress={72}
10
+ * totalTimeSpent={14400}
11
+ * modules={modules}
12
+ * streak={{ currentDays: 5, longestDays: 12 }}
13
+ * />
14
+ */
15
+ export interface ProgressDashboardProps {
16
+ /** Overall course progress percentage (0-100) */
17
+ overallProgress: number;
18
+ /** Total time spent in seconds */
19
+ totalTimeSpent: number;
20
+ /** Per-module progress */
21
+ modules: ModuleProgress[];
22
+ /** Recent activity items */
23
+ recentActivity?: ActivityItem[];
24
+ /** Streak data */
25
+ streak?: {
26
+ currentDays: number;
27
+ longestDays: number;
28
+ };
29
+ /** Earned achievements/badges */
30
+ achievements?: Achievement[];
31
+ /** Number of recent activity items to show */
32
+ recentActivityLimit?: number;
33
+ /** Called when the user clicks a module */
34
+ onModuleClick?: (moduleUid: string) => void;
35
+ /** CSS class name for the root element */
36
+ className?: string;
37
+ /** Inline styles for the root element */
38
+ style?: React.CSSProperties;
39
+ }
40
+ export interface ModuleProgress {
41
+ /** Unique identifier */
42
+ uid: string;
43
+ /** Module name */
44
+ name: string;
45
+ /** Completed items count */
46
+ completedItems: number;
47
+ /** Total items in the module */
48
+ totalItems: number;
49
+ /** Time spent in seconds */
50
+ timeSpent: number;
51
+ }
52
+ export interface ActivityItem {
53
+ /** Unique identifier */
54
+ uid: string;
55
+ /** Activity description */
56
+ description: string;
57
+ /** Activity timestamp */
58
+ timestamp: string;
59
+ /** Activity type */
60
+ type: "lesson_completed" | "quiz_passed" | "assignment_submitted" | "badge_earned";
61
+ }
62
+ export interface Achievement {
63
+ /** Unique identifier */
64
+ uid: string;
65
+ /** Achievement name */
66
+ name: string;
67
+ /** Achievement description */
68
+ description: string;
69
+ /** Icon URL */
70
+ iconUrl?: string;
71
+ /** Date earned */
72
+ earnedAt: string;
73
+ }
@@ -0,0 +1,2 @@
1
+ import { QuizSessionProps } from './types';
2
+ export declare function QuizSession({ questions, initialAnswers, onSubmit, onAnswerChange, timeElapsedSeconds, timeLimitSeconds, isSubmitting, readOnly, className, style, }: QuizSessionProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,46 @@
1
+ import { QuestionData, SessionAnswer } from '../../questions/types';
2
+ /**
3
+ * QuizSession section — a complete assessment session experience.
4
+ *
5
+ * Manages question navigation, per-question answer accumulation, and
6
+ * flag toggling. Combines AssessmentToolbar with QuestionRenderer.
7
+ * Pass your questions array and an onSubmit callback — everything
8
+ * else is handled internally.
9
+ *
10
+ * @example
11
+ * <QuizSession
12
+ * questions={questions}
13
+ * onSubmit={(answers) => submitAssessment(answers)}
14
+ * timeLimitSeconds={1800}
15
+ * />
16
+ */
17
+ export interface QuizSessionProps {
18
+ /** Ordered list of questions to present */
19
+ questions: QuestionData[];
20
+ /**
21
+ * Pre-populated answers — use to resume a session already in progress.
22
+ */
23
+ initialAnswers?: SessionAnswer[];
24
+ /**
25
+ * Called when the user clicks Submit.
26
+ * Receives the final accumulated answers array.
27
+ */
28
+ onSubmit: (answers: SessionAnswer[]) => void;
29
+ /**
30
+ * Called whenever the user changes an answer (useful for auto-save).
31
+ * Fires with the full answers array after each mutation.
32
+ */
33
+ onAnswerChange?: (answers: SessionAnswer[]) => void;
34
+ /** Elapsed time in seconds — renders the timer in the toolbar when provided */
35
+ timeElapsedSeconds?: number;
36
+ /** Time limit in seconds — enables countdown mode in the timer */
37
+ timeLimitSeconds?: number;
38
+ /** Whether the submit action is currently in flight */
39
+ isSubmitting?: boolean;
40
+ /** When true, all inputs are disabled (e.g. after submission) */
41
+ readOnly?: boolean;
42
+ /** CSS class name for the root element */
43
+ className?: string;
44
+ /** Inline styles for the root element */
45
+ style?: React.CSSProperties;
46
+ }
@@ -0,0 +1,2 @@
1
+ import { ResourceLibraryProps } from './types';
2
+ export declare function ResourceLibrary({ resources, categories, onResourceClick, onDownload, viewMode: initialViewMode, allowViewToggle, showSearch, emptyMessage, readOnly, className, style, }: ResourceLibraryProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,58 @@
1
+ /**
2
+ * ResourceLibrary section — a searchable resource catalog.
3
+ *
4
+ * Displays downloadable course resources in a grid or list view with
5
+ * search, category tabs, and view mode toggling.
6
+ *
7
+ * @example
8
+ * <ResourceLibrary
9
+ * resources={resources}
10
+ * categories={categories}
11
+ * onResourceClick={(r) => download(r)}
12
+ * />
13
+ */
14
+ export interface ResourceLibraryProps {
15
+ /** Resources to display */
16
+ resources: Resource[];
17
+ /** Optional categories for tab filtering */
18
+ categories?: {
19
+ uid: string;
20
+ label: string;
21
+ }[];
22
+ /** Called when the user clicks a resource */
23
+ onResourceClick: (resource: Resource) => void;
24
+ /** Called when the user downloads a resource */
25
+ onDownload?: (resource: Resource) => void;
26
+ /** Layout view mode */
27
+ viewMode?: "grid" | "list";
28
+ /** Whether the user can toggle between grid and list */
29
+ allowViewToggle?: boolean;
30
+ /** Whether to show search */
31
+ showSearch?: boolean;
32
+ /** Empty state message */
33
+ emptyMessage?: string;
34
+ /** When true, disables interactions */
35
+ readOnly?: boolean;
36
+ /** CSS class name for the root element */
37
+ className?: string;
38
+ /** Inline styles for the root element */
39
+ style?: React.CSSProperties;
40
+ }
41
+ export interface Resource {
42
+ /** Unique identifier */
43
+ uid: string;
44
+ /** Resource name */
45
+ name: string;
46
+ /** Optional description */
47
+ description?: string;
48
+ /** Resource type */
49
+ type: "pdf" | "document" | "video" | "link" | "image" | "archive" | "other";
50
+ /** Resource URL */
51
+ url: string;
52
+ /** File size in bytes */
53
+ fileSize?: number;
54
+ /** Category UID for filtering */
55
+ categoryUid?: string;
56
+ /** Date added as ISO string */
57
+ addedAt?: string;
58
+ }
@@ -0,0 +1,2 @@
1
+ import { ScrollableQuizProps } from './types';
2
+ export declare function ScrollableQuiz({ questions, initialAnswers, onSubmit, onAnswerChange, showNavigator, showQuestionNumbers, questionGroups, isSubmitting, readOnly, className, style, }: ScrollableQuizProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,42 @@
1
+ import { QuestionData, SessionAnswer } from '../../questions/types';
2
+ /**
3
+ * ScrollableQuiz section — all questions on a single scrollable page.
4
+ *
5
+ * Renders every question in a vertical list with a sticky sidebar navigator
6
+ * that highlights the currently visible question. Supports optional question
7
+ * grouping by section labels.
8
+ *
9
+ * @example
10
+ * <ScrollableQuiz
11
+ * questions={questions}
12
+ * onSubmit={(answers) => submit(answers)}
13
+ * showNavigator
14
+ * />
15
+ */
16
+ export interface ScrollableQuizProps {
17
+ /** Ordered list of questions to present */
18
+ questions: QuestionData[];
19
+ /** Pre-populated answers for resuming */
20
+ initialAnswers?: SessionAnswer[];
21
+ /** Called when the user clicks Submit with the full answers array */
22
+ onSubmit: (answers: SessionAnswer[]) => void;
23
+ /** Called whenever the user changes any answer (useful for auto-save) */
24
+ onAnswerChange?: (answers: SessionAnswer[]) => void;
25
+ /** Whether to show the sticky sidebar navigator */
26
+ showNavigator?: boolean;
27
+ /** Whether to show question numbers beside each question */
28
+ showQuestionNumbers?: boolean;
29
+ /** Optional grouping of questions into labeled sections */
30
+ questionGroups?: {
31
+ label: string;
32
+ questionUids: string[];
33
+ }[];
34
+ /** Whether the submit action is in flight */
35
+ isSubmitting?: boolean;
36
+ /** When true, all inputs are disabled */
37
+ readOnly?: boolean;
38
+ /** CSS class name for the root element */
39
+ className?: string;
40
+ /** Inline styles for the root element */
41
+ style?: React.CSSProperties;
42
+ }
@@ -0,0 +1,2 @@
1
+ import { SurveyFormProps } from './types';
2
+ export declare function SurveyForm({ title, description, questions, initialAnswers, onSubmit, onAnswerChange, showProgress, requireAll, submitLabel, isSubmitting, readOnly, className, style, }: SurveyFormProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,69 @@
1
+ import { ReactNode } from 'react';
2
+ import { AnswerOption } from '../../questions/types';
3
+ /**
4
+ * SurveyForm section — an ungraded survey/feedback form.
5
+ *
6
+ * Supports Likert scale, star rating, open-text, single-choice,
7
+ * and multiple-choice question types. Questions can be displayed
8
+ * all at once or one at a time.
9
+ *
10
+ * @example
11
+ * <SurveyForm
12
+ * title="Course Evaluation"
13
+ * questions={surveyQuestions}
14
+ * onSubmit={(answers) => submitSurvey(answers)}
15
+ * />
16
+ */
17
+ export interface SurveyFormProps {
18
+ /** Survey title displayed at the top */
19
+ title: string;
20
+ /** Optional introductory text or description */
21
+ description?: ReactNode;
22
+ /** Survey questions */
23
+ questions: SurveyQuestion[];
24
+ /** Pre-populated answers */
25
+ initialAnswers?: SurveyAnswer[];
26
+ /** Called on submission with all answers */
27
+ onSubmit: (answers: SurveyAnswer[]) => void;
28
+ /** Called whenever any answer changes */
29
+ onAnswerChange?: (answers: SurveyAnswer[]) => void;
30
+ /** Whether to show a progress indicator */
31
+ showProgress?: boolean;
32
+ /** Whether all questions must be answered before submit */
33
+ requireAll?: boolean;
34
+ /** Label for the submit button */
35
+ submitLabel?: string;
36
+ /** Whether the submit action is in flight */
37
+ isSubmitting?: boolean;
38
+ /** When true, all inputs are disabled */
39
+ readOnly?: boolean;
40
+ /** CSS class name for the root element */
41
+ className?: string;
42
+ /** Inline styles for the root element */
43
+ style?: React.CSSProperties;
44
+ }
45
+ export interface SurveyQuestion {
46
+ /** Unique identifier */
47
+ uid: string;
48
+ /** Question type */
49
+ type: "likert" | "rating" | "open_text" | "choice" | "multiple_choice";
50
+ /** Question text */
51
+ content: string;
52
+ /** For likert: labels for scale endpoints */
53
+ scaleLabels?: {
54
+ low: string;
55
+ high: string;
56
+ };
57
+ /** For likert: number of scale points */
58
+ scalePoints?: 5 | 7;
59
+ /** For choice/multiple_choice: answer options */
60
+ answers?: AnswerOption[];
61
+ /** Whether this question is required */
62
+ required?: boolean;
63
+ }
64
+ export interface SurveyAnswer {
65
+ /** Question UID */
66
+ questionUid: string;
67
+ /** Answer value — string for text, number for likert/rating, uid for choice */
68
+ value: string | number;
69
+ }
@@ -0,0 +1,34 @@
1
+ export { QuizSession } from './QuizSession/QuizSession';
2
+ export type { QuizSessionProps } from './QuizSession/types';
3
+ export { LecturePlayer } from './LecturePlayer/LecturePlayer';
4
+ export type { LecturePlayerProps } from './LecturePlayer/types';
5
+ export { FlashcardStudySession } from './FlashcardStudySession/FlashcardStudySession';
6
+ export type { FlashcardStudySessionProps, FlashcardSessionStats, } from './FlashcardStudySession/types';
7
+ export { AssessmentReview } from './AssessmentReview/AssessmentReview';
8
+ export type { AssessmentReviewProps, AssessmentScore, AssessmentReviewGroup, } from './AssessmentReview/types';
9
+ export { CourseOutline } from './CourseOutline/CourseOutline';
10
+ export type { CourseOutlineProps } from './CourseOutline/types';
11
+ export { ScrollableQuiz } from './ScrollableQuiz/ScrollableQuiz';
12
+ export type { ScrollableQuizProps } from './ScrollableQuiz/types';
13
+ export { PracticeQuiz } from './PracticeQuiz/PracticeQuiz';
14
+ export type { PracticeQuizProps, PracticeQuizStats, } from './PracticeQuiz/types';
15
+ export { ExamSession } from './ExamSession/ExamSession';
16
+ export type { ExamSessionProps, ExamSubmitMetadata, } from './ExamSession/types';
17
+ export { SurveyForm } from './SurveyForm/SurveyForm';
18
+ export type { SurveyFormProps, SurveyQuestion, SurveyAnswer, } from './SurveyForm/types';
19
+ export { LessonPage } from './LessonPage/LessonPage';
20
+ export type { LessonPageProps } from './LessonPage/types';
21
+ export { ResourceLibrary } from './ResourceLibrary/ResourceLibrary';
22
+ export type { ResourceLibraryProps, Resource, } from './ResourceLibrary/types';
23
+ export { AnnouncementFeed } from './AnnouncementFeed/AnnouncementFeed';
24
+ export type { AnnouncementFeedProps, Announcement, } from './AnnouncementFeed/types';
25
+ export { DiscussionThread } from './DiscussionThread/DiscussionThread';
26
+ export type { DiscussionThreadProps, DiscussionPost, DiscussionUser, } from './DiscussionThread/types';
27
+ export { AssignmentSubmission } from './AssignmentSubmission/AssignmentSubmission';
28
+ export type { AssignmentSubmissionProps, SubmissionData, } from './AssignmentSubmission/types';
29
+ export { GradebookTable } from './GradebookTable/GradebookTable';
30
+ export type { GradebookTableProps, GradeItem, GradeCategory, OverallGrade, } from './GradebookTable/types';
31
+ export { ProgressDashboard } from './ProgressDashboard/ProgressDashboard';
32
+ export type { ProgressDashboardProps, ModuleProgress, ActivityItem, Achievement, } from './ProgressDashboard/types';
33
+ export { CertificateViewer } from './CertificateViewer/CertificateViewer';
34
+ export type { CertificateViewerProps } from './CertificateViewer/types';
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),p=require("react"),t=require("./table-DSBBqb9X.cjs"),M=require("lucide-react");function W({questions:n,initialAnswers:r=[],onSubmit:l,onAnswerChange:c,timeElapsedSeconds:f,timeLimitSeconds:a,isSubmitting:m=!1,readOnly:i=!1,className:w,style:C}){const[d,b]=p.useState(0),[D,u]=p.useState(r),[z,N]=p.useState(new Set),T=n[d],j=p.useMemo(()=>n.map((S,h)=>({uid:S.uid,sequence:h+1,isFlagged:z.has(S.uid),isAnswered:D.some(x=>x.uid===S.uid),isSkipped:!1})),[n,D,z]);function k(S){if(!T)return;const h=T.uid,x=S.map(v=>({uid:h,answerUid:v.uid,content:v.content}));u(v=>{const y=[...v.filter(A=>A.uid!==h),...x];return c==null||c(y),y})}function s(S){const h=n.findIndex(x=>x.uid===S);h!==-1&&b(h)}function o(S){N(h=>{const x=new Set(h);return x.has(S)?x.delete(S):x.add(S),x})}function g(){l(D)}return e.jsxs("div",{className:t.cn(w),style:C,children:[e.jsx(t.AssessmentToolbar,{currentQuestionIndex:d,totalQuestions:n.length,hasNext:d<n.length-1,hasPrevious:d>0,onNext:()=>b(S=>Math.min(S+1,n.length-1)),onPrevious:()=>b(S=>Math.max(S-1,0)),onSubmit:g,timeElapsedSeconds:f,timeLimitSeconds:a,questions:j,onNavigateToQuestion:s,onToggleFlag:o,currentQuestionUid:T==null?void 0:T.uid,isSubmitting:m,readOnly:i}),T&&e.jsx(t.Card,{className:"mt-3",children:e.jsx(t.CardContent,{className:"pt-6",children:e.jsx(t.QuestionRenderer,{question:T,sessionAnswers:D.filter(S=>S.uid===T.uid),onAnswer:k,readOnly:i})})})]})}function X({video:n,notes:r,layout:l="horizontal",notesPanelWidth:c="340px",notesPanelHeight:f="240px",className:a,style:m}){const i=l==="horizontal";return r?e.jsxs("div",{className:t.cn("flex overflow-hidden",i?"flex-row":"flex-col",a),style:m,children:[e.jsx("div",{className:"flex-1 min-w-0 min-h-0",children:e.jsx(t.VideoPlayer,{...n})}),e.jsxs(t.Card,{className:t.cn("overflow-auto shrink-0 rounded-none border-0",i?"border-l border-border":"border-t border-border w-full"),style:{width:i?c:void 0,height:i?void 0:f},children:[e.jsx(t.CardHeader,{children:e.jsx(t.CardTitle,{children:"Notes"})}),e.jsx(t.CardContent,{children:typeof r=="string"?e.jsx("span",{className:"text-sm text-foreground",children:r}):r})]})]}):e.jsx("div",{className:a,style:m,children:e.jsx(t.VideoPlayer,{...n})})}function O({cards:n,title:r,description:l,shuffled:c=!1,onComplete:f,readOnly:a=!1,className:m,style:i}){const[w,C]=p.useState(!1),d={totalCards:n.length,wasShuffled:c};function b(){C(!0),f==null||f(d)}function D(){C(!1)}return w?e.jsx("div",{className:t.cn(m),style:i,children:e.jsx(t.Card,{children:e.jsxs(t.CardContent,{className:"pt-6 text-center flex flex-col items-center gap-2",children:[e.jsx(M.CheckCircle,{size:48,className:"text-success"}),e.jsx("span",{className:"text-xl font-bold text-foreground",children:"Deck complete!"}),r&&e.jsxs("span",{className:"text-muted-foreground",children:["You finished ",e.jsx("strong",{children:r})]}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:[d.totalCards," card",d.totalCards!==1?"s":""," studied",d.wasShuffled?" (shuffled)":""]}),e.jsx(t.Button,{className:"mt-1",onClick:D,children:"Study Again"})]})})}):e.jsx("div",{className:t.cn(m),style:i,children:e.jsx(t.FlashcardDeck,{cards:n,deckName:r,deckDescription:l,shuffled:c,showProgress:!0,onComplete:b,readOnly:a})})}function q({score:n}){const r=n.percentage!==void 0?n.percentage:n.total>0?Math.round(n.correct/n.total*100):0;return e.jsx(t.Card,{className:"mb-3",children:e.jsx(t.CardContent,{className:"pt-6",children:e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsxs("div",{children:[e.jsxs("span",{className:"text-2xl font-bold leading-none text-foreground",children:[r,"%"]}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:[n.correct," of ",n.total," correct"]})]}),n.passed!==void 0&&e.jsx(t.Badge,{variant:n.passed?"success":"destructive",children:n.passed?"Passed":"Failed"}),n.passingScore!==void 0&&e.jsxs("span",{className:"text-sm text-muted-foreground",children:["Passing score: ",n.passingScore,"%"]})]})})})}function V({questions:n,sessionAnswers:r,showCorrectAnswers:l}){return e.jsx("div",{className:"flex flex-col gap-3",children:n.map((c,f)=>e.jsxs(t.Card,{className:"overflow-hidden",children:[e.jsx("div",{className:"px-2 py-1 bg-muted",children:e.jsxs("span",{className:"text-xs text-muted-foreground font-semibold",children:["Question ",f+1]})}),e.jsx(t.Separator,{}),e.jsx(t.CardContent,{className:"pt-4 pb-6",children:e.jsx(t.QuestionRenderer,{question:c,sessionAnswers:r.filter(a=>a.uid===c.uid),readOnly:!0,showCorrectAnswers:l})})]},c.uid))})}function ee(n,r,l,c){const f=new Map(n.map(i=>[i.uid,i])),a=new Set(l.flatMap(i=>i.questionUids)),m=n.filter(i=>!a.has(i.uid));return e.jsxs("div",{className:"flex flex-col gap-4",children:[l.map(i=>{const w=i.questionUids.map(C=>f.get(C)).filter(Boolean);return e.jsxs("div",{children:[e.jsx("span",{className:"uppercase text-xs tracking-wide text-muted-foreground font-semibold",children:i.label}),e.jsx(t.Separator,{className:"mb-2"}),e.jsx(V,{questions:w,sessionAnswers:r,showCorrectAnswers:c})]},i.label)}),m.length>0&&e.jsx("div",{children:e.jsx(V,{questions:m,sessionAnswers:r,showCorrectAnswers:c})})]})}function te({questions:n,sessionAnswers:r,score:l,questionGroups:c,showCorrectAnswers:f=!0,className:a,style:m}){return e.jsxs("div",{className:t.cn(a),style:m,children:[l&&e.jsx(q,{score:l}),c&&c.length>0?ee(n,r,c,f):e.jsx(V,{questions:n,sessionAnswers:r,showCorrectAnswers:f})]})}function G(n){const r=[];for(const l of n)!l.children||l.children.length===0?r.push(l.uid):r.push(...G(l.children));return r}function se({items:n,progress:r,courseTitle:l,activeItemUid:c,onItemClick:f,showOverallProgress:a=!0,showDuration:m=!0,showIcons:i=!0,readOnly:w=!1,className:C,style:d}){const{completedCount:b,totalCount:D,percentage:u}=p.useMemo(()=>{const z=G(n),N=z.length,T=r?z.filter(j=>r.some(k=>k.resourceUid===j&&k.isCompleted)).length:0;return{completedCount:T,totalCount:N,percentage:N>0?Math.round(T/N*100):0}},[n,r]);return e.jsxs("div",{className:t.cn(C),style:d,children:[(l||a)&&e.jsxs("div",{className:"px-2 pt-2 pb-1",children:[l&&e.jsx("p",{className:t.cn("font-semibold text-sm text-foreground",a&&"mb-1"),children:l}),a&&e.jsxs("div",{children:[e.jsx(t.Progress,{value:u,size:"sm"}),e.jsxs("span",{className:"text-xs text-muted-foreground mt-0.5 block",children:[b," of ",D," completed"]})]})]}),e.jsx(t.CurriculumTree,{items:n,progress:r,activeItemUid:c,onItemClick:f,readOnly:w,showDuration:m,showIcons:i,showProgress:!0})]})}function ne({questions:n,initialAnswers:r=[],onSubmit:l,onAnswerChange:c,showNavigator:f=!0,showQuestionNumbers:a=!0,questionGroups:m,isSubmitting:i=!1,readOnly:w=!1,className:C,style:d}){var S;const[b,D]=p.useState(r),[u,z]=p.useState(((S=n[0])==null?void 0:S.uid)??null),N=p.useRef(new Map),T=p.useMemo(()=>{const h=new Set(b.map(x=>x.uid));return n.filter(x=>h.has(x.uid)).length},[n,b]);p.useEffect(()=>{const h=new IntersectionObserver(x=>{for(const v of x)v.isIntersecting&&z(v.target.getAttribute("data-question-uid"))},{rootMargin:"-20% 0px -60% 0px"});return N.current.forEach(x=>h.observe(x)),()=>h.disconnect()},[n]);const j=p.useCallback((h,x)=>{x?N.current.set(h,x):N.current.delete(h)},[]);function k(h,x){const v=x.map(U=>({uid:h,answerUid:U.uid,content:U.content}));D(U=>{const A=[...U.filter(F=>F.uid!==h),...v];return c==null||c(A),A})}function s(h){var x;(x=N.current.get(h))==null||x.scrollIntoView({behavior:"smooth",block:"center"})}const o=p.useMemo(()=>{if(!m)return[{label:null,questions:n}];const h=m.map(U=>({label:U.label,questions:U.questionUids.map(y=>n.find(A=>A.uid===y)).filter(Boolean)})),x=new Set(m.flatMap(U=>U.questionUids)),v=n.filter(U=>!x.has(U.uid));return v.length>0&&h.push({label:null,questions:v}),h},[n,m]);let g=0;return e.jsxs("div",{className:t.cn("flex gap-3",C),style:d,children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[o.map((h,x)=>e.jsxs("div",{children:[h.label&&e.jsx("p",{className:t.cn("text-lg font-semibold mb-2 text-foreground",x>0&&"mt-4"),children:h.label}),h.questions.map(v=>{const U=g++;return e.jsx(t.Card,{ref:y=>j(v.uid,y),"data-question-uid":v.uid,className:"mb-2",children:e.jsxs(t.CardContent,{className:"pt-6",children:[a&&e.jsxs("p",{className:"font-semibold text-sm text-muted-foreground mb-1",children:["Question ",U+1]}),e.jsx(t.QuestionRenderer,{question:v,sessionAnswers:b.filter(y=>y.uid===v.uid),onAnswer:y=>k(v.uid,y),readOnly:w})]})},v.uid)})]},x)),e.jsxs("div",{className:"mt-3 flex justify-between items-center",children:[e.jsxs("span",{className:"text-sm text-muted-foreground",children:[T," of ",n.length," answered"]}),e.jsx(t.Button,{onClick:()=>l(b),disabled:i||w,children:i?"Submitting...":"Submit"})]})]}),f&&e.jsxs(t.Card,{className:"hidden md:block w-50 shrink-0 sticky top-4 self-start p-3",children:[e.jsx("p",{className:"font-semibold text-sm mb-1 text-foreground",children:"Questions"}),e.jsx("div",{className:"flex flex-wrap gap-0.5",children:n.map((h,x)=>{const v=b.some(y=>y.uid===h.uid),U=u===h.uid;return e.jsx("button",{type:"button",className:t.cn("inline-flex items-center justify-center text-xs font-medium min-w-9 px-1 py-0.5 rounded-full cursor-pointer border transition-colors",U?"bg-primary border-primary text-primary-foreground":v?"border-success text-success bg-transparent":"border-border text-foreground bg-transparent hover:bg-muted"),onClick:()=>s(h.uid),children:x+1},h.uid)})})]})]})}function re(n){const r=[...n];for(let l=r.length-1;l>0;l--){const c=Math.floor(Math.random()*(l+1));[r[l],r[c]]=[r[c],r[l]]}return r}function ae({questions:n,instantFeedback:r=!0,allowRetry:l=!0,onComplete:c,shuffled:f=!1,readOnly:a=!1,className:m,style:i}){const w=p.useMemo(()=>f?re(n):n,[n,f]),[C,d]=p.useState(0),[b,D]=p.useState(new Set),[u,z]=p.useState(new Map),[N,T]=p.useState(new Set),[j,k]=p.useState(null),[s,o]=p.useState(!1),g=w[C],S=g?b.has(g.uid):!1;function h(){var $;if(!g||!j)return;const y=(u.get(g.uid)??0)+1;z(R=>new Map(R).set(g.uid,y)),D(R=>new Set(R).add(g.uid));const A=new Set((($=g.answers)==null?void 0:$.filter(R=>R.isCorrect).map(R=>R.uid))??[]),F=new Set(j.map(R=>R.uid));A.size===F.size&&[...A].every(R=>F.has(R))&&y===1&&T(R=>new Set(R).add(g.uid))}function x(){g&&(D(y=>{const A=new Set(y);return A.delete(g.uid),A}),k(null))}function v(){if(C<w.length-1)d(y=>y+1),k(null);else{const y={totalQuestions:w.length,correctOnFirstAttempt:N.size,totalAttempts:Array.from(u.values()).reduce((A,F)=>A+F,0)};o(!0),c==null||c(y)}}const U=p.useMemo(()=>{var F;if(!g||!j)return!1;const y=new Set(((F=g.answers)==null?void 0:F.filter(I=>I.isCorrect).map(I=>I.uid))??[]),A=new Set(j.map(I=>I.uid));return y.size===A.size&&[...y].every(I=>A.has(I))},[g,j]);if(s){const y=w.length>0?Math.round(N.size/w.length*100):0;return e.jsx(t.Card,{className:m,style:i,children:e.jsxs(t.CardContent,{className:"pt-6 text-center",children:[e.jsx(M.CheckCircle,{size:48,className:"text-success mx-auto mb-4"}),e.jsx("p",{className:"text-xl font-bold mb-1 text-foreground",children:"Practice Complete!"}),e.jsxs("p",{className:"text-muted-foreground mb-2",children:[N.size," of ",w.length," correct on first attempt (",y,"%)"]}),e.jsx("div",{className:"flex justify-center",children:e.jsx(t.Button,{variant:"outline",onClick:()=>{d(0),D(new Set),z(new Map),T(new Set),k(null),o(!1)},children:"Practice Again"})})]})})}return e.jsxs("div",{className:m,style:i,children:[e.jsxs("div",{className:"flex justify-between items-center mb-2",children:[e.jsxs("span",{className:"font-semibold text-sm text-foreground",children:["Question ",C+1," of ",w.length]}),e.jsxs("span",{className:"text-xs text-muted-foreground",children:[N.size," correct on first try"]})]}),e.jsx(t.Progress,{value:C+(S?1:0),max:w.length,size:"sm",className:"mb-3"}),g&&e.jsx(t.Card,{children:e.jsxs(t.CardContent,{className:"pt-6",children:[e.jsx(t.QuestionRenderer,{question:g,sessionAnswers:(j==null?void 0:j.map(y=>({uid:g.uid,answerUid:y.uid,content:y.content})))??[],onAnswer:y=>k(y),readOnly:a||S,showCorrectAnswers:S}),r&&S&&e.jsx(t.FeedbackBanner,{isCorrect:U,explanation:g.explanation,onRetry:l&&!U?x:void 0}),e.jsxs("div",{className:"flex justify-end gap-1 mt-2",children:[!S&&r&&e.jsx(t.Button,{onClick:h,disabled:!j||j.length===0||a,children:"Check Answer"}),(!r||S)&&e.jsx(t.Button,{onClick:v,disabled:a,children:C<w.length-1?"Next Question":"Finish"})]})]})})]})}function le({questions:n,initialAnswers:r=[],onSubmit:l,onAnswerChange:c,timeLimitSeconds:f,timeElapsedSeconds:a,autoSubmitOnTimeout:m=!0,timeWarningThreshold:i=300,allowBackNavigation:w=!0,confirmBeforeSubmit:C=!0,examTitle:d,instructions:b,isSubmitting:D=!1,readOnly:u=!1,className:z,style:N}){const[T,j]=p.useState(0),[k,s]=p.useState(r),[o,g]=p.useState(new Set),[S,h]=p.useState(!1),[x,v]=p.useState(!1),U=p.useRef(!1),y=n[T],A=f-a;p.useEffect(()=>{A<=i&&A>0&&v(!0)},[A,i]),p.useEffect(()=>{m&&A<=0&&!U.current&&(U.current=!0,_(!0))},[A,m]);const F=p.useMemo(()=>n.map((B,P)=>({uid:B.uid,sequence:P+1,isFlagged:o.has(B.uid),isAnswered:k.some(L=>L.uid===B.uid),isSkipped:!1})),[n,k,o]);function I(B){if(!y)return;const P=y.uid,L=B.map(Q=>({uid:P,answerUid:Q.uid,content:Q.content}));s(Q=>{const H=[...Q.filter(K=>K.uid!==P),...L];return c==null||c(H),H})}function $(B){const P=n.findIndex(L=>L.uid===B);P!==-1&&j(P)}function R(B){g(P=>{const L=new Set(P);return L.has(B)?L.delete(B):L.add(B),L})}function J(){C?h(!0):_(!1)}function _(B){const P=new Set(k.map(Q=>Q.uid)),L={timeElapsedSeconds:a,wasAutoSubmitted:B,answeredCount:n.filter(Q=>P.has(Q.uid)).length,totalQuestions:n.length};l(k,L)}return e.jsxs("div",{className:t.cn(z),style:N,children:[d&&e.jsx("p",{className:"text-xl font-bold mb-2 text-foreground",children:d}),x&&A>0&&A<=i&&e.jsx(t.Alert,{variant:"warning",className:"mb-2",children:e.jsxs(t.AlertDescription,{children:[Math.ceil(A/60)," minute",Math.ceil(A/60)!==1?"s":""," remaining"]})}),e.jsx(t.AssessmentToolbar,{currentQuestionIndex:T,totalQuestions:n.length,hasNext:T<n.length-1,hasPrevious:w&&T>0,onNext:()=>j(B=>Math.min(B+1,n.length-1)),onPrevious:()=>w&&j(B=>Math.max(B-1,0)),onSubmit:J,timeElapsedSeconds:a,timeLimitSeconds:f,questions:F,onNavigateToQuestion:$,onToggleFlag:R,currentQuestionUid:y==null?void 0:y.uid,isSubmitting:D,readOnly:u}),b&&T===0&&e.jsx(t.Card,{className:"mb-2",children:e.jsx(t.CardContent,{className:"pt-6",children:b})}),y&&e.jsx(t.Card,{className:"mt-3",children:e.jsx(t.CardContent,{className:"pt-6",children:e.jsx(t.QuestionRenderer,{question:y,sessionAnswers:k.filter(B=>B.uid===y.uid),onAnswer:I,readOnly:u})})}),e.jsx(t.ConfirmDialog,{open:S,title:"Submit Exam?",message:`You have answered ${F.filter(B=>B.isAnswered).length} of ${n.length} questions. Once submitted, you cannot change your answers.`,confirmLabel:"Submit Exam",cancelLabel:"Continue Exam",confirmColor:"primary",onConfirm:()=>{h(!1),_(!1)},onCancel:()=>h(!1),isLoading:D})]})}function ie({title:n,description:r,questions:l,initialAnswers:c=[],onSubmit:f,onAnswerChange:a,showProgress:m=!0,requireAll:i=!1,submitLabel:w="Submit Survey",isSubmitting:C=!1,readOnly:d=!1,className:b,style:D}){const[u,z]=p.useState(c),N=p.useMemo(()=>{const s=new Set(u.map(o=>o.questionUid));return l.filter(o=>s.has(o.uid)).length},[l,u]),T=!i||N===l.length;function j(s,o){z(g=>{const h=[...g.filter(x=>x.questionUid!==s),{questionUid:s,value:o}];return a==null||a(h),h})}function k(s){return u.find(o=>o.questionUid===s)}return e.jsxs("div",{className:b,style:D,children:[e.jsx("p",{className:"text-xl font-bold text-foreground mb-1",children:n}),r&&e.jsx("div",{className:"mb-2 text-muted-foreground text-sm",children:typeof r=="string"?e.jsx("span",{children:r}):r}),m&&e.jsxs("div",{className:"mb-3",children:[e.jsx(t.Progress,{value:N/l.length*100}),e.jsxs("span",{className:"block text-xs text-muted-foreground mt-0.5",children:[N," of ",l.length," answered"]})]}),l.map((s,o)=>{var S,h;const g=k(s.uid);return e.jsx(t.Card,{className:"mb-2",children:e.jsxs(t.CardContent,{className:"pt-6",children:[e.jsxs("p",{className:"font-medium text-foreground mb-2",children:[o+1,". ",s.content,s.required&&e.jsx("span",{className:"text-destructive ml-0.5",children:"*"})]}),s.type==="likert"&&e.jsx(t.LikertScale,{value:g?Number(g.value):null,onChange:x=>j(s.uid,x),points:s.scalePoints,lowLabel:(S=s.scaleLabels)==null?void 0:S.low,highLabel:(h=s.scaleLabels)==null?void 0:h.high,readOnly:d}),s.type==="rating"&&e.jsx(t.StarRating,{value:g?Number(g.value):0,onChange:x=>j(s.uid,x),readOnly:d}),s.type==="open_text"&&e.jsx(t.Textarea,{placeholder:"Type your response...",value:(g==null?void 0:g.value)??"",onChange:x=>j(s.uid,x.target.value),disabled:d,className:"min-h-24"}),s.type==="choice"&&s.answers&&e.jsx("div",{className:"flex flex-col gap-2",children:s.answers.map(x=>e.jsxs("label",{className:"flex items-center gap-2 cursor-pointer py-1 text-sm text-foreground has-[input:disabled]:cursor-default has-[input:disabled]:opacity-60",children:[e.jsx("input",{type:"radio",className:"accent-primary m-0 shrink-0",name:`survey-q-${s.uid}`,value:x.uid,checked:(g==null?void 0:g.value)===x.uid,onChange:()=>j(s.uid,x.uid),disabled:d}),e.jsx("span",{children:x.content})]},x.uid))}),s.type==="multiple_choice"&&s.answers&&e.jsx("div",{className:"flex flex-col gap-2",children:s.answers.map(x=>{const v=u.filter(U=>U.questionUid===s.uid).map(U=>String(U.value));return e.jsxs("label",{className:"flex items-center gap-2 cursor-pointer py-1 text-sm text-foreground has-[input:disabled]:cursor-default has-[input:disabled]:opacity-60",children:[e.jsx("input",{type:"checkbox",className:"accent-primary m-0 shrink-0",checked:v.includes(x.uid),disabled:d,onChange:U=>{const y=u.filter(F=>F.questionUid===s.uid);let A;U.target.checked?A=[...y,{questionUid:s.uid,value:x.uid}]:A=y.filter(F=>String(F.value)!==x.uid),z(F=>[...F.filter(I=>I.questionUid!==s.uid),...A]),a==null||a([...u.filter(F=>F.questionUid!==s.uid),...A])}}),e.jsx("span",{children:x.content})]},x.uid)})})]})},s.uid)}),e.jsxs("div",{className:"flex justify-between items-center mt-2",children:[e.jsxs("span",{className:"text-sm text-muted-foreground",children:[N," of ",l.length," answered"]}),e.jsx(t.Button,{onClick:()=>f(u),disabled:!T||C||d,children:C?"Submitting...":w})]})]})}function de({title:n,blocks:r,isCompleted:l=!1,onMarkComplete:c,onNextLesson:f,nextLessonTitle:a,estimatedDuration:m,showDuration:i=!0,readOnly:w=!1,className:C,style:d}){const[b,D]=p.useState(l),[,u]=p.useState(new Map);function z(T,j){u(k=>new Map(k).set(T,j))}function N(){D(!0),c==null||c()}return e.jsxs("div",{className:t.cn(C),style:d,children:[e.jsxs("div",{className:"mb-3",children:[e.jsx("p",{className:"text-2xl font-bold mb-0.5 text-foreground",children:n}),i&&m!=null&&e.jsxs("div",{className:"flex items-center gap-0.5 text-muted-foreground",children:[e.jsx(M.Clock,{size:16}),e.jsx("span",{className:"text-sm",children:t.formatDuration(m)})]})]}),e.jsx(t.Separator,{className:"mb-3"}),e.jsx("div",{className:"flex flex-col gap-3",children:r.map((T,j)=>e.jsx(t.ContentBlock,{block:T,onQuestionAnswer:z,readOnly:w},j))}),e.jsx("div",{className:"border border-border rounded-md px-4 py-3 mt-4 sticky bottom-0 bg-background z-10",children:e.jsxs("div",{className:"flex justify-between items-center",children:[b?e.jsxs("div",{className:"flex items-center gap-1 text-success",children:[e.jsx(M.Check,{size:20}),e.jsx("span",{className:"text-sm font-semibold",children:"Lesson Complete"})]}):e.jsxs(t.Button,{onClick:N,disabled:w,children:[e.jsx(M.Check,{size:18})," Mark Complete"]}),f&&e.jsxs(t.Button,{variant:b?"default":"outline",onClick:f,children:[a?`Next: ${a}`:"Next Lesson"," ",e.jsx(M.ChevronRight,{size:18})]})]})})]})}function Y(n){return n<1024?`${n} B`:n<1024*1024?`${(n/1024).toFixed(1)} KB`:`${(n/(1024*1024)).toFixed(1)} MB`}const Z={pdf:"document",document:"document",video:"video",link:"link",image:"document",archive:"document",other:"document"};function ce({resources:n,categories:r,onResourceClick:l,onDownload:c,viewMode:f="list",allowViewToggle:a=!0,showSearch:m=!0,emptyMessage:i="No resources found",readOnly:w=!1,className:C,style:d}){const[b,D]=p.useState(""),[u,z]=p.useState(null),[N,T]=p.useState(f),j=p.useMemo(()=>{let s=n;if(u&&(s=s.filter(o=>o.categoryUid===u)),b.trim()){const o=b.toLowerCase();s=s.filter(g=>{var S;return g.name.toLowerCase().includes(o)||((S=g.description)==null?void 0:S.toLowerCase().includes(o))})}return s},[n,u,b]);function k(s){const o=Z[s.type]??"document";return e.jsxs("div",{className:t.cn("flex items-center gap-3 px-3 py-2",!w&&"cursor-pointer hover:bg-muted",w&&"opacity-70"),onClick:()=>!w&&l(s),children:[e.jsx("div",{className:"min-w-10",children:e.jsx(t.LearningObjectIcon,{type:o,size:20})}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("span",{className:"text-sm text-foreground",children:s.name}),(s.description||s.fileSize!=null)&&e.jsx("span",{className:"text-sm text-muted-foreground",children:[s.description,s.fileSize!=null&&Y(s.fileSize)].filter(Boolean).join(" · ")})]}),c&&e.jsxs(t.Tooltip,{children:[e.jsx(t.TooltipTrigger,{render:e.jsx(t.Button,{variant:"ghost",size:"icon-xs","aria-label":"Download",onClick:g=>{g.stopPropagation(),c(s)},children:e.jsx(M.Download,{size:16})})}),e.jsx(t.TooltipContent,{children:"Download"})]})]},s.uid)}return e.jsxs("div",{className:C,style:d,children:[e.jsxs("div",{className:"flex gap-2 items-center mb-2",children:[m&&e.jsx("div",{className:"flex-1 max-w-80",children:e.jsx(t.SearchInput,{value:b,onChange:D,placeholder:"Search resources...",size:"small"})}),a&&e.jsxs("div",{className:"flex gap-0.5",children:[e.jsxs(t.Tooltip,{children:[e.jsx(t.TooltipTrigger,{render:e.jsx(t.Button,{variant:"ghost",size:"icon-xs","aria-label":"List view",className:t.cn(N==="list"&&"text-primary"),onClick:()=>T("list"),children:e.jsx(M.List,{size:18})})}),e.jsx(t.TooltipContent,{children:"List view"})]}),e.jsxs(t.Tooltip,{children:[e.jsx(t.TooltipTrigger,{render:e.jsx(t.Button,{variant:"ghost",size:"icon-xs","aria-label":"Grid view",className:t.cn(N==="grid"&&"text-primary"),onClick:()=>T("grid"),children:e.jsx(M.Grid,{size:18})})}),e.jsx(t.TooltipContent,{children:"Grid view"})]})]})]}),r&&r.length>0&&e.jsx(t.Tabs,{value:u??"all",onValueChange:s=>z(s==="all"?null:s),className:"mb-2",children:e.jsxs(t.TabsList,{children:[e.jsx(t.TabsTrigger,{value:"all",children:"All"}),r.map(s=>e.jsx(t.TabsTrigger,{value:s.uid,children:s.label},s.uid))]})}),j.length===0?e.jsx(t.EmptyState,{title:i,description:"Try adjusting your search or filter."}):N==="list"?e.jsx(t.Card,{children:j.map(k)}):e.jsx("div",{className:"grid grid-cols-[repeat(auto-fill,minmax(240px,1fr))] gap-2",children:j.map(s=>e.jsx(t.Card,{className:t.cn("transition-colors",!w&&"cursor-pointer hover:border-primary"),onClick:()=>!w&&l(s),children:e.jsxs(t.CardContent,{className:"pt-4 pb-4",children:[e.jsxs("div",{className:"flex gap-1 items-center mb-1",children:[e.jsx(t.LearningObjectIcon,{type:Z[s.type]??"document",size:20}),e.jsx("span",{className:"font-semibold text-sm text-foreground truncate",children:s.name})]}),s.description&&e.jsx("p",{className:"text-sm text-muted-foreground mb-1 truncate",children:s.description}),s.fileSize!=null&&e.jsx("span",{className:"text-xs text-muted-foreground",children:Y(s.fileSize)})]})},s.uid))})]})}function oe(n){const r=new Date(n),c=new Date().getTime()-r.getTime(),f=Math.floor(c/6e4);if(f<1)return"Just now";if(f<60)return`${f}m ago`;const a=Math.floor(f/60);if(a<24)return`${a}h ago`;const m=Math.floor(a/24);return m<7?`${m}d ago`:r.toLocaleDateString()}function ue({announcements:n,onMarkRead:r,onSelect:l,showAvatars:c=!0,previewLines:f=3,emptyMessage:a="No announcements yet",readOnly:m=!1,className:i,style:w}){const[C,d]=p.useState(new Set),b=p.useMemo(()=>{const u=n.filter(N=>N.isPinned),z=n.filter(N=>!N.isPinned);return[...u,...z]},[n]);function D(u){d(N=>{const T=new Set(N);return T.has(u)?T.delete(u):T.add(u),T});const z=n.find(N=>N.uid===u);z&&!z.isRead&&(r==null||r(u))}return b.length===0?e.jsx("div",{className:i,style:w,children:e.jsx(t.EmptyState,{title:a})}):e.jsx("div",{className:t.cn("flex flex-col gap-2",i),style:w,children:b.map(u=>{const z=C.has(u.uid);return e.jsx(t.Card,{className:t.cn(u.isRead&&"opacity-85",l&&"cursor-pointer",u.isPinned&&"border-l-4 border-l-warning"),onClick:()=>l&&!m?l(u):D(u.uid),children:e.jsx(t.CardContent,{className:"pt-4 pb-4",children:e.jsxs("div",{className:"flex gap-1.5 items-start",children:[c&&e.jsx(t.UserAvatar,{displayName:u.author.displayName,avatarUrl:u.author.avatarUrl,role:u.author.role,size:"medium"}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-1 mb-0.5",children:[u.isPinned&&e.jsx(M.Pin,{size:14}),e.jsx("span",{className:t.cn("text-foreground",u.isRead?"font-normal":"font-semibold"),children:u.title}),!u.isRead&&e.jsx(t.Badge,{variant:"destructive",className:"text-[10px] px-1.5 py-0",children:"New"})]}),e.jsxs("span",{className:"block text-xs text-muted-foreground mb-1",children:[u.author.displayName," · ",oe(u.createdAt)]}),e.jsx("span",{className:t.cn("text-sm text-foreground",!z&&"line-clamp-(--preview-lines) overflow-hidden"),style:z?void 0:{"--preview-lines":f},children:u.content}),!z&&u.content.length>200&&e.jsx(t.Button,{variant:"link",size:"xs",className:"px-0 mt-0.5 h-auto",onClick:N=>{N.stopPropagation(),D(u.uid)},children:"Read more"})]})]})})},u.uid)})})}function xe({title:n,rootPost:r,replies:l,currentUser:c,onReply:f,onToggleLike:a,onMarkAnswer:m,maxDepth:i=3,allowReplies:w=!0,sortOrder:C="oldest",readOnly:d=!1,className:b,style:D}){const[u,z]=p.useState(null),[N,T]=p.useState(""),j=p.useMemo(()=>{const o=new Map;for(const g of l){const S=g.parentUid??r.uid,h=o.get(S)??[];h.push(g),o.set(S,h)}for(const[,g]of o)g.sort((S,h)=>C==="newest"?new Date(h.createdAt).getTime()-new Date(S.createdAt).getTime():C==="most_liked"?h.likeCount-S.likeCount:new Date(S.createdAt).getTime()-new Date(h.createdAt).getTime());return o},[l,r.uid,C]);function k(o){N.trim()&&(f(o,N.trim()),T(""),z(null))}function s(o,g){const S=j.get(o.uid)??[],h=Math.min(g,i),x=e.jsxs("div",{className:"flex items-center gap-1",children:[a&&!d&&e.jsxs(t.Tooltip,{children:[e.jsx(t.TooltipTrigger,{render:e.jsxs(t.Button,{variant:"ghost",size:"sm","aria-label":o.isLikedByCurrentUser?"Unlike":"Like",className:t.cn(o.isLikedByCurrentUser&&"text-destructive"),onClick:()=>a(o.uid),children:[e.jsx(M.Heart,{size:14,fill:o.isLikedByCurrentUser?"currentColor":"none"}),o.likeCount>0?o.likeCount:"Like"]})}),e.jsx(t.TooltipContent,{children:o.isLikedByCurrentUser?"Unlike":"Like"})]}),w&&!d&&e.jsxs(t.Tooltip,{children:[e.jsx(t.TooltipTrigger,{render:e.jsxs(t.Button,{variant:"ghost",size:"sm","aria-label":"Reply",onClick:()=>z(o.uid),children:[e.jsx(M.Reply,{size:14}),"Reply"]})}),e.jsx(t.TooltipContent,{children:"Reply"})]}),m&&!d&&c.role!=="student"&&!o.isAnswer&&e.jsxs(t.Tooltip,{children:[e.jsx(t.TooltipTrigger,{render:e.jsxs(t.Button,{variant:"ghost",size:"sm","aria-label":"Mark as answer",className:"text-success",onClick:()=>m(o.uid),children:[e.jsx(M.CheckCircle,{size:14}),"Mark Answer"]})}),e.jsx(t.TooltipContent,{children:"Mark as answer"})]})]});return e.jsxs("div",{children:[e.jsx(t.PostCard,{author:o.author,content:o.content,createdAt:o.createdAt,updatedAt:o.updatedAt,actions:x,highlight:o.isAnswer?"answer":"none",indentLevel:h,className:"mb-1"}),u===o.uid&&e.jsx(t.Card,{className:"mb-1",style:{marginLeft:`${(h+1)*16}px`},children:e.jsxs(t.CardContent,{className:"pt-4 pb-4",children:[e.jsx(t.Textarea,{className:"min-h-15 mb-1",placeholder:"Write a reply...",value:N,onChange:v=>T(v.target.value)}),e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(t.Button,{size:"sm",onClick:()=>k(o.uid),disabled:!N.trim(),children:"Post Reply"}),e.jsx(t.Button,{variant:"ghost",size:"sm",onClick:()=>{z(null),T("")},children:"Cancel"})]})]})}),S.map(v=>s(v,g+1))]},o.uid)}return e.jsxs("div",{className:b,style:D,children:[e.jsxs("div",{className:"flex items-center gap-1 mb-2",children:[e.jsx(M.MessageSquare,{size:20,className:"text-foreground shrink-0"}),e.jsx("span",{className:"text-lg font-semibold text-foreground",children:n}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:[l.length," ",l.length===1?"reply":"replies"]})]}),e.jsx(t.Separator,{className:"mb-2"}),s(r,0)]})}function me({title:n,instructions:r,dueDate:l,maxScore:c,status:f,submissionTypes:a,existingSubmission:m,fileConstraints:i,onSubmit:w,onSaveDraft:C,grade:d,isSubmitting:b=!1,readOnly:D=!1,className:u,style:z}){const[N,T]=p.useState((m==null?void 0:m.textContent)??""),[j,k]=p.useState((m==null?void 0:m.files)??[]),[s,o]=p.useState((m==null?void 0:m.url)??""),[g,S]=p.useState(a[0]),h=!D&&!["submitted","graded"].includes(f);function x(){return{textContent:a.includes("text")?N:void 0,files:a.includes("file")?j:void 0,url:a.includes("url")?s:void 0}}return e.jsxs("div",{className:u,style:z,children:[e.jsx("div",{className:"flex justify-between items-start mb-2",children:e.jsxs("div",{children:[e.jsx("div",{className:"text-xl font-bold text-foreground mb-0.5",children:n}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(t.StatusBadge,{status:f}),l&&e.jsx(t.DueDateDisplay,{dueDate:l,size:"small"}),c!=null&&e.jsxs("span",{className:"text-sm text-muted-foreground",children:[c," points"]})]})]})}),e.jsx(t.Card,{className:"mb-3",children:e.jsxs(t.CardContent,{className:"pt-6",children:[e.jsx("div",{className:"font-semibold text-sm text-foreground mb-1",children:"Instructions"}),e.jsx("div",{className:"text-muted-foreground text-sm",children:typeof r=="string"?e.jsx("span",{children:r}):r})]})}),d&&e.jsx(t.Alert,{variant:"success",className:"mb-3",children:e.jsxs(t.AlertDescription,{children:[e.jsxs("div",{className:"font-semibold text-sm mb-1",children:["Grade: ",d.score,c!=null?` / ${c}`:""]}),d.feedback&&e.jsx("div",{children:d.feedback})]})}),h&&e.jsxs(e.Fragment,{children:[a.length>1?e.jsxs(t.Tabs,{value:g,onValueChange:v=>S(v),children:[e.jsxs(t.TabsList,{children:[a.includes("text")&&e.jsx(t.TabsTrigger,{value:"text",children:"Text"}),a.includes("file")&&e.jsx(t.TabsTrigger,{value:"file",children:"File Upload"}),a.includes("url")&&e.jsx(t.TabsTrigger,{value:"url",children:"URL"})]}),a.includes("text")&&e.jsx(t.TabsContent,{value:"text",children:e.jsx(t.Textarea,{className:"min-h-45",placeholder:"Type your submission...",value:N,onChange:v=>T(v.target.value)})}),a.includes("file")&&e.jsx(t.TabsContent,{value:"file",children:e.jsx(t.FileUploadZone,{files:j,onFilesAdded:v=>k(U=>[...U,...v]),onFileRemove:v=>k(U=>U.filter((y,A)=>A!==v)),accept:i==null?void 0:i.acceptedTypes,maxFiles:i==null?void 0:i.maxFiles,maxSizeMB:i==null?void 0:i.maxSizeMB})}),a.includes("url")&&e.jsx(t.TabsContent,{value:"url",children:e.jsx(t.Input,{placeholder:"https://...",value:s,onChange:v=>o(v.target.value)})})]}):e.jsxs(e.Fragment,{children:[a.includes("text")&&e.jsx(t.Textarea,{className:"min-h-45 mb-2",placeholder:"Type your submission...",value:N,onChange:v=>T(v.target.value)}),a.includes("file")&&e.jsx("div",{className:"mb-2",children:e.jsx(t.FileUploadZone,{files:j,onFilesAdded:v=>k(U=>[...U,...v]),onFileRemove:v=>k(U=>U.filter((y,A)=>A!==v)),accept:i==null?void 0:i.acceptedTypes,maxFiles:i==null?void 0:i.maxFiles,maxSizeMB:i==null?void 0:i.maxSizeMB})}),a.includes("url")&&e.jsx(t.Input,{className:"mb-2",placeholder:"https://...",value:s,onChange:v=>o(v.target.value)})]}),e.jsx(t.Separator,{className:"my-2"}),e.jsxs("div",{className:"flex gap-1 justify-end",children:[C&&e.jsxs(t.Button,{variant:"outline",onClick:()=>C(x()),disabled:b,children:[e.jsx(M.Save,{size:16}),"Save Draft"]}),e.jsxs(t.Button,{onClick:()=>w(x()),disabled:b,children:[e.jsx(M.Send,{size:16}),b?"Submitting...":"Submit"]})]})]})]})}function E({label:n,field:r,sortField:l,sortDir:c,onSort:f,textAlign:a}){const m=l===r;return e.jsx(t.TableHead,{className:t.cn("cursor-pointer select-none hover:bg-muted",a==="right"&&"text-right"),onClick:()=>f(r),children:e.jsxs("div",{className:t.cn("flex items-center gap-1",a==="right"&&"justify-end"),children:[e.jsx("span",{className:t.cn(m?"text-foreground":"text-muted-foreground"),children:n}),m&&(c==="asc"?e.jsx(M.ArrowUp,{size:14}):e.jsx(M.ArrowDown,{size:14}))]})})}function he({items:n,categories:r,overallGrade:l,showWeights:c=!0,showCategoryTotals:f=!0,onItemClick:a,readOnly:m=!1,className:i,style:w}){const[C,d]=p.useState("dueDate"),[b,D]=p.useState("asc");function u(j){C===j?D(k=>k==="asc"?"desc":"asc"):(d(j),D("asc"))}const z=p.useMemo(()=>{const j=[...n];return j.sort((k,s)=>{let o=0;switch(C){case"name":o=k.name.localeCompare(s.name);break;case"score":o=(k.score??-1)-(s.score??-1);break;case"dueDate":o=(k.dueDate??"").localeCompare(s.dueDate??"");break;case"status":o=k.status.localeCompare(s.status);break}return b==="asc"?o:-o}),j},[n,C,b]),N=p.useMemo(()=>{if(!r||r.length===0)return[{category:null,items:z}];const j=r.map(s=>({category:s,items:z.filter(o=>o.categoryUid===s.uid)})),k=z.filter(s=>!s.categoryUid);return k.length>0&&j.push({category:null,items:k}),j},[z,r]),T=c?5:4;return e.jsxs("div",{className:i,style:w,children:[l&&e.jsx(t.Card,{className:"mb-3",children:e.jsx(t.CardContent,{className:"pt-6",children:e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx(t.GradeIndicator,{percentage:l.percentage,letterGrade:l.letterGrade,size:"large",passingThreshold:60}),e.jsxs("div",{children:[e.jsx("div",{className:"text-lg font-semibold text-foreground",children:"Overall Grade"}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:[l.pointsEarned," / ",l.pointsPossible," points"]})]})]})})}),e.jsx(t.Card,{children:e.jsxs(t.Table,{children:[e.jsx(t.TableHeader,{children:e.jsxs(t.TableRow,{children:[e.jsx(E,{label:"Assignment",field:"name",sortField:C,sortDir:b,onSort:u}),e.jsx(E,{label:"Status",field:"status",sortField:C,sortDir:b,onSort:u}),e.jsx(E,{label:"Due Date",field:"dueDate",sortField:C,sortDir:b,onSort:u}),e.jsx(E,{label:"Score",field:"score",sortField:C,sortDir:b,onSort:u,textAlign:"right"}),c&&e.jsx(t.TableHead,{className:"text-right text-muted-foreground",children:"Weight"})]})}),e.jsx(t.TableBody,{children:N.map((j,k)=>e.jsxs(p.Fragment,{children:[j.category&&f&&e.jsx(t.TableRow,{className:"bg-muted hover:bg-muted",children:e.jsx(t.TableCell,{colSpan:T,children:e.jsxs("span",{className:"font-semibold text-sm text-foreground",children:[j.category.name,j.category.weight!=null&&` (${j.category.weight}%)`]})})}),j.items.map(s=>e.jsxs(t.TableRow,{className:t.cn(a&&!m&&"cursor-pointer"),onClick:()=>a&&!m?a(s):void 0,children:[e.jsx(t.TableCell,{children:s.name}),e.jsx(t.TableCell,{children:e.jsx(t.StatusBadge,{status:s.status,size:"small"})}),e.jsx(t.TableCell,{children:s.dueDate?e.jsx(t.DueDateDisplay,{dueDate:s.dueDate,submittedDate:s.submittedDate,size:"small"}):"—"}),e.jsx(t.TableCell,{className:"text-right",children:s.score!=null?e.jsxs("span",{className:"text-sm font-semibold text-foreground",children:[s.score," / ",s.maxScore]}):s.status==="excused"?e.jsx("span",{className:"text-sm text-muted-foreground",children:"Excused"}):e.jsx("span",{className:"text-sm text-muted-foreground",children:"—"})}),c&&e.jsx(t.TableCell,{className:"text-right",children:s.weight!=null?`${s.weight}%`:"—"})]},s.uid))]},k))})]})})]})}const fe={lesson_completed:M.BookOpen,quiz_passed:M.CheckCircle,assignment_submitted:M.Send,badge_earned:M.Award};function je({overallProgress:n,totalTimeSpent:r,modules:l,recentActivity:c,streak:f,achievements:a,recentActivityLimit:m=5,onModuleClick:i,className:w,style:C}){return e.jsxs("div",{className:w,style:C,children:[e.jsxs("div",{className:"grid grid-cols-[repeat(auto-fit,minmax(160px,1fr))] gap-2 mb-3",children:[e.jsx(t.Card,{className:"p-2 flex justify-center",children:e.jsx(t.ProgressRing,{value:n,size:100})}),e.jsx(t.StatCard,{icon:e.jsx(M.Clock,{size:24}),label:"Time Spent",value:t.formatDuration(r)}),f&&e.jsx(t.StatCard,{icon:e.jsx(M.Flame,{size:24}),label:"Current Streak",value:`${f.currentDays} days`,subtitle:`Longest: ${f.longestDays} days`}),e.jsx(t.StatCard,{icon:e.jsx(M.BookOpen,{size:24}),label:"Modules",value:`${l.filter(d=>d.completedItems===d.totalItems).length} / ${l.length}`,subtitle:"completed"})]}),e.jsx("p",{className:"text-lg font-semibold mb-2 text-foreground",children:"Module Progress"}),e.jsx("div",{className:"flex flex-col gap-1.5 mb-3",children:l.map(d=>{const b=d.totalItems>0?d.completedItems/d.totalItems*100:0;return e.jsxs(t.Card,{className:t.cn("p-2 transition-colors",i&&"cursor-pointer hover:border-primary"),onClick:()=>i==null?void 0:i(d.uid),children:[e.jsxs("div",{className:"flex justify-between items-center mb-0.5",children:[e.jsx("span",{className:"font-semibold text-sm text-foreground",children:d.name}),e.jsxs("span",{className:"text-xs text-muted-foreground",children:[d.completedItems," / ",d.totalItems]})]}),e.jsx(t.Progress,{value:b,size:"sm"})]},d.uid)})}),c&&c.length>0&&e.jsxs(e.Fragment,{children:[e.jsx("p",{className:"text-lg font-semibold mb-2 text-foreground",children:"Recent Activity"}),e.jsx("div",{className:"flex flex-col gap-1 mb-3",children:c.slice(0,m).map(d=>{const b=fe[d.type]??M.CheckCircle;return e.jsxs("div",{className:"flex gap-1.5 items-center",children:[e.jsx(b,{size:16}),e.jsx("span",{className:"flex-1 text-sm text-foreground",children:d.description}),e.jsx("span",{className:"text-xs text-muted-foreground",children:new Date(d.timestamp).toLocaleDateString()})]},d.uid)})})]}),a&&a.length>0&&e.jsxs(e.Fragment,{children:[e.jsx("p",{className:"text-lg font-semibold mb-2 text-foreground",children:"Achievements"}),e.jsx("div",{className:"grid grid-cols-[repeat(auto-fill,minmax(140px,1fr))] gap-2",children:a.map(d=>e.jsxs(t.Card,{className:"p-2 text-center",children:[d.iconUrl?e.jsx("img",{src:d.iconUrl,alt:d.name,className:"w-12 h-12 mb-1 mx-auto"}):e.jsx(M.Trophy,{size:32,className:"mx-auto mb-2 text-warning"}),e.jsx("p",{className:"font-semibold text-sm text-foreground",children:d.name}),e.jsx("p",{className:"text-xs text-muted-foreground",children:d.description})]},d.uid))})]})]})}const pe={classic:"border-[3px] border-double border-warning bg-linear-to-br from-[#fffbe6] to-[#fff8e1]",modern:"border border-primary bg-linear-to-br from-[#fff5f5] to-[#fee2e2]",minimal:"border border-border"};function ge({recipientName:n,courseTitle:r,completionDate:l,organizationName:c,organizationLogo:f,signatory:a,certificateId:m,variant:i="classic",showActions:w=!0,onPrint:C,onDownload:d,className:b,style:D}){const u=(()=>{try{return new Date(l).toLocaleDateString("en-US",{year:"numeric",month:"long",day:"numeric"})}catch{return l}})();function z(){C?C():window.print()}return e.jsxs("div",{className:b,style:D,children:[e.jsxs("div",{className:t.cn("p-3 sm:p-5 md:p-6 text-center max-w-200 mx-auto rounded-md",pe[i]),children:[f?e.jsx("img",{src:f,alt:c,className:"h-15 mb-2 mx-auto block"}):e.jsx(M.Award,{size:48,className:t.cn("mx-auto mb-4",i==="classic"&&"text-warning")}),e.jsx("p",{className:"uppercase tracking-[3px] text-sm text-foreground/70",children:"Certificate of Completion"}),e.jsx(t.Separator,{className:"my-2 mx-auto max-w-50"}),e.jsx("p",{className:"text-sm text-foreground mb-1",children:"This is to certify that"}),e.jsx("p",{className:t.cn("text-2xl font-bold mb-2 text-foreground",i==="classic"&&"font-serif"),children:n}),e.jsx("p",{className:"text-sm text-foreground mb-1",children:"has successfully completed"}),e.jsx("p",{className:"text-xl font-bold mb-2 text-primary",children:r}),e.jsxs("p",{className:"text-sm text-foreground mb-3",children:["Issued by ",c," on ",u]}),a&&e.jsxs("div",{className:"mt-4 mb-2",children:[e.jsx(t.Separator,{className:"my-2 mx-auto max-w-50"}),e.jsx("p",{className:"font-semibold text-sm text-foreground",children:a.name}),e.jsx("p",{className:"text-xs text-muted-foreground",children:a.title})]}),m&&e.jsxs("span",{className:"block text-xs text-muted-foreground mt-2",children:["Certificate ID: ",m]})]}),w&&e.jsxs("div",{className:"flex justify-center gap-2 mt-3",children:[e.jsxs(t.Button,{variant:"outline",onClick:z,children:[e.jsx(M.Printer,{size:16})," Print"]}),d&&e.jsxs(t.Button,{variant:"outline",onClick:d,children:[e.jsx(M.Download,{size:16})," Download"]})]})]})}exports.AnnouncementFeed=ue;exports.AssessmentReview=te;exports.AssignmentSubmission=me;exports.CertificateViewer=ge;exports.CourseOutline=se;exports.DiscussionThread=xe;exports.ExamSession=le;exports.FlashcardStudySession=O;exports.GradebookTable=he;exports.LecturePlayer=X;exports.LessonPage=de;exports.PracticeQuiz=ae;exports.ProgressDashboard=je;exports.QuizSession=W;exports.ResourceLibrary=ce;exports.ScrollableQuiz=ne;exports.SurveyForm=ie;