@hydralms/components 0.1.2 → 0.2.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.
- package/dist/ForumBoard-CHXU3mjC.js +2207 -0
- package/dist/ForumBoard-d1w5-r6n.cjs +1 -0
- package/dist/assessment-toolbar/assessment-toolbar.d.ts +1 -1
- package/dist/assessment-toolbar/index.d.ts +5 -1
- package/dist/assessment-toolbar/question-header-bar.d.ts +2 -0
- package/dist/assessment-toolbar/question-materials-drawer.d.ts +2 -0
- package/dist/assessment-toolbar/question-navigator.d.ts +1 -1
- package/dist/assessment-toolbar/types.d.ts +52 -4
- package/dist/assessment-toolbar/use-countdown.d.ts +43 -0
- package/dist/common/index.d.ts +2 -1
- package/dist/common/stepper.d.ts +6 -0
- package/dist/common/types.d.ts +37 -0
- package/dist/components.css +1 -1
- package/dist/content/attachment-list.d.ts +6 -0
- package/dist/content/content-block.d.ts +1 -1
- package/dist/content/index.d.ts +2 -1
- package/dist/content/types.d.ts +39 -0
- package/dist/curriculum/curriculum-item.d.ts +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +551 -312
- package/dist/modules/AssignmentModule/AssignmentModule.d.ts +8 -0
- package/dist/modules/AssignmentModule/types.d.ts +65 -0
- package/dist/modules/CertificateModule/CertificateModule.d.ts +9 -0
- package/dist/modules/CertificateModule/types.d.ts +49 -0
- package/dist/modules/DiscussionModule/DiscussionModule.d.ts +8 -0
- package/dist/modules/DiscussionModule/types.d.ts +47 -0
- package/dist/modules/ExamModule/ExamModule.d.ts +8 -0
- package/dist/modules/ExamModule/types.d.ts +64 -0
- package/dist/modules/GradeCenterModule/GradeCenterModule.d.ts +9 -0
- package/dist/modules/GradeCenterModule/types.d.ts +54 -0
- package/dist/modules/QuizModule/QuizModule.d.ts +1 -1
- package/dist/modules/QuizModule/types.d.ts +6 -1
- package/dist/modules/SurveyModule/SurveyModule.d.ts +7 -0
- package/dist/modules/SurveyModule/types.d.ts +49 -0
- package/dist/modules/index.d.ts +12 -0
- package/dist/modules.cjs +1 -0
- package/dist/modules.js +1422 -0
- package/dist/progress/achievement-badge.d.ts +6 -0
- package/dist/progress/activity-timeline.d.ts +6 -0
- package/dist/progress/index.d.ts +4 -1
- package/dist/progress/stat-card.d.ts +1 -1
- package/dist/progress/streak-badge.d.ts +6 -0
- package/dist/progress/types.d.ts +97 -0
- package/dist/questions/essay.d.ts +1 -1
- package/dist/questions/hotspot.d.ts +21 -0
- package/dist/questions/index.d.ts +9 -1
- package/dist/questions/inline-choice.d.ts +21 -0
- package/dist/questions/matching.d.ts +22 -0
- package/dist/questions/numeric.d.ts +11 -0
- package/dist/questions/ordering.d.ts +12 -0
- package/dist/questions/scenario.d.ts +23 -0
- package/dist/questions/scoring.d.ts +22 -0
- package/dist/questions/spreadsheet.d.ts +29 -0
- package/dist/questions/types.d.ts +106 -1
- package/dist/questions/use-drag-reorder.d.ts +17 -0
- package/dist/sections/CertificateViewer/types.d.ts +7 -5
- package/dist/sections/ExamSession/ExamSession.d.ts +1 -1
- package/dist/sections/ExamSession/types.d.ts +6 -1
- package/dist/sections/ForumBoard/ForumBoard.d.ts +8 -0
- package/dist/sections/ForumBoard/types.d.ts +64 -0
- package/dist/sections/QuizSession/QuizSession.d.ts +1 -1
- package/dist/sections/QuizSession/types.d.ts +6 -1
- package/dist/sections/RequirementsChecklist/RequirementsChecklist.d.ts +8 -0
- package/dist/sections/RequirementsChecklist/types.d.ts +37 -0
- package/dist/sections/RubricView/RubricView.d.ts +9 -0
- package/dist/sections/RubricView/types.d.ts +50 -0
- package/dist/sections/index.d.ts +7 -1
- package/dist/sections.cjs +1 -1
- package/dist/sections.js +250 -1715
- package/dist/social/post-card.d.ts +1 -1
- package/dist/tabs-DRM2Iq_J.cjs +172 -0
- package/dist/tabs-Wf3h_Cx3.js +21580 -0
- package/dist/ui/alert.d.ts +1 -1
- package/dist/ui/badge.d.ts +1 -1
- package/dist/ui/button.d.ts +1 -1
- package/dist/ui/drawer.d.ts +84 -0
- package/dist/ui/index.d.ts +3 -0
- package/dist/ui/progress.d.ts +1 -1
- package/dist/ui/rich-text-editor.d.ts +30 -0
- package/dist/ui/rich-text-toolbar.d.ts +8 -0
- package/dist/utils/array-utils.d.ts +4 -0
- package/dist/utils/flatten-leaves.d.ts +6 -0
- package/dist/utils/format-file-size.d.ts +1 -0
- package/dist/utils/format-timestamp.d.ts +1 -0
- package/dist/utils/is-empty-html.d.ts +5 -0
- package/dist/utils/shuffle.d.ts +1 -0
- package/dist/utils/string-utils.d.ts +12 -0
- package/dist/video/video-bookmark.d.ts +1 -1
- package/dist/video/video-playlist-item.d.ts +1 -1
- package/package.json +141 -3
- package/src/assessment-toolbar/assessment-toolbar.tsx +54 -49
- package/src/assessment-toolbar/index.ts +6 -0
- package/src/assessment-toolbar/question-header-bar.tsx +61 -0
- package/src/assessment-toolbar/question-materials-drawer.tsx +55 -0
- package/src/assessment-toolbar/question-navigator.tsx +3 -31
- package/src/assessment-toolbar/timer-display.tsx +2 -2
- package/src/assessment-toolbar/types.ts +54 -4
- package/src/assessment-toolbar/use-countdown.ts +153 -0
- package/src/common/index.ts +3 -0
- package/src/common/search-input.tsx +7 -6
- package/src/common/stepper.tsx +100 -0
- package/src/common/types.ts +39 -0
- package/src/content/attachment-list.tsx +90 -0
- package/src/content/content-block.tsx +4 -2
- package/src/content/file-upload-zone.tsx +1 -6
- package/src/content/index.ts +3 -0
- package/src/content/types.ts +41 -0
- package/src/curriculum/curriculum-item.tsx +7 -3
- package/src/feedback/feedback-banner.tsx +12 -14
- package/src/flashcards/flashcard-deck.tsx +1 -9
- package/src/flashcards/flashcard.tsx +1 -1
- package/src/modules/AssignmentModule/AssignmentModule.tsx +305 -0
- package/src/modules/AssignmentModule/types.ts +73 -0
- package/src/modules/CertificateModule/CertificateModule.tsx +161 -0
- package/src/modules/CertificateModule/types.ts +47 -0
- package/src/modules/CoursePlayer/CoursePlayer.tsx +44 -48
- package/src/modules/DiscussionModule/DiscussionModule.tsx +110 -0
- package/src/modules/DiscussionModule/types.ts +54 -0
- package/src/modules/ExamModule/ExamModule.tsx +285 -0
- package/src/modules/ExamModule/types.ts +66 -0
- package/src/modules/FlashcardLab/FlashcardLab.tsx +29 -16
- package/src/modules/GradeCenterModule/GradeCenterModule.tsx +169 -0
- package/src/modules/GradeCenterModule/types.ts +63 -0
- package/src/modules/QuizModule/QuizModule.tsx +88 -88
- package/src/modules/QuizModule/types.ts +6 -1
- package/src/modules/SurveyModule/SurveyModule.tsx +180 -0
- package/src/modules/SurveyModule/types.ts +51 -0
- package/src/modules/index.ts +24 -0
- package/src/progress/achievement-badge.tsx +52 -0
- package/src/progress/activity-timeline.tsx +84 -0
- package/src/progress/index.ts +7 -0
- package/src/progress/stat-card.tsx +30 -18
- package/src/progress/streak-badge.tsx +35 -0
- package/src/progress/types.ts +101 -0
- package/src/questions/choice.tsx +7 -9
- package/src/questions/essay.tsx +23 -25
- package/src/questions/fill-in-the-blank.tsx +13 -16
- package/src/questions/hotspot.tsx +154 -0
- package/src/questions/index.ts +16 -0
- package/src/questions/inline-choice.tsx +151 -0
- package/src/questions/matching.tsx +228 -0
- package/src/questions/multiple-choice.tsx +7 -9
- package/src/questions/numeric.tsx +102 -0
- package/src/questions/ordering.tsx +159 -0
- package/src/questions/question-renderer.tsx +21 -0
- package/src/questions/scenario.tsx +140 -0
- package/src/questions/scoring.ts +201 -0
- package/src/questions/spreadsheet.tsx +259 -0
- package/src/questions/true-false.tsx +7 -9
- package/src/questions/types.ts +123 -1
- package/src/questions/use-drag-reorder.ts +80 -0
- package/src/sections/AnnouncementFeed/AnnouncementFeed.tsx +2 -15
- package/src/sections/AssessmentReview/AssessmentReview.tsx +13 -2
- package/src/sections/AssignmentSubmission/AssignmentSubmission.tsx +7 -5
- package/src/sections/CertificateViewer/CertificateViewer.tsx +409 -56
- package/src/sections/CertificateViewer/types.ts +13 -5
- package/src/sections/CourseOutline/CourseOutline.tsx +4 -14
- package/src/sections/DiscussionThread/DiscussionThread.tsx +13 -10
- package/src/sections/ExamSession/ExamSession.tsx +44 -7
- package/src/sections/ExamSession/types.ts +6 -1
- package/src/sections/ForumBoard/ForumBoard.tsx +284 -0
- package/src/sections/ForumBoard/types.ts +67 -0
- package/src/sections/GradebookTable/GradebookTable.tsx +1 -1
- package/src/sections/LecturePlayer/LecturePlayer.tsx +1 -1
- package/src/sections/LessonPage/LessonPage.tsx +5 -9
- package/src/sections/PracticeQuiz/PracticeQuiz.tsx +15 -26
- package/src/sections/ProgressDashboard/ProgressDashboard.tsx +65 -65
- package/src/sections/QuizSession/QuizSession.tsx +67 -8
- package/src/sections/QuizSession/types.ts +6 -1
- package/src/sections/RequirementsChecklist/RequirementsChecklist.tsx +107 -0
- package/src/sections/RequirementsChecklist/types.ts +38 -0
- package/src/sections/ResourceLibrary/ResourceLibrary.tsx +4 -9
- package/src/sections/RubricView/RubricView.tsx +138 -0
- package/src/sections/RubricView/types.ts +52 -0
- package/src/sections/ScrollableQuiz/ScrollableQuiz.tsx +23 -9
- package/src/sections/SurveyForm/SurveyForm.tsx +8 -5
- package/src/sections/index.ts +20 -1
- package/src/social/post-card.tsx +8 -19
- package/src/social/user-avatar.tsx +1 -0
- package/src/styles/globals.css +13 -0
- package/src/ui/drawer.tsx +600 -0
- package/src/ui/index.ts +19 -0
- package/src/ui/rich-text-editor.tsx +109 -0
- package/src/ui/rich-text-toolbar.tsx +156 -0
- package/src/utils/array-utils.ts +17 -0
- package/src/utils/flatten-leaves.ts +17 -0
- package/src/utils/format-file-size.ts +5 -0
- package/src/utils/format-timestamp.ts +13 -0
- package/src/utils/is-empty-html.ts +7 -0
- package/src/utils/shuffle.ts +8 -0
- package/src/utils/string-utils.ts +30 -0
- package/src/video/video-bookmark.tsx +4 -3
- package/src/video/video-chapter-list.tsx +9 -4
- package/src/video/video-player.tsx +11 -4
- package/src/video/video-playlist-item.tsx +8 -3
- package/src/video/video-thumbnail-card.tsx +4 -0
- package/src/video/video-transcript.tsx +8 -5
- package/dist/table-BrS5cDQu.js +0 -2510
- package/dist/table-D6AkBBEo.cjs +0 -1
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { AssignmentModuleProps } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* AssignmentModule — a complete assignment experience with instructions,
|
|
4
|
+
* submission work area, and confirmation/grade review.
|
|
5
|
+
*
|
|
6
|
+
* Steps: Instructions → Work (AssignmentSubmission) → Confirmation.
|
|
7
|
+
*/
|
|
8
|
+
export declare function AssignmentModule({ title, instructions, dueDate, maxScore, submissionTypes, fileConstraints, rubric, existingSubmission, status, grade, onSubmit, onSaveDraft, className, style, }: AssignmentModuleProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { SubmissionData } from '../../sections/AssignmentSubmission/types';
|
|
3
|
+
import { RubricCriterion } from '../../sections/RubricView/types';
|
|
4
|
+
/**
|
|
5
|
+
* AssignmentModule — a complete assignment experience with instructions,
|
|
6
|
+
* submission, and confirmation/grade review.
|
|
7
|
+
*
|
|
8
|
+
* Steps: Instructions → Work (AssignmentSubmission) → Confirmation.
|
|
9
|
+
* Optionally shows a grading rubric in both the instructions and
|
|
10
|
+
* graded confirmation views.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* <AssignmentModule
|
|
14
|
+
* title="Week 3 Essay"
|
|
15
|
+
* instructions={<p>Write a 500-word essay on React hooks.</p>}
|
|
16
|
+
* submissionTypes={["text", "file"]}
|
|
17
|
+
* rubric={rubricCriteria}
|
|
18
|
+
* onSubmit={(submission) => submitAssignment(submission)}
|
|
19
|
+
* />
|
|
20
|
+
*/
|
|
21
|
+
export interface AssignmentModuleProps {
|
|
22
|
+
/** Assignment title */
|
|
23
|
+
title: string;
|
|
24
|
+
/** Assignment instructions (rich content) */
|
|
25
|
+
instructions: ReactNode;
|
|
26
|
+
/** Due date as ISO string */
|
|
27
|
+
dueDate?: string;
|
|
28
|
+
/** Maximum score points */
|
|
29
|
+
maxScore?: number;
|
|
30
|
+
/** Allowed submission types */
|
|
31
|
+
submissionTypes: ("text" | "file" | "url")[];
|
|
32
|
+
/** File upload constraints */
|
|
33
|
+
fileConstraints?: {
|
|
34
|
+
maxFiles?: number;
|
|
35
|
+
maxSizeMB?: number;
|
|
36
|
+
acceptedTypes?: string;
|
|
37
|
+
};
|
|
38
|
+
/** Rubric criteria for grading (shown in instructions and graded confirmation) */
|
|
39
|
+
rubric?: RubricCriterion[];
|
|
40
|
+
/** Existing submission for editing/viewing */
|
|
41
|
+
existingSubmission?: SubmissionData;
|
|
42
|
+
/** Current submission status. @default "not_started" */
|
|
43
|
+
status?: "not_started" | "draft" | "submitted" | "late" | "graded" | "resubmit";
|
|
44
|
+
/** Grade data when graded */
|
|
45
|
+
grade?: {
|
|
46
|
+
score: number;
|
|
47
|
+
feedback?: ReactNode;
|
|
48
|
+
/** Selected rubric level UIDs per criterion UID */
|
|
49
|
+
rubricLevels?: Record<string, string>;
|
|
50
|
+
};
|
|
51
|
+
/** Called on final submission */
|
|
52
|
+
onSubmit?: (submission: SubmissionData) => void;
|
|
53
|
+
/** Called on draft save */
|
|
54
|
+
onSaveDraft?: (submission: SubmissionData) => void;
|
|
55
|
+
/** CSS class name for the root element */
|
|
56
|
+
className?: string;
|
|
57
|
+
/** Inline styles for the root element */
|
|
58
|
+
style?: React.CSSProperties;
|
|
59
|
+
}
|
|
60
|
+
export interface AssignmentModuleResult {
|
|
61
|
+
/** The submitted data */
|
|
62
|
+
submission: SubmissionData;
|
|
63
|
+
/** Status after submission */
|
|
64
|
+
status: string;
|
|
65
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { CertificateModuleProps } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* CertificateModule — a certificate-earning flow with requirements tracking
|
|
4
|
+
* and certificate display.
|
|
5
|
+
*
|
|
6
|
+
* Steps: Requirements (checklist + progress) → Certificate (CertificateViewer).
|
|
7
|
+
* The certificate step is only accessible when all requirements are completed.
|
|
8
|
+
*/
|
|
9
|
+
export declare function CertificateModule({ courseTitle, recipientName, organizationName, organizationLogo, signatory, completionDate, certificateVariant, requirements, overallProgress, onRequirementClick, onCertificateEarned, className, style, }: CertificateModuleProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Requirement } from '../../sections/RequirementsChecklist/types';
|
|
2
|
+
import { CertificateVariant } from '../../sections/CertificateViewer/types';
|
|
3
|
+
/**
|
|
4
|
+
* CertificateModule — a certificate-earning flow with requirements tracking
|
|
5
|
+
* and certificate display.
|
|
6
|
+
*
|
|
7
|
+
* Steps: Requirements (checklist + progress) → Certificate (CertificateViewer).
|
|
8
|
+
* The certificate step is only accessible when all requirements are met.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* <CertificateModule
|
|
12
|
+
* courseTitle="React Fundamentals"
|
|
13
|
+
* recipientName="Jane Smith"
|
|
14
|
+
* organizationName="HydraLMS Academy"
|
|
15
|
+
* requirements={requirements}
|
|
16
|
+
* overallProgress={100}
|
|
17
|
+
* />
|
|
18
|
+
*/
|
|
19
|
+
export interface CertificateModuleProps {
|
|
20
|
+
/** Course or program title */
|
|
21
|
+
courseTitle: string;
|
|
22
|
+
/** Recipient's full name */
|
|
23
|
+
recipientName: string;
|
|
24
|
+
/** Issuing organization name */
|
|
25
|
+
organizationName: string;
|
|
26
|
+
/** Organization logo URL */
|
|
27
|
+
organizationLogo?: string;
|
|
28
|
+
/** Signatory information */
|
|
29
|
+
signatory?: {
|
|
30
|
+
name: string;
|
|
31
|
+
title: string;
|
|
32
|
+
};
|
|
33
|
+
/** Completion date (used on the certificate) */
|
|
34
|
+
completionDate?: string;
|
|
35
|
+
/** Certificate visual variant. @default "modern" */
|
|
36
|
+
certificateVariant?: CertificateVariant;
|
|
37
|
+
/** Completion requirements */
|
|
38
|
+
requirements: Requirement[];
|
|
39
|
+
/** Overall course progress (0-100) */
|
|
40
|
+
overallProgress: number;
|
|
41
|
+
/** Called when a requirement item is clicked */
|
|
42
|
+
onRequirementClick?: (uid: string) => void;
|
|
43
|
+
/** Called when the certificate screen is first displayed */
|
|
44
|
+
onCertificateEarned?: () => void;
|
|
45
|
+
/** CSS class name for the root element */
|
|
46
|
+
className?: string;
|
|
47
|
+
/** Inline styles for the root element */
|
|
48
|
+
style?: React.CSSProperties;
|
|
49
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { DiscussionModuleProps } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* DiscussionModule — a master-detail discussion forum with topic list and thread view.
|
|
4
|
+
*
|
|
5
|
+
* Panel-based layout: ForumBoard (topic listing) ↔ DiscussionThread (thread detail).
|
|
6
|
+
* Clicking a topic drills into the thread; a back button returns to the board.
|
|
7
|
+
*/
|
|
8
|
+
export declare function DiscussionModule({ forumTitle, topics, currentUser, threads, onCreateTopic, onReply, onToggleLike, onMarkAnswer, onTopicOpen, readOnly, className, style, }: DiscussionModuleProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { DiscussionUser, DiscussionPost } from '../../sections/DiscussionThread/types';
|
|
2
|
+
import { ForumTopic } from '../../sections/ForumBoard/types';
|
|
3
|
+
/**
|
|
4
|
+
* DiscussionModule — a master-detail discussion forum with topic list and thread view.
|
|
5
|
+
*
|
|
6
|
+
* Panel-based layout: ForumBoard (topic list) ↔ DiscussionThread (thread detail).
|
|
7
|
+
* Clicking a topic drills into the thread; a back button returns to the board.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* <DiscussionModule
|
|
11
|
+
* forumTitle="Class Discussion"
|
|
12
|
+
* topics={topics}
|
|
13
|
+
* threads={threadData}
|
|
14
|
+
* currentUser={user}
|
|
15
|
+
* onCreateTopic={(title, content) => createTopic(title, content)}
|
|
16
|
+
* onReply={(topicUid, parentUid, content) => postReply(topicUid, parentUid, content)}
|
|
17
|
+
* />
|
|
18
|
+
*/
|
|
19
|
+
export interface DiscussionModuleProps {
|
|
20
|
+
/** Forum title */
|
|
21
|
+
forumTitle?: string;
|
|
22
|
+
/** List of discussion topics */
|
|
23
|
+
topics: ForumTopic[];
|
|
24
|
+
/** The currently authenticated user */
|
|
25
|
+
currentUser: DiscussionUser;
|
|
26
|
+
/** Thread data keyed by topic UID */
|
|
27
|
+
threads: Record<string, {
|
|
28
|
+
rootPost: DiscussionPost;
|
|
29
|
+
replies: DiscussionPost[];
|
|
30
|
+
}>;
|
|
31
|
+
/** Called when a new topic is created */
|
|
32
|
+
onCreateTopic?: (title: string, content: string) => void;
|
|
33
|
+
/** Called when a reply is posted */
|
|
34
|
+
onReply?: (topicUid: string, parentUid: string, content: string) => void;
|
|
35
|
+
/** Called when a like is toggled */
|
|
36
|
+
onToggleLike?: (topicUid: string, postUid: string) => void;
|
|
37
|
+
/** Called when a post is marked as the answer */
|
|
38
|
+
onMarkAnswer?: (topicUid: string, postUid: string) => void;
|
|
39
|
+
/** Called when a topic is opened (for lazy loading thread data) */
|
|
40
|
+
onTopicOpen?: (topicUid: string) => void;
|
|
41
|
+
/** When true, disables all interactions */
|
|
42
|
+
readOnly?: boolean;
|
|
43
|
+
/** CSS class name for the root element */
|
|
44
|
+
className?: string;
|
|
45
|
+
/** Inline styles for the root element */
|
|
46
|
+
style?: React.CSSProperties;
|
|
47
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ExamModuleProps } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* ExamModule — a complete formal exam experience.
|
|
4
|
+
*
|
|
5
|
+
* Steps: Intro (rules/instructions) → Exam (timed ExamSession) → Results (score + review).
|
|
6
|
+
* Manages an external timer that feeds elapsed time to ExamSession.
|
|
7
|
+
*/
|
|
8
|
+
export declare function ExamModule({ title, description, instructions, questions, timeLimitSeconds, passingScore, allowBackNavigation, autoSubmitOnTimeout, timeWarningThreshold, allowRetake, showReview, onComplete, className, style, }: ExamModuleProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { QuestionData, SessionAnswer } from '../../questions/types';
|
|
3
|
+
/**
|
|
4
|
+
* ExamModule — a formal timed exam experience with intro, exam, and results steps.
|
|
5
|
+
*
|
|
6
|
+
* Wraps ExamSession with an intro screen showing rules/instructions and a
|
|
7
|
+
* results screen with scoring, stats, and optional answer review.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* <ExamModule
|
|
11
|
+
* title="Midterm Exam"
|
|
12
|
+
* instructions={<p>You have 60 minutes. No notes allowed.</p>}
|
|
13
|
+
* questions={questions}
|
|
14
|
+
* timeLimitSeconds={3600}
|
|
15
|
+
* passingScore={70}
|
|
16
|
+
* onComplete={(result) => saveResult(result)}
|
|
17
|
+
* />
|
|
18
|
+
*/
|
|
19
|
+
export interface ExamModuleProps {
|
|
20
|
+
/** Exam title displayed on the intro screen */
|
|
21
|
+
title: string;
|
|
22
|
+
/** Exam description displayed on the intro screen */
|
|
23
|
+
description?: string;
|
|
24
|
+
/** Exam rules/instructions rendered on the intro screen */
|
|
25
|
+
instructions?: ReactNode;
|
|
26
|
+
/** Ordered list of questions */
|
|
27
|
+
questions: QuestionData[];
|
|
28
|
+
/** Time limit in seconds (required for exams) */
|
|
29
|
+
timeLimitSeconds: number;
|
|
30
|
+
/** Passing threshold as a percentage (e.g. 70 means 70%) */
|
|
31
|
+
passingScore?: number;
|
|
32
|
+
/** Whether the user can go back to previous questions. @default true */
|
|
33
|
+
allowBackNavigation?: boolean;
|
|
34
|
+
/** Auto-submit when time runs out. @default true */
|
|
35
|
+
autoSubmitOnTimeout?: boolean;
|
|
36
|
+
/** Seconds remaining at which to show a time warning */
|
|
37
|
+
timeWarningThreshold?: number;
|
|
38
|
+
/** Whether to allow retaking the exam from the results screen. @default false */
|
|
39
|
+
allowRetake?: boolean;
|
|
40
|
+
/** Whether to show correct/incorrect answer highlighting in the review. @default true */
|
|
41
|
+
showReview?: boolean;
|
|
42
|
+
/** Called when the exam is completed (submitted) */
|
|
43
|
+
onComplete?: (result: ExamModuleResult) => void;
|
|
44
|
+
/** CSS class name for the root element */
|
|
45
|
+
className?: string;
|
|
46
|
+
/** Inline styles for the root element */
|
|
47
|
+
style?: React.CSSProperties;
|
|
48
|
+
}
|
|
49
|
+
export interface ExamModuleResult {
|
|
50
|
+
/** The user's submitted answers */
|
|
51
|
+
answers: SessionAnswer[];
|
|
52
|
+
/** Number of correct answers */
|
|
53
|
+
correct: number;
|
|
54
|
+
/** Total number of gradable questions */
|
|
55
|
+
total: number;
|
|
56
|
+
/** Score as a percentage (0-100) */
|
|
57
|
+
percentage: number;
|
|
58
|
+
/** Whether the user passed (only meaningful when passingScore is set) */
|
|
59
|
+
passed: boolean;
|
|
60
|
+
/** Total time taken in seconds */
|
|
61
|
+
timeElapsedSeconds: number;
|
|
62
|
+
/** Whether the submission was triggered by timeout */
|
|
63
|
+
wasAutoSubmitted: boolean;
|
|
64
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { GradeCenterModuleProps } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* GradeCenterModule — a tabbed grade center with gradebook, progress dashboard,
|
|
4
|
+
* and drill-down into individual assessment reviews.
|
|
5
|
+
*
|
|
6
|
+
* Uses a panel-based layout (like CoursePlayer) with tabs for Grades and Progress,
|
|
7
|
+
* and a slide-in detail panel for reviewing individual assessments.
|
|
8
|
+
*/
|
|
9
|
+
export declare function GradeCenterModule({ courseTitle, gradeItems, categories, overallGrade, showWeights, progressData, reviewData, className, style, }: GradeCenterModuleProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { GradeItem, GradeCategory, OverallGrade } from '../../sections/GradebookTable/types';
|
|
2
|
+
import { ModuleProgress, ActivityItem, Achievement } from '../../sections/ProgressDashboard/types';
|
|
3
|
+
import { AssessmentScore } from '../../sections/AssessmentReview/types';
|
|
4
|
+
import { QuestionData, SessionAnswer } from '../../questions/types';
|
|
5
|
+
/**
|
|
6
|
+
* GradeCenterModule — a tabbed grade center with gradebook, progress dashboard,
|
|
7
|
+
* and drill-down into individual assessment reviews.
|
|
8
|
+
*
|
|
9
|
+
* Combines GradebookTable, ProgressDashboard, and AssessmentReview sections
|
|
10
|
+
* in a master-detail layout with tab navigation.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* <GradeCenterModule
|
|
14
|
+
* courseTitle="React Fundamentals"
|
|
15
|
+
* gradeItems={items}
|
|
16
|
+
* overallGrade={overallGrade}
|
|
17
|
+
* progressData={{ overallProgress: 75, totalTimeSpent: 45000, modules: [] }}
|
|
18
|
+
* reviewData={{ quiz1: { questions, sessionAnswers, score } }}
|
|
19
|
+
* />
|
|
20
|
+
*/
|
|
21
|
+
export interface GradeCenterModuleProps {
|
|
22
|
+
/** Course title shown in the header */
|
|
23
|
+
courseTitle?: string;
|
|
24
|
+
/** Grade items (assignments, quizzes, etc.) */
|
|
25
|
+
gradeItems: GradeItem[];
|
|
26
|
+
/** Optional category grouping */
|
|
27
|
+
categories?: GradeCategory[];
|
|
28
|
+
/** Overall course grade summary */
|
|
29
|
+
overallGrade?: OverallGrade;
|
|
30
|
+
/** Whether to show the weight column in the gradebook */
|
|
31
|
+
showWeights?: boolean;
|
|
32
|
+
/** Data for the progress tab — tab is hidden if not provided */
|
|
33
|
+
progressData?: {
|
|
34
|
+
overallProgress: number;
|
|
35
|
+
totalTimeSpent: number;
|
|
36
|
+
modules: ModuleProgress[];
|
|
37
|
+
recentActivity?: ActivityItem[];
|
|
38
|
+
streak?: {
|
|
39
|
+
currentDays: number;
|
|
40
|
+
longestDays: number;
|
|
41
|
+
};
|
|
42
|
+
achievements?: Achievement[];
|
|
43
|
+
};
|
|
44
|
+
/** Review data keyed by grade item UID — enables drill-down on click */
|
|
45
|
+
reviewData?: Record<string, {
|
|
46
|
+
questions: QuestionData[];
|
|
47
|
+
sessionAnswers: SessionAnswer[];
|
|
48
|
+
score?: AssessmentScore;
|
|
49
|
+
}>;
|
|
50
|
+
/** CSS class name for the root element */
|
|
51
|
+
className?: string;
|
|
52
|
+
/** Inline styles for the root element */
|
|
53
|
+
style?: React.CSSProperties;
|
|
54
|
+
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { QuizModuleProps } from './types';
|
|
2
|
-
export declare function QuizModule({ title, description, questions, timeLimitSeconds, passingScore, allowRetake, onComplete, showReview, className, style, }: QuizModuleProps): import("react/jsx-runtime").JSX.Element;
|
|
2
|
+
export declare function QuizModule({ title, description, questions, timeLimitSeconds, passingScore, allowRetake, onComplete, showReview, questionMaterials, className, style, }: QuizModuleProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { QuestionData, SessionAnswer } from '../../questions/types';
|
|
1
|
+
import { QuestionData, QuestionMaterial, SessionAnswer } from '../../questions/types';
|
|
2
2
|
/**
|
|
3
3
|
* QuizModule — a complete multi-step assessment experience.
|
|
4
4
|
*
|
|
@@ -33,6 +33,11 @@ export interface QuizModuleProps {
|
|
|
33
33
|
onComplete?: (result: QuizModuleResult) => void;
|
|
34
34
|
/** Whether to show correct/incorrect answer highlighting in the review. @default true */
|
|
35
35
|
showReview?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Related materials keyed by question UID. When provided, a "Materials"
|
|
38
|
+
* button appears in the question header, opening a drawer with content blocks.
|
|
39
|
+
*/
|
|
40
|
+
questionMaterials?: QuestionMaterial[];
|
|
36
41
|
/** CSS class name for the root element */
|
|
37
42
|
className?: string;
|
|
38
43
|
/** Inline styles for the root element */
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { SurveyModuleProps } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* SurveyModule — a complete survey experience with intro, form, and thank-you steps.
|
|
4
|
+
*
|
|
5
|
+
* Steps: Intro → SurveyForm → Thank You with response stats.
|
|
6
|
+
*/
|
|
7
|
+
export declare function SurveyModule({ title, description, questions, requireAll, showProgress, thankYouTitle, thankYouMessage, onComplete, allowRestart, className, style, }: SurveyModuleProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { SurveyQuestion, SurveyAnswer } from '../../sections/SurveyForm/types';
|
|
2
|
+
/**
|
|
3
|
+
* SurveyModule — a complete survey experience with intro, form, and thank-you steps.
|
|
4
|
+
*
|
|
5
|
+
* Wraps SurveyForm with a welcoming intro screen and a thank-you completion
|
|
6
|
+
* screen showing response stats.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* <SurveyModule
|
|
10
|
+
* title="Course Evaluation"
|
|
11
|
+
* description="Help us improve this course."
|
|
12
|
+
* questions={surveyQuestions}
|
|
13
|
+
* onComplete={(result) => submitSurvey(result)}
|
|
14
|
+
* />
|
|
15
|
+
*/
|
|
16
|
+
export interface SurveyModuleProps {
|
|
17
|
+
/** Survey title displayed on the intro and form screens */
|
|
18
|
+
title: string;
|
|
19
|
+
/** Survey description displayed on the intro screen */
|
|
20
|
+
description?: string;
|
|
21
|
+
/** Survey questions */
|
|
22
|
+
questions: SurveyQuestion[];
|
|
23
|
+
/** Whether all questions must be answered before submit. @default false */
|
|
24
|
+
requireAll?: boolean;
|
|
25
|
+
/** Whether to show a progress indicator in the survey form. @default true */
|
|
26
|
+
showProgress?: boolean;
|
|
27
|
+
/** Custom title for the thank-you screen. @default "Thank You!" */
|
|
28
|
+
thankYouTitle?: string;
|
|
29
|
+
/** Custom message for the thank-you screen */
|
|
30
|
+
thankYouMessage?: string;
|
|
31
|
+
/** Called when the survey is completed */
|
|
32
|
+
onComplete?: (result: SurveyModuleResult) => void;
|
|
33
|
+
/** Allow restarting the survey from the thank-you screen. @default false */
|
|
34
|
+
allowRestart?: boolean;
|
|
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 SurveyModuleResult {
|
|
41
|
+
/** The user's submitted answers */
|
|
42
|
+
answers: SurveyAnswer[];
|
|
43
|
+
/** Total number of questions */
|
|
44
|
+
totalQuestions: number;
|
|
45
|
+
/** Number of questions answered */
|
|
46
|
+
answeredCount: number;
|
|
47
|
+
/** Total time taken in seconds */
|
|
48
|
+
timeElapsedSeconds: number;
|
|
49
|
+
}
|
package/dist/modules/index.d.ts
CHANGED
|
@@ -4,3 +4,15 @@ export { FlashcardLab } from './FlashcardLab/FlashcardLab';
|
|
|
4
4
|
export type { FlashcardLabProps, FlashcardDeckOption, FlashcardLabResult, } from './FlashcardLab/types';
|
|
5
5
|
export { CoursePlayer } from './CoursePlayer/CoursePlayer';
|
|
6
6
|
export type { CoursePlayerProps, CoursePlayerItem } from './CoursePlayer/types';
|
|
7
|
+
export { ExamModule } from './ExamModule/ExamModule';
|
|
8
|
+
export type { ExamModuleProps, ExamModuleResult } from './ExamModule/types';
|
|
9
|
+
export { SurveyModule } from './SurveyModule/SurveyModule';
|
|
10
|
+
export type { SurveyModuleProps, SurveyModuleResult, } from './SurveyModule/types';
|
|
11
|
+
export { GradeCenterModule } from './GradeCenterModule/GradeCenterModule';
|
|
12
|
+
export type { GradeCenterModuleProps } from './GradeCenterModule/types';
|
|
13
|
+
export { AssignmentModule } from './AssignmentModule/AssignmentModule';
|
|
14
|
+
export type { AssignmentModuleProps, AssignmentModuleResult, } from './AssignmentModule/types';
|
|
15
|
+
export { CertificateModule } from './CertificateModule/CertificateModule';
|
|
16
|
+
export type { CertificateModuleProps } from './CertificateModule/types';
|
|
17
|
+
export { DiscussionModule } from './DiscussionModule/DiscussionModule';
|
|
18
|
+
export type { DiscussionModuleProps } from './DiscussionModule/types';
|
package/dist/modules.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),a=require("react"),t=require("lucide-react"),A=require("./ForumBoard-d1w5-r6n.cjs"),s=require("./tabs-DRM2Iq_J.cjs");function Q({title:m,description:v,questions:h,timeLimitSeconds:u,passingScore:w,allowRetake:f=!0,onComplete:i,showReview:o=!0,questionMaterials:j,className:x,style:C}){const[g,l]=a.useState({tag:"intro"}),[N,c]=a.useState(0),p=a.useRef(null),b=a.useRef(null),R=a.useRef(null);a.useEffect(()=>{var n;(n=R.current)==null||n.focus({preventScroll:!0})},[g.tag]),a.useEffect(()=>(g.tag==="quiz"?(p.current=Date.now(),b.current=setInterval(()=>{p.current&&c(Math.floor((Date.now()-p.current)/1e3))},1e3)):b.current&&(clearInterval(b.current),b.current=null),()=>{b.current&&clearInterval(b.current)}),[g.tag]);function k(n){const{correct:B,total:T,percentage:E}=s.scoreAssessment(h,n),M=p.current?Math.floor((Date.now()-p.current)/1e3):N;return{answers:n,correct:B,total:T,percentage:E,passed:w!==void 0?E>=w:!0,timeElapsedSeconds:M}}function S(n){const B=k(n);l({tag:"results",result:B}),i==null||i(B)}function y(){c(0),p.current=null,l({tag:"intro"})}if(g.tag==="intro")return e.jsx("div",{ref:R,tabIndex:-1,className:s.cn("max-w-2xl mx-auto outline-none",x),style:C,children:e.jsx(s.Card,{children:e.jsxs(s.CardContent,{className:"pt-8 pb-8 text-center",children:[e.jsx("div",{className:"mx-auto mb-4 w-14 h-14 rounded-full bg-primary/10 flex items-center justify-center",children:e.jsx(t.Trophy,{className:"size-7 text-primary"})}),e.jsx("h2",{className:"text-2xl font-bold text-foreground mb-2",children:m}),v&&e.jsx("p",{className:"text-muted-foreground mb-6 max-w-md mx-auto",children:v}),e.jsxs("div",{className:"flex flex-wrap justify-center gap-2 mb-8",children:[e.jsxs(s.Badge,{variant:"outline",className:"gap-1.5",children:[e.jsx(t.HelpCircle,{className:"size-3.5"}),h.length," questions"]}),u&&e.jsxs(s.Badge,{variant:"outline",className:"gap-1.5",children:[e.jsx(t.Clock,{className:"size-3.5"}),s.formatDuration(u)," time limit"]}),w!==void 0&&e.jsxs(s.Badge,{variant:"outline",className:"gap-1.5",children:[e.jsx(t.CheckCircle2,{className:"size-3.5"}),w,"% to pass"]})]}),e.jsxs(s.Button,{size:"lg",onClick:()=>l({tag:"quiz"}),children:[e.jsx(t.Play,{className:"size-4 mr-2"}),"Start Quiz"]})]})})});if(g.tag==="quiz")return e.jsx("div",{ref:R,tabIndex:-1,className:s.cn("outline-none",x),style:C,children:e.jsx(A.QuizSession,{questions:h,onSubmit:S,timeElapsedSeconds:N,timeLimitSeconds:u,questionMaterials:j})});const{result:r}=g,d=r.passed;return e.jsxs("div",{ref:R,tabIndex:-1,className:s.cn("max-w-2xl mx-auto outline-none",x),style:C,children:[e.jsx(s.Card,{children:e.jsxs(s.CardContent,{className:"pt-8 pb-8",children:[e.jsxs("div",{className:"text-center mb-8",children:[e.jsx(s.ProgressRing,{value:r.percentage,size:140,strokeWidth:10,color:d?"var(--success)":"var(--destructive)",className:"mx-auto mb-4 text-foreground"}),e.jsx(s.Badge,{variant:d?"success":"destructive",className:"text-sm px-3 py-1 mb-2",children:d?"Passed":"Failed"}),e.jsx("h2",{className:"text-xl font-bold text-foreground",children:m})]}),e.jsxs("div",{className:"grid grid-cols-2 sm:grid-cols-4 gap-3 mb-8",children:[e.jsx(s.StatCard,{icon:e.jsx(t.CheckCircle2,{}),label:"Correct",description:"Questions answered right",value:`${r.correct}/${r.total}`}),e.jsx(s.StatCard,{icon:e.jsx(t.XCircle,{}),label:"Incorrect",description:"Questions to review",value:`${r.total-r.correct}/${r.total}`}),e.jsx(s.StatCard,{icon:e.jsx(t.Trophy,{}),label:"Score",description:"Overall percentage",value:`${r.percentage}%`}),e.jsx(s.StatCard,{icon:e.jsx(t.Clock,{}),label:"Time",description:"Total elapsed",value:s.formatDuration(r.timeElapsedSeconds)})]}),f&&e.jsx("div",{className:"flex justify-center mb-8",children:e.jsxs(s.Button,{variant:"outline",onClick:y,children:[e.jsx(t.RotateCcw,{className:"size-4 mr-2"}),"Retake Quiz"]})})]})}),o&&e.jsxs(e.Fragment,{children:[e.jsx(s.Separator,{className:"my-6"}),e.jsx("h3",{className:"text-lg font-semibold text-foreground mb-4",children:"Question Review"}),e.jsx(A.AssessmentReview,{questions:h,sessionAnswers:r.answers,showCorrectAnswers:!0})]})]})}function $({decks:m,showShuffleToggle:v=!0,defaultShuffled:h=!1,allowMultiSelect:u=!0,onComplete:w,className:f,style:i}){const[o,j]=a.useState({tag:"setup"}),[x,C]=a.useState(new Set),[g,l]=a.useState(h),N=a.useRef(null),c=a.useRef(null);a.useEffect(()=>{var r;(r=c.current)==null||r.focus({preventScroll:!0})},[o.tag]);function p(r){C(d=>{const n=new Set(d);return n.has(r)?n.delete(r):(u||n.clear(),n.add(r)),n})}function b(){const r=m.filter(n=>x.has(n.uid)),d=r.flatMap(n=>n.cards);N.current=Date.now(),j({tag:"study",cards:d,deckUids:r.map(n=>n.uid),shuffled:g})}function R(){if(o.tag!=="study")return;const r=N.current?Math.floor((Date.now()-N.current)/1e3):0,d={totalCards:o.cards.length,decksStudied:o.deckUids.length,deckUids:o.deckUids,wasShuffled:o.shuffled,timeElapsedSeconds:r};j({tag:"completion",result:d}),w==null||w(d)}function k(){if(o.tag!=="completion")return;const d=m.filter(n=>o.result.deckUids.includes(n.uid)).flatMap(n=>n.cards);N.current=Date.now(),j({tag:"study",cards:d,deckUids:o.result.deckUids,shuffled:o.result.wasShuffled})}function S(){C(new Set),l(h),j({tag:"setup"})}if(o.tag==="setup")return e.jsx("div",{ref:c,tabIndex:-1,className:s.cn("max-w-2xl mx-auto outline-none",f),style:i,children:e.jsx(s.Card,{children:e.jsxs(s.CardContent,{className:"pt-8 pb-8",children:[e.jsxs("div",{className:"text-center mb-6",children:[e.jsx("div",{className:"mx-auto mb-4 w-14 h-14 rounded-full bg-primary/10 flex items-center justify-center",children:e.jsx(t.BookOpen,{className:"size-7 text-primary"})}),e.jsx("h2",{className:"text-2xl font-bold text-foreground mb-2",children:"Choose Your Decks"}),e.jsx("p",{className:"text-muted-foreground text-sm",children:u?"Select one or more decks to study":"Select a deck to study"})]}),e.jsx("div",{className:"grid sm:grid-cols-2 lg:grid-cols-3 gap-3 mb-6",children:m.map(r=>{const d=x.has(r.uid);return e.jsx(s.Card,{className:s.cn("cursor-pointer transition-all py-0",d?"border-primary ring-1 ring-primary":"hover:border-muted-foreground/30"),onClick:()=>p(r.uid),children:e.jsxs(s.CardContent,{className:"py-4",children:[e.jsxs("div",{className:"flex items-start justify-between mb-2",children:[e.jsx("h3",{className:"font-semibold text-foreground text-sm",children:r.title}),e.jsxs(s.Badge,{variant:"secondary",className:"text-xs shrink-0",children:[r.cards.length," cards"]})]}),r.description&&e.jsx("p",{className:"text-xs text-muted-foreground line-clamp-2",children:r.description})]})},r.uid)})}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[v&&e.jsxs(s.Button,{variant:g?"secondary":"outline",size:"sm",className:"gap-1.5",onClick:()=>l(r=>!r),children:[e.jsx(t.Shuffle,{className:"size-3.5"}),"Shuffle"]}),x.size>0&&e.jsxs("span",{className:"text-xs text-muted-foreground",children:[m.filter(r=>x.has(r.uid)).reduce((r,d)=>r+d.cards.length,0)," ","cards selected"]})]}),e.jsx(s.Button,{onClick:b,disabled:x.size===0,children:"Start Studying"})]})]})})});if(o.tag==="study"){const r=m.filter(d=>o.deckUids.includes(d.uid)).map(d=>d.title).join(", ");return e.jsx("div",{ref:c,tabIndex:-1,className:s.cn("outline-none",f),style:i,children:e.jsx(A.FlashcardStudySession,{cards:o.cards,title:r,shuffled:o.shuffled,onComplete:R})})}const{result:y}=o;return e.jsx("div",{ref:c,tabIndex:-1,className:s.cn("max-w-2xl mx-auto outline-none",f),style:i,children:e.jsx(s.Card,{children:e.jsxs(s.CardContent,{className:"pt-8 pb-8",children:[e.jsxs("div",{className:"text-center mb-8",children:[e.jsxs("div",{className:"relative mx-auto mb-4",children:[e.jsx(s.ProgressRing,{value:100,size:120,strokeWidth:10,color:"var(--success)",className:"text-foreground",label:""}),e.jsx(t.CheckCircle2,{className:"size-8 text-success absolute inset-0 m-auto"})]}),e.jsx("h2",{className:"text-xl font-bold text-foreground mb-2",children:"Study Session Complete"}),e.jsx("p",{className:"text-muted-foreground text-sm",children:"Great work! Here's your session summary."})]}),e.jsxs("div",{className:"grid grid-cols-2 sm:grid-cols-4 gap-3 mb-8",children:[e.jsx(s.StatCard,{icon:e.jsx(t.Layers,{}),label:"Cards Studied",description:"Total cards reviewed",value:String(y.totalCards)}),e.jsx(s.StatCard,{icon:e.jsx(t.BookOpen,{}),label:"Decks",description:"Decks completed",value:String(y.decksStudied)}),e.jsx(s.StatCard,{icon:e.jsx(t.Clock,{}),label:"Time Spent",description:"Session duration",value:s.formatDuration(y.timeElapsedSeconds)}),e.jsx(s.StatCard,{icon:e.jsx(t.Shuffle,{}),label:"Shuffled",description:"Card order randomized",value:y.wasShuffled?"Yes":"No"})]}),e.jsxs("div",{className:"flex justify-center gap-3",children:[e.jsxs(s.Button,{variant:"outline",onClick:S,children:[e.jsx(t.ArrowLeft,{className:"size-4 mr-2"}),"Pick New Deck"]}),e.jsxs(s.Button,{onClick:k,children:[e.jsx(t.RotateCcw,{className:"size-4 mr-2"}),"Study Again"]})]})]})})})}function q({courseTitle:m,curriculum:v,progress:h,items:u,initialItemUid:w,onItemComplete:f,onItemChange:i,sidebarCollapsed:o=!1,readOnly:j=!1,className:x,style:C}){const g=a.useRef(null),l=a.useMemo(()=>A.flattenLeaves(v),[v]),N=a.useMemo(()=>new Map(u.map(z=>[z.uid,z])),[u]),[c,p]=a.useState(w??l[0]??""),[b,R]=a.useState(!o),[k,S]=a.useState(()=>h?new Set(h.filter(z=>z.isCompleted).map(z=>z.resourceUid)):new Set),y=l.indexOf(c),r=y>0,d=y<l.length-1,n=k.has(c),B=l.length>0?Math.round(l.filter(z=>k.has(z)).length/l.length*100):0,T=N.get(c);a.useEffect(()=>{var z;(z=g.current)==null||z.focus({preventScroll:!0})},[c]);function E(z){p(z),i==null||i(z)}function M(z){(!z.children||z.children.length===0)&&E(z.uid)}function D(){S(z=>new Set(z).add(c)),f==null||f(c)}function I(){d&&E(l[y+1])}function U(){r&&E(l[y-1])}const L=a.useMemo(()=>{const z=new Map((h??[]).map(P=>[P.resourceUid,P]));for(const P of k)z.has(P)?z.set(P,{...z.get(P),isCompleted:!0}):z.set(P,{resourceUid:P,isCompleted:!0});return Array.from(z.values())},[h,k]),F=d?N.get(l[y+1]):null;return e.jsxs("div",{className:s.cn("flex h-full overflow-hidden",x),style:C,children:[e.jsx(s.Drawer,{open:b,onOpenChange:R,side:"left",children:e.jsxs(s.DrawerContent,{size:"sm",scrollLock:!1,children:[e.jsxs(s.DrawerHeader,{className:"flex-row items-center justify-between",children:[e.jsx(s.DrawerTitle,{className:"text-xs font-semibold text-muted-foreground uppercase tracking-wide",children:"Course"}),e.jsx(s.DrawerClose,{})]}),e.jsx(s.DrawerBody,{className:"px-2 pb-2",children:e.jsx(A.CourseOutline,{items:v,progress:L,courseTitle:m,activeItemUid:c,onItemClick:M,readOnly:j})})]})}),e.jsxs("div",{className:"flex-1 flex flex-col min-w-0 overflow-hidden",children:[e.jsxs("div",{className:"flex items-center gap-2 px-4 py-2 border-b border-border bg-background shrink-0",children:[e.jsx(s.Button,{variant:"ghost",size:"sm",className:"size-7 p-0 mr-1",onClick:()=>R(!0),children:e.jsx(t.PanelLeft,{className:"size-4"})}),e.jsx("div",{className:"flex-1 min-w-0",children:e.jsx("span",{className:"text-sm font-semibold text-foreground truncate block",children:(T==null?void 0:T.title)??"Select an item"})}),e.jsxs("span",{className:"text-xs text-muted-foreground shrink-0",children:[y+1," / ",l.length]})]}),e.jsx("div",{ref:g,tabIndex:-1,className:"flex-1 overflow-y-auto p-6 outline-none",children:T?Y(T,j,D,n,I,d,F):e.jsx(s.EmptyState,{title:"No content selected",description:"Select an item from the course outline to get started."})}),e.jsx("div",{className:"shrink-0 border-t border-border bg-background px-4 py-3",children:e.jsxs("div",{className:"flex items-center gap-4",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("div",{className:"flex items-center gap-2 mb-1",children:e.jsxs("span",{className:"text-xs text-muted-foreground",children:[B,"% complete"]})}),e.jsx(s.Progress,{value:B,size:"sm"})]}),e.jsxs("div",{className:"flex items-center gap-2 shrink-0",children:[!n&&T&&e.jsxs(s.Button,{size:"sm",variant:"outline",onClick:D,disabled:j,children:[e.jsx(t.Check,{className:"size-3.5 mr-1"}),"Complete"]}),e.jsx(s.Button,{size:"sm",variant:"ghost",onClick:U,disabled:!r,children:e.jsx(t.ChevronLeft,{className:"size-4"})}),e.jsx(s.Button,{size:"sm",variant:"ghost",onClick:I,disabled:!d,children:e.jsx(t.ChevronRight,{className:"size-4"})})]})]})})]})]})}function Y(m,v,h,u,w,f,i){switch(m.type){case"lesson":return e.jsx(A.LessonPage,{title:m.title,blocks:m.blocks,isCompleted:u,onMarkComplete:h,onNextLesson:f?w:void 0,nextLessonTitle:i==null?void 0:i.title,readOnly:v});case"video":return e.jsx(A.LecturePlayer,{video:{src:m.src,poster:m.poster,title:m.title}});case"quiz":return e.jsx(A.PracticeQuiz,{questions:m.questions,instantFeedback:!0,allowRetry:!0,readOnly:v});default:return e.jsx(s.EmptyState,{title:"Unknown content type",description:"This content type is not supported."})}}function G({title:m,description:v,instructions:h,questions:u,timeLimitSeconds:w,passingScore:f,allowBackNavigation:i=!0,autoSubmitOnTimeout:o=!0,timeWarningThreshold:j,allowRetake:x=!1,showReview:C=!0,onComplete:g,className:l,style:N}){const[c,p]=a.useState({tag:"intro"}),[b,R]=a.useState(0),k=a.useRef(null),S=a.useRef(null),y=a.useRef(null);a.useEffect(()=>{var E;(E=y.current)==null||E.focus({preventScroll:!0})},[c.tag]),a.useEffect(()=>(c.tag==="exam"?(k.current=Date.now(),S.current=setInterval(()=>{k.current&&R(Math.floor((Date.now()-k.current)/1e3))},1e3)):S.current&&(clearInterval(S.current),S.current=null),()=>{S.current&&clearInterval(S.current)}),[c.tag]);function r(E,M){const{correct:D,total:I,percentage:U}=s.scoreAssessment(u,E);return{answers:E,correct:D,total:I,percentage:U,passed:f!==void 0?U>=f:!0,timeElapsedSeconds:M.timeElapsedSeconds,wasAutoSubmitted:M.wasAutoSubmitted}}function d(E,M){const D=r(E,M);p({tag:"results",result:D}),g==null||g(D)}function n(){R(0),k.current=null,p({tag:"intro"})}if(c.tag==="intro")return e.jsx("div",{ref:y,tabIndex:-1,className:s.cn("max-w-2xl mx-auto outline-none",l),style:N,children:e.jsx(s.Card,{children:e.jsxs(s.CardContent,{className:"pt-8 pb-8 text-center",children:[e.jsx("div",{className:"mx-auto mb-4 w-14 h-14 rounded-full bg-primary/10 flex items-center justify-center",children:e.jsx(t.ShieldCheck,{className:"size-7 text-primary"})}),e.jsx("h2",{className:"text-2xl font-bold text-foreground mb-2",children:m}),v&&e.jsx("p",{className:"text-muted-foreground mb-6 max-w-md mx-auto",children:v}),h&&e.jsx(s.Alert,{className:"text-left mb-6",children:e.jsx(s.AlertDescription,{children:h})}),e.jsxs("div",{className:"flex flex-wrap justify-center gap-2 mb-8",children:[e.jsxs(s.Badge,{variant:"outline",className:"gap-1.5",children:[e.jsx(t.HelpCircle,{className:"size-3.5"}),u.length," questions"]}),e.jsxs(s.Badge,{variant:"outline",className:"gap-1.5",children:[e.jsx(t.Clock,{className:"size-3.5"}),s.formatDuration(w)," time limit"]}),f!==void 0&&e.jsxs(s.Badge,{variant:"outline",className:"gap-1.5",children:[e.jsx(t.CheckCircle2,{className:"size-3.5"}),f,"% to pass"]})]}),e.jsxs(s.Button,{size:"lg",onClick:()=>p({tag:"exam"}),children:[e.jsx(t.Play,{className:"size-4 mr-2"}),"Begin Exam"]})]})})});if(c.tag==="exam")return e.jsx("div",{ref:y,tabIndex:-1,className:s.cn("outline-none",l),style:N,children:e.jsx(A.ExamSession,{questions:u,timeLimitSeconds:w,timeElapsedSeconds:b,autoSubmitOnTimeout:o,timeWarningThreshold:j,allowBackNavigation:i,confirmBeforeSubmit:!0,examTitle:m,onSubmit:d})});const{result:B}=c,T=B.passed;return e.jsxs("div",{ref:y,tabIndex:-1,className:s.cn("max-w-2xl mx-auto outline-none",l),style:N,children:[e.jsx(s.Card,{children:e.jsxs(s.CardContent,{className:"pt-8 pb-8",children:[e.jsxs("div",{className:"text-center mb-8",children:[e.jsx(s.ProgressRing,{value:B.percentage,size:140,strokeWidth:10,color:T?"var(--success)":"var(--destructive)",className:"mx-auto mb-4 text-foreground"}),e.jsx(s.Badge,{variant:T?"success":"destructive",className:"text-sm px-3 py-1 mb-2",children:T?"Passed":"Failed"}),B.wasAutoSubmitted&&e.jsx(s.Badge,{variant:"outline",className:"text-sm px-3 py-1 mb-2 ml-2",children:"Auto-submitted"}),e.jsx("h2",{className:"text-xl font-bold text-foreground",children:m})]}),e.jsxs("div",{className:"grid grid-cols-2 sm:grid-cols-4 gap-3 mb-8",children:[e.jsx(s.StatCard,{icon:e.jsx(t.CheckCircle2,{}),label:"Correct",description:"Questions answered right",value:`${B.correct}/${B.total}`}),e.jsx(s.StatCard,{icon:e.jsx(t.XCircle,{}),label:"Incorrect",description:"Questions to review",value:`${B.total-B.correct}/${B.total}`}),e.jsx(s.StatCard,{icon:e.jsx(t.Trophy,{}),label:"Score",description:"Overall percentage",value:`${B.percentage}%`}),e.jsx(s.StatCard,{icon:e.jsx(t.Clock,{}),label:"Time",description:"Total elapsed",value:s.formatDuration(B.timeElapsedSeconds)})]}),x&&e.jsx("div",{className:"flex justify-center mb-8",children:e.jsxs(s.Button,{variant:"outline",onClick:n,children:[e.jsx(t.RotateCcw,{className:"size-4 mr-2"}),"Retake Exam"]})})]})}),C&&e.jsxs(e.Fragment,{children:[e.jsx(s.Separator,{className:"my-6"}),e.jsx("h3",{className:"text-lg font-semibold text-foreground mb-4",children:"Question Review"}),e.jsx(A.AssessmentReview,{questions:u,sessionAnswers:B.answers,showCorrectAnswers:!0})]})]})}function H({title:m,description:v,questions:h,requireAll:u=!1,showProgress:w=!0,thankYouTitle:f="Thank You!",thankYouMessage:i,onComplete:o,allowRestart:j=!1,className:x,style:C}){const[g,l]=a.useState({tag:"intro"}),N=a.useRef(null),c=a.useRef(null);a.useEffect(()=>{var S;(S=c.current)==null||S.focus({preventScroll:!0})},[g.tag]);function p(S){const y=N.current?Math.floor((Date.now()-N.current)/1e3):0,r={answers:S,totalQuestions:h.length,answeredCount:S.length,timeElapsedSeconds:y};l({tag:"thankYou",result:r}),o==null||o(r)}function b(){N.current=null,l({tag:"intro"})}function R(){N.current=Date.now(),l({tag:"survey"})}if(g.tag==="intro")return e.jsx("div",{ref:c,tabIndex:-1,className:s.cn("max-w-2xl mx-auto outline-none",x),style:C,children:e.jsx(s.Card,{children:e.jsxs(s.CardContent,{className:"pt-8 pb-8 text-center",children:[e.jsx("div",{className:"mx-auto mb-4 w-14 h-14 rounded-full bg-primary/10 flex items-center justify-center",children:e.jsx(t.ClipboardList,{className:"size-7 text-primary"})}),e.jsx("h2",{className:"text-2xl font-bold text-foreground mb-2",children:m}),v&&e.jsx("p",{className:"text-muted-foreground mb-6 max-w-md mx-auto",children:v}),e.jsx("div",{className:"flex flex-wrap justify-center gap-2 mb-8",children:e.jsxs(s.Badge,{variant:"outline",className:"gap-1.5",children:[e.jsx(t.HelpCircle,{className:"size-3.5"}),h.length," questions"]})}),e.jsxs(s.Button,{size:"lg",onClick:R,children:[e.jsx(t.Play,{className:"size-4 mr-2"}),"Begin Survey"]})]})})});if(g.tag==="survey")return e.jsx("div",{ref:c,tabIndex:-1,className:s.cn("outline-none",x),style:C,children:e.jsx(A.SurveyForm,{title:m,questions:h,requireAll:u,showProgress:w,onSubmit:p})});const{result:k}=g;return e.jsx("div",{ref:c,tabIndex:-1,className:s.cn("max-w-2xl mx-auto outline-none",x),style:C,children:e.jsx(s.Card,{children:e.jsxs(s.CardContent,{className:"pt-8 pb-8 text-center",children:[e.jsx("div",{className:"mx-auto mb-4 w-14 h-14 rounded-full bg-success/10 flex items-center justify-center",children:e.jsx(t.CheckCircle2,{className:"size-7 text-success"})}),e.jsx("h2",{className:"text-2xl font-bold text-foreground mb-2",children:f}),e.jsx("p",{className:"text-muted-foreground mb-6 max-w-md mx-auto",children:i??"Your responses have been recorded. Thank you for your feedback!"}),e.jsxs("div",{className:"grid grid-cols-2 gap-3 max-w-sm mx-auto mb-6",children:[e.jsx(s.StatCard,{icon:e.jsx(t.HelpCircle,{}),label:"Answered",description:"Questions completed",value:`${k.answeredCount}/${k.totalQuestions}`}),e.jsx(s.StatCard,{icon:e.jsx(t.Clock,{}),label:"Time",description:"Total elapsed",value:s.formatDuration(k.timeElapsedSeconds)})]}),j&&e.jsxs(s.Button,{variant:"outline",onClick:b,children:[e.jsx(t.RotateCcw,{className:"size-4 mr-2"}),"Take Again"]})]})})})}function O({courseTitle:m,gradeItems:v,categories:h,overallGrade:u,showWeights:w,progressData:f,reviewData:i,className:o,style:j}){const[x,C]=a.useState(null),g=a.useRef(null);a.useEffect(()=>{var b;(b=g.current)==null||b.focus({preventScroll:!0})},[x]);function l(b){i!=null&&i[b.uid]&&C(b.uid)}function N(){C(null)}const c=x?v.find(b=>b.uid===x):null,p=x?i==null?void 0:i[x]:null;return e.jsxs("div",{ref:g,tabIndex:-1,className:s.cn("outline-none",o),style:j,children:[e.jsxs("div",{className:"flex items-center justify-between mb-6",children:[e.jsxs("div",{children:[m&&e.jsx("h2",{className:"text-xl font-bold text-foreground",children:m}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"Grade Center"})]}),u&&e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx(s.GradeIndicator,{percentage:u.percentage,letterGrade:u.letterGrade,size:"medium"}),e.jsxs("div",{className:"text-right",children:[e.jsxs("div",{className:"text-sm font-medium text-foreground",children:[u.pointsEarned,"/",u.pointsPossible," pts"]}),u.letterGrade&&e.jsx("div",{className:"text-xs text-muted-foreground",children:u.letterGrade})]})]})]}),e.jsx(s.Separator,{className:"mb-6"}),c&&p?e.jsxs("div",{children:[e.jsxs(s.Button,{variant:"ghost",size:"sm",onClick:N,className:"mb-4",children:[e.jsx(t.ArrowLeft,{className:"size-4 mr-1.5"}),"Back to Grades"]}),e.jsx(s.Card,{className:"mb-4",children:e.jsxs(s.CardContent,{className:"py-3 px-4",children:[e.jsx("h3",{className:"font-semibold text-foreground",children:c.name}),c.score!==null&&e.jsxs("p",{className:"text-sm text-muted-foreground",children:["Score: ",c.score,"/",c.maxScore," (",Math.round(c.score/c.maxScore*100),"%)"]})]})}),e.jsx(A.AssessmentReview,{questions:p.questions,sessionAnswers:p.sessionAnswers,score:p.score,showCorrectAnswers:!0})]}):e.jsxs(s.Tabs,{defaultValue:"grades",children:[f&&e.jsxs(s.TabsList,{className:"mb-6",children:[e.jsxs(s.TabsTrigger,{value:"grades",children:[e.jsx(t.BookOpen,{className:"size-4 mr-1.5"}),"Grades"]}),e.jsxs(s.TabsTrigger,{value:"progress",children:[e.jsx(t.BarChart3,{className:"size-4 mr-1.5"}),"Progress"]})]}),e.jsx(s.TabsContent,{value:"grades",children:e.jsx(A.GradebookTable,{items:v,categories:h,overallGrade:u,showWeights:w,onItemClick:l})}),f&&e.jsx(s.TabsContent,{value:"progress",children:e.jsx(A.ProgressDashboard,{overallProgress:f.overallProgress,totalTimeSpent:f.totalTimeSpent,modules:f.modules,recentActivity:f.recentActivity,streak:f.streak,achievements:f.achievements})})]})]})}const V={text:"Text Entry",file:"File Upload",url:"URL Submission"};function W({title:m,instructions:v,dueDate:h,maxScore:u,submissionTypes:w,fileConstraints:f,rubric:i,existingSubmission:o,status:j="not_started",grade:x,onSubmit:C,onSaveDraft:g,className:l,style:N}){const c=j==="submitted"||j==="graded"?{tag:"confirmation",submission:o??{}}:{tag:"instructions"},[p,b]=a.useState(c),R=a.useRef(null);a.useEffect(()=>{var n;(n=R.current)==null||n.focus({preventScroll:!0})},[p.tag]);const k=a.useMemo(()=>i?i.reduce((n,B)=>n+Math.max(...B.levels.map(T=>T.points)),0):0,[i]);function S(n){C==null||C(n),b({tag:"confirmation",submission:n})}function y(n){g==null||g(n)}const r=j==="not_started"||j==="draft"||j==="resubmit";if(p.tag==="instructions")return e.jsx("div",{ref:R,tabIndex:-1,className:s.cn("max-w-2xl mx-auto outline-none",l),style:N,children:e.jsx(s.Card,{children:e.jsxs(s.CardContent,{className:"pt-8 pb-8",children:[e.jsxs("div",{className:"text-center mb-6",children:[e.jsx("div",{className:"mx-auto mb-4 w-14 h-14 rounded-full bg-primary/10 flex items-center justify-center",children:e.jsx(t.FileEdit,{className:"size-7 text-primary"})}),e.jsx("h2",{className:"text-2xl font-bold text-foreground mb-2",children:m})]}),e.jsxs("div",{className:"flex flex-wrap justify-center gap-2 mb-6",children:[h&&e.jsx(s.DueDateDisplay,{dueDate:h,size:"small"}),u!==void 0&&e.jsxs(s.Badge,{variant:"outline",className:"gap-1.5",children:[e.jsx(t.CheckCircle2,{className:"size-3.5"}),u," points"]}),e.jsxs(s.Badge,{variant:"outline",className:"gap-1.5",children:[e.jsx(t.Paperclip,{className:"size-3.5"}),w.map(n=>V[n]).join(", ")]}),e.jsx(s.StatusBadge,{status:j})]}),e.jsx(s.Separator,{className:"my-6"}),e.jsx("div",{className:"prose prose-sm text-foreground mb-6",children:v}),i&&i.length>0&&e.jsxs(e.Fragment,{children:[e.jsx(s.Separator,{className:"my-6"}),e.jsx(A.RubricView,{criteria:i,maxScore:k})]}),r&&e.jsx("div",{className:"text-center mt-8",children:e.jsxs(s.Button,{size:"lg",onClick:()=>b({tag:"work"}),children:[e.jsx(t.Play,{className:"size-4 mr-2"}),"Start Assignment"]})})]})})});if(p.tag==="work")return e.jsxs("div",{ref:R,tabIndex:-1,className:s.cn("outline-none",l),style:N,children:[e.jsxs(s.Button,{variant:"ghost",size:"sm",onClick:()=>b({tag:"instructions"}),className:"mb-4",children:[e.jsx(t.ArrowLeft,{className:"size-4 mr-1.5"}),"Back to Instructions"]}),e.jsx(A.AssignmentSubmission,{title:m,instructions:v,dueDate:h,maxScore:u,status:j,submissionTypes:w,existingSubmission:o,fileConstraints:f,grade:x,onSubmit:S,onSaveDraft:y})]});const{submission:d}=p;return e.jsx("div",{ref:R,tabIndex:-1,className:s.cn("max-w-2xl mx-auto outline-none",l),style:N,children:e.jsx(s.Card,{children:e.jsxs(s.CardContent,{className:"pt-8 pb-8",children:[e.jsxs("div",{className:"text-center mb-6",children:[e.jsx("div",{className:"mx-auto mb-4 w-14 h-14 rounded-full bg-success/10 flex items-center justify-center",children:e.jsx(t.CheckCircle2,{className:"size-7 text-success"})}),e.jsx("h2",{className:"text-xl font-bold text-foreground mb-2",children:j==="graded"?"Assignment Graded":"Submission Received"}),e.jsxs("div",{className:"flex justify-center gap-2 mb-4",children:[e.jsx(s.StatusBadge,{status:j}),h&&e.jsx(s.DueDateDisplay,{dueDate:h,size:"small"})]})]}),j==="graded"&&x&&e.jsxs("div",{className:"text-center mb-6",children:[e.jsx(s.GradeIndicator,{percentage:u?Math.round(x.score/u*100):0,size:"large"}),e.jsxs("p",{className:"text-sm text-muted-foreground mt-2",children:[x.score,"/",u," points"]}),x.feedback&&e.jsx(s.Alert,{className:"text-left mt-4",children:e.jsx(s.AlertDescription,{children:x.feedback})}),i&&x.rubricLevels&&e.jsxs(e.Fragment,{children:[e.jsx(s.Separator,{className:"my-6"}),e.jsx(A.RubricView,{criteria:i,selectedLevels:x.rubricLevels,totalScore:x.score,maxScore:k})]})]}),e.jsx(s.Separator,{className:"my-6"}),e.jsx("h3",{className:"text-sm font-semibold text-foreground mb-3",children:"What You Submitted"}),e.jsxs("div",{className:"space-y-2 text-sm text-muted-foreground",children:[d.textContent&&e.jsxs("div",{className:"flex items-start gap-2",children:[e.jsx(t.FileText,{className:"size-4 mt-0.5 shrink-0"}),e.jsx("span",{className:"line-clamp-2",children:d.textContent})]}),d.files&&d.files.length>0&&e.jsxs("div",{className:"flex items-start gap-2",children:[e.jsx(t.Paperclip,{className:"size-4 mt-0.5 shrink-0"}),e.jsxs("span",{children:[d.files.length," file",d.files.length!==1?"s":""," uploaded"]})]}),d.url&&e.jsxs("div",{className:"flex items-start gap-2",children:[e.jsx(t.Link,{className:"size-4 mt-0.5 shrink-0"}),e.jsx("span",{className:"truncate",children:d.url})]})]}),r&&e.jsx("div",{className:"text-center mt-8",children:e.jsxs(s.Button,{variant:"outline",onClick:()=>b({tag:"work"}),children:[e.jsx(t.FileEdit,{className:"size-4 mr-2"}),"Edit Submission"]})})]})})})}function _({courseTitle:m,recipientName:v,organizationName:h,organizationLogo:u,signatory:w,completionDate:f,certificateVariant:i="modern",requirements:o,overallProgress:j,onRequirementClick:x,onCertificateEarned:C,className:g,style:l}){const{allComplete:N,completedCount:c}=a.useMemo(()=>{const S=o.filter(y=>y.completed).length;return{allComplete:S===o.length,completedCount:S}},[o]),[p,b]=a.useState({tag:"requirements"}),R=a.useRef(null),k=a.useRef(!1);return a.useEffect(()=>{var S;(S=R.current)==null||S.focus({preventScroll:!0})},[p.tag]),a.useEffect(()=>{p.tag==="certificate"&&!k.current&&(k.current=!0,C==null||C())},[p.tag,C]),p.tag==="requirements"?e.jsx("div",{ref:R,tabIndex:-1,className:s.cn("max-w-2xl mx-auto outline-none",g),style:l,children:e.jsx(s.Card,{children:e.jsxs(s.CardContent,{className:"pt-8 pb-8",children:[e.jsxs("div",{className:"text-center mb-6",children:[e.jsx(s.ProgressRing,{value:j,size:100,strokeWidth:8,color:N?"var(--success)":"var(--primary)",className:"mx-auto mb-4 text-foreground"}),e.jsx("h2",{className:"text-xl font-bold text-foreground mb-2",children:m}),e.jsx("p",{className:"text-sm text-muted-foreground",children:N?"All requirements met — your certificate is ready!":`${c} of ${o.length} requirements complete`})]}),e.jsx(A.RequirementsChecklist,{requirements:o,onRequirementClick:x,className:"mb-6"}),N&&e.jsx("div",{className:"text-center mt-6",children:e.jsxs(s.Button,{size:"lg",onClick:()=>b({tag:"certificate"}),children:[e.jsx(t.Award,{className:"size-4 mr-2"}),"View Certificate"]})})]})})}):e.jsxs("div",{ref:R,tabIndex:-1,className:s.cn("outline-none",g),style:l,children:[e.jsxs(s.Button,{variant:"ghost",size:"sm",onClick:()=>b({tag:"requirements"}),className:"mb-4",children:[e.jsx(t.ArrowLeft,{className:"size-4 mr-1.5"}),"Back to Requirements"]}),e.jsxs("div",{className:"text-center mb-8",children:[e.jsx("div",{className:"mx-auto mb-4 w-14 h-14 rounded-full bg-success/10 flex items-center justify-center",children:e.jsx(t.PartyPopper,{className:"size-7 text-success"})}),e.jsx("h2",{className:"text-2xl font-bold text-foreground mb-2",children:"Congratulations!"}),e.jsxs("p",{className:"text-muted-foreground",children:["You've completed all requirements for"," ",e.jsx("span",{className:"font-medium text-foreground",children:m})]})]}),e.jsx(A.CertificateViewer,{recipientName:v,courseTitle:m,completionDate:f??new Date().toISOString().split("T")[0],organizationName:h,organizationLogo:u,signatory:w,variant:i,showActions:!0})]})}function X({forumTitle:m,topics:v,currentUser:h,threads:u,onCreateTopic:w,onReply:f,onToggleLike:i,onMarkAnswer:o,onTopicOpen:j,readOnly:x,className:C,style:g}){const[l,N]=a.useState(null),[c,p]=a.useState(""),[b,R]=a.useState("newest"),k=a.useRef(null);a.useEffect(()=>{var n;(n=k.current)==null||n.focus({preventScroll:!0})},[l]);function S(n){N(n),j==null||j(n)}function y(){N(null)}const r=l?u[l]:null,d=l?v.find(n=>n.uid===l):null;return e.jsx("div",{ref:k,tabIndex:-1,className:s.cn("outline-none",C),style:g,children:l&&r?e.jsxs("div",{children:[e.jsxs(s.Button,{variant:"ghost",size:"sm",onClick:y,className:"mb-4",children:[e.jsx(t.ArrowLeft,{className:"size-4 mr-1.5"}),"Back to Topics"]}),e.jsx(A.DiscussionThread,{title:(d==null?void 0:d.title)??"",rootPost:r.rootPost,replies:r.replies,currentUser:h,onReply:(n,B)=>f==null?void 0:f(l,n,B),onToggleLike:i?n=>i(l,n):void 0,onMarkAnswer:o?n=>o(l,n):void 0,readOnly:x})]}):e.jsx(A.ForumBoard,{title:m,topics:v,currentUser:h,onTopicClick:S,onCreateTopic:w,sortOrder:b,onSortChange:R,searchQuery:c,onSearchChange:p,readOnly:x})})}exports.AssignmentModule=W;exports.CertificateModule=_;exports.CoursePlayer=q;exports.DiscussionModule=X;exports.ExamModule=G;exports.FlashcardLab=$;exports.GradeCenterModule=O;exports.QuizModule=Q;exports.SurveyModule=H;
|