@mui-toolpad-extended-tuni/courses 3.0.4 → 3.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/README.md CHANGED
@@ -15,8 +15,8 @@ npm install @mui-toolpad-extended-tuni/courses @mui-toolpad-extended-tuni/main @
15
15
  This package requires the following peer dependencies to be installed:
16
16
 
17
17
  ### Required Packages
18
- - **`@mui-toolpad-extended-tuni/main`**: ^3.3.0 - **MUST be installed separately**
19
- - **`@mui-toolpad-extended-tuni/core`**: ^3.1.0 - **MUST be installed separately** (also required by main)
18
+ - **`@mui-toolpad-extended-tuni/main`**: ^3.4.0 - **MUST be installed separately**
19
+ - **`@mui-toolpad-extended-tuni/core`**: ^3.2.0 - **MUST be installed separately** (also required by main)
20
20
 
21
21
  ### React & UI Framework
22
22
  - `react@^19.0.0`
@@ -40,6 +40,56 @@ npm install @mui-toolpad-extended-tuni/courses @mui-toolpad-extended-tuni/main @
40
40
  axios zustand
41
41
  ```
42
42
 
43
+ ## API Configuration
44
+
45
+ This package uses configurable API endpoints. Each microservice accepts its own `apiEndpoints` prop, allowing you to configure endpoints independently for only the services you use.
46
+
47
+ ### Default Endpoints
48
+
49
+ If no `apiEndpoints` prop is provided, the package uses these default endpoints:
50
+
51
+ - `get: "api/courses/"` - GET list of courses
52
+ - `getById: "api/courses/:id"` - GET course by ID (use `:id` placeholder)
53
+ - `getByUrl: "api/courses/?encoded_url=:encodedUrl"` - GET course by URL (use `:encodedUrl` placeholder)
54
+ - `post: "api/courses/"` - POST create new course
55
+ - `put: "api/courses/:id/"` - PUT update course (use `:id` placeholder)
56
+ - `delete: "api/chat/courses/:id"` - DELETE course (use `:id` placeholder)
57
+
58
+ ### Customizing Endpoints
59
+
60
+ Configure endpoints directly on the `CourseMicroservice` component:
61
+
62
+ ```tsx
63
+ import { CourseMicroservice } from '@mui-toolpad-extended-tuni/courses';
64
+ import type { CoursesApiEndpoints } from '@mui-toolpad-extended-tuni/courses';
65
+
66
+ const coursesEndpoints: CoursesApiEndpoints = {
67
+ get: "https://api.example.com/v1/courses",
68
+ getById: "https://api.example.com/v1/courses/:id",
69
+ getByUrl: "https://api.example.com/v1/courses?url=:encodedUrl",
70
+ post: "https://api.example.com/v1/courses",
71
+ put: "https://api.example.com/v1/courses/:id",
72
+ delete: "https://api.example.com/v1/courses/:id",
73
+ };
74
+
75
+ <CourseMicroservice apiEndpoints={coursesEndpoints}>
76
+ {/* Your course microservices */}
77
+ </CourseMicroservice>
78
+ ```
79
+
80
+ **Note**: You can use either full URLs (`https://api.example.com/courses`) or relative paths (`api/courses/`). Placeholders like `:id` will be replaced with actual values at runtime.
81
+
82
+ **Partial Configuration**: You can configure only the endpoints you need to customize. Unspecified endpoints will use defaults:
83
+
84
+ ```tsx
85
+ <CourseMicroservice apiEndpoints={{
86
+ get: "api/v2/courses", // Only override GET endpoint
87
+ // Other endpoints use defaults
88
+ }}>
89
+ {/* Your course microservices */}
90
+ </CourseMicroservice>
91
+ ```
92
+
43
93
  ## Usage
44
94
 
45
95
  ### Basic Setup
@@ -294,6 +344,338 @@ Course events are published with this structure:
294
344
  }
295
345
  ```
296
346
 
347
+ ## API Endpoints
348
+
349
+ This package makes the following API calls. All endpoints are configurable via `apiConfig`.
350
+
351
+ ### GET `/api/courses/` (or configured `get` endpoint)
352
+
353
+ Retrieves a list of all courses.
354
+
355
+ **Request**: No body required
356
+
357
+ **Response**: `200 OK`
358
+ ```json
359
+ [
360
+ {
361
+ "id": "course-123",
362
+ "title": "Introduction to Computer Science",
363
+ "description": "Basic CS concepts",
364
+ "code": "COMP.CS.100",
365
+ "instance": "compcs100-fall-2024",
366
+ "start_date": "2024-09-01T00:00:00Z",
367
+ "end_date": "2024-12-15T23:59:59Z",
368
+ "created_at": "2024-08-01T10:00:00Z",
369
+ "updated_at": "2024-08-15T14:30:00Z",
370
+ "visibility": {
371
+ "mode": "public",
372
+ "start_date": null,
373
+ "end_date": null
374
+ },
375
+ "events": {
376
+ "lecture": [],
377
+ "exercise": [],
378
+ "exam": [],
379
+ "deadline": [],
380
+ "other": []
381
+ },
382
+ "data_processing": {
383
+ "purposes": ["course_delivery", "assessment"],
384
+ "retention": 365,
385
+ "third_party_processors": [],
386
+ "special_categories": false,
387
+ "legal_basis": "consent"
388
+ }
389
+ }
390
+ ]
391
+ ```
392
+
393
+ **Response Type**: `Course[]` (array of Course objects)
394
+
395
+ ### GET `/api/courses/:id` (or configured `getById` endpoint)
396
+
397
+ Retrieves a single course by ID.
398
+
399
+ **Request Parameters**:
400
+ - `:id` (path parameter) - Course ID
401
+
402
+ **Response**: `200 OK`
403
+ ```json
404
+ {
405
+ "id": "course-123",
406
+ "title": "Introduction to Computer Science",
407
+ "description": "Basic CS concepts",
408
+ "code": "COMP.CS.100",
409
+ "instance": "compcs100-fall-2024",
410
+ // ... same structure as list endpoint
411
+ }
412
+ ```
413
+
414
+ **Response Type**: `Course`
415
+
416
+ ### GET `/api/courses/?encoded_url=:encodedUrl` (or configured `getByUrl` endpoint)
417
+
418
+ Retrieves a course by URL (base64-encoded).
419
+
420
+ **Request Parameters**:
421
+ - `encoded_url` (query parameter) - Base64-encoded course URL
422
+
423
+ **Response**: `200 OK` (array with single course)
424
+ ```json
425
+ [
426
+ {
427
+ "id": "course-123",
428
+ // ... course object
429
+ }
430
+ ]
431
+ ```
432
+
433
+ **Response Type**: `Course[]` (array with one Course)
434
+
435
+ ### POST `/api/courses/` (or configured `post` endpoint)
436
+
437
+ Creates a new course.
438
+
439
+ **Request Body**: `CourseRaw` (snake_case)
440
+ ```json
441
+ {
442
+ "title": "Introduction to Computer Science",
443
+ "description": "Basic CS concepts",
444
+ "code": "COMP.CS.100",
445
+ "instance": "compcs100-fall-2024",
446
+ "start_date": "2024-09-01T00:00:00Z",
447
+ "end_date": "2024-12-15T23:59:59Z",
448
+ "visibility": {
449
+ "mode": "public",
450
+ "start_date": null,
451
+ "end_date": null
452
+ },
453
+ "events": {
454
+ "lecture": [],
455
+ "exercise": [],
456
+ "exam": [],
457
+ "deadline": [],
458
+ "other": []
459
+ },
460
+ "data_processing": {
461
+ "purposes": ["course_delivery", "assessment"],
462
+ "retention": 365,
463
+ "third_party_processors": [],
464
+ "special_categories": false,
465
+ "legal_basis": "consent"
466
+ }
467
+ }
468
+ ```
469
+
470
+ **Response**: `201 Created`
471
+ ```json
472
+ {
473
+ "id": "course-123",
474
+ "title": "Introduction to Computer Science",
475
+ // ... full Course object with generated ID and timestamps
476
+ "created_at": "2024-08-01T10:00:00Z",
477
+ "updated_at": "2024-08-01T10:00:00Z"
478
+ }
479
+ ```
480
+
481
+ **Response Type**: `Course`
482
+
483
+ **Note**: The request body should be in snake_case format. The package automatically converts from camelCase.
484
+
485
+ ### PUT `/api/courses/:id/` (or configured `put` endpoint)
486
+
487
+ Updates an existing course.
488
+
489
+ **Request Parameters**:
490
+ - `:id` (path parameter) - Course ID
491
+
492
+ **Request Body**: `Course` (snake_case, must include `id`)
493
+ ```json
494
+ {
495
+ "id": "course-123",
496
+ "title": "Updated Course Title",
497
+ "description": "Updated description",
498
+ // ... all Course fields
499
+ }
500
+ ```
501
+
502
+ **Response**: `200 OK`
503
+ ```json
504
+ {
505
+ "id": "course-123",
506
+ "title": "Updated Course Title",
507
+ // ... updated Course object
508
+ "updated_at": "2024-08-15T14:30:00Z"
509
+ }
510
+ ```
511
+
512
+ **Response Type**: `Course`
513
+
514
+ ### DELETE `/api/chat/courses/:id` (or configured `delete` endpoint)
515
+
516
+ Deletes a course.
517
+
518
+ **Request Parameters**:
519
+ - `:id` (path parameter) - Course ID
520
+
521
+ **Response**: `200 OK`
522
+ ```json
523
+ {
524
+ "id": "course-123",
525
+ // ... deleted Course object
526
+ }
527
+ ```
528
+
529
+ **Response Type**: `Course`
530
+
531
+ ## Data Types
532
+
533
+ ### Course
534
+
535
+ Complete course object returned by API (includes `id`, `createdAt`, `updatedAt`).
536
+
537
+ ```typescript
538
+ interface Course extends CourseRaw {
539
+ id: string; // Unique course ID
540
+ createdAt: string; // ISO date string - when course was created
541
+ updatedAt: string; // ISO date string - when course was last updated
542
+ }
543
+ ```
544
+
545
+ ### CourseRaw
546
+
547
+ Course data for creating/updating courses (request body format).
548
+
549
+ ```typescript
550
+ interface CourseRaw {
551
+ title: string; // Course title (required)
552
+ description: string; // Course description (required)
553
+ code: string; // Course code, e.g., "COMP.CS.300" (required)
554
+ instance: string; // Instance identifier, e.g., "compcs300-october-2024" (required)
555
+ ltiLoginUrl?: string; // LTI login URL (optional)
556
+ services?: string[]; // List of services used (optional)
557
+ image?: { // Course images (optional)
558
+ large: string; // 1200x800px image URL
559
+ medium: string; // 600x400px image URL
560
+ thumbnail: string; // 300x200px image URL
561
+ };
562
+ startDate: string | null; // ISO date string - course start date
563
+ endDate: string | null; // ISO date string - course end date
564
+ visibility: { // Visibility settings
565
+ mode: "public" | "enrolled" | "private";
566
+ startDate: string | null; // When course becomes visible
567
+ endDate: string | null; // When visibility ends
568
+ };
569
+ events: { // Course events by type
570
+ lecture: CourseEvent[];
571
+ exercise: CourseEvent[];
572
+ exam: CourseEvent[];
573
+ deadline: CourseEvent[];
574
+ other: CourseEvent[];
575
+ };
576
+ tags?: string[]; // Course tags for categorization
577
+ language?: string; // ISO 639-1 language code
578
+ dataProcessing: { // GDPR data processing info
579
+ purposes: string[]; // What data is used for
580
+ retention: number; // Retention period in days
581
+ thirdPartyProcessors: Array<{
582
+ name: string;
583
+ purpose: string;
584
+ dataShared: string[];
585
+ }>;
586
+ specialCategories: boolean; // Special categories of personal data
587
+ legalBasis: "consent" | "contract" | "legal_obligation" | "legitimate_interests";
588
+ };
589
+ enrollment?: { // Enrollment settings
590
+ startDate: string | null; // Enrollment opens
591
+ endDate: string | null; // Enrollment closes
592
+ status: {
593
+ open: boolean; // Whether new enrollments accepted
594
+ maxStudents?: number; // Maximum students (optional)
595
+ };
596
+ };
597
+ relationships?: { // Course relationships
598
+ prerequisites: CourseRelation[];
599
+ continuations: CourseRelation[];
600
+ alternatives: CourseRelation[];
601
+ related: CourseRelation[];
602
+ };
603
+ studyModule?: { // Study module info
604
+ name: string; // Module name
605
+ order?: number; // Order within module
606
+ credits: number; // Credit points
607
+ level: "basic" | "intermediate" | "advanced";
608
+ };
609
+ }
610
+ ```
611
+
612
+ ### CourseEvent
613
+
614
+ Individual course event (lecture, exercise, exam, etc.).
615
+
616
+ ```typescript
617
+ interface CourseEvent {
618
+ id: string; // Event ID
619
+ type: "lecture" | "exercise" | "exam" | "deadline" | "other";
620
+ title: string; // Event title
621
+ description?: string; // Event description
622
+ startTime: string; // ISO date string - event start
623
+ endTime?: string; // ISO date string - event end
624
+ location?: string; // Physical or virtual location
625
+ teachers?: EnrollmentData[]; // Array of teachers
626
+ recurring?: { // Recurring event settings
627
+ frequency: "daily" | "weekly" | "biweekly";
628
+ until: string; // ISO date string - when recurrence ends
629
+ exceptions?: string[]; // ISO date strings - cancelled dates
630
+ };
631
+ maxParticipants?: number; // Maximum participants
632
+ requiresRegistration?: boolean; // Whether registration required
633
+ }
634
+ ```
635
+
636
+ ### EnrollmentData
637
+
638
+ User enrollment information for a course.
639
+
640
+ ```typescript
641
+ interface EnrollmentData {
642
+ courseId: string; // Course ID
643
+ userId: string; // User ID
644
+ name: string; // User name
645
+ email: string; // User email
646
+ role: "student" | "teacher" | "guest";
647
+ status: "enrolled" | "pending" | "rejected";
648
+ }
649
+ ```
650
+
651
+ ### CourseRelation
652
+
653
+ Relationship between courses (prerequisites, continuations, etc.).
654
+
655
+ ```typescript
656
+ interface CourseRelation {
657
+ code: string; // Related course code
658
+ type: "prerequisite" | "recommended" | "parallel" | "continues_from" |
659
+ "alternative_to" | "part_of" | "prepares_for";
660
+ description?: string; // Why courses are related
661
+ required?: boolean; // Hard requirement or suggestion
662
+ }
663
+ ```
664
+
665
+ ### Type Definitions
666
+
667
+ ```typescript
668
+ type courseRole = "student" | "teacher" | "guest";
669
+ type visibilityMode = "public" | "enrolled" | "private";
670
+ type courseEventType = "lecture" | "exercise" | "exam" | "deadline" | "other";
671
+ type courseEventFrequency = "daily" | "weekly" | "biweekly";
672
+ type legalBasis = "consent" | "contract" | "legal_obligation" | "legitimate_interests";
673
+ type enrollmentStatus = "enrolled" | "pending" | "rejected";
674
+ type courseLevel = "basic" | "intermediate" | "advanced";
675
+ type courseRelationType = "prerequisite" | "recommended" | "parallel" |
676
+ "continues_from" | "alternative_to" | "part_of" | "prepares_for";
677
+ ```
678
+
297
679
  ## Exports
298
680
 
299
681
  ### Components
@@ -309,17 +691,34 @@ Course events are published with this structure:
309
691
 
310
692
  ### Hooks
311
693
  - `useCourseMicroserviceRegistration` - Hook for registering custom course microservices (must be used within `CourseMicroservice` context)
694
+ - `useCoursesApiConfig` - Hook to access courses API endpoint configuration
312
695
 
313
696
  ### Store
314
697
  - `useCourseStore` - Zustand store for course management
315
698
 
699
+ ### Network Functions
700
+ - `getCourses()` - Fetch all courses
701
+ - `getCourseById(courseId: string)` - Fetch course by ID
702
+ - `getCourseByUrl(url: string)` - Fetch course by URL
703
+ - `addCourse(courseData: CourseRaw)` - Create new course
704
+ - `updateCourse(course: Course)` - Update existing course
705
+ - `deleteCourse(courseId: string)` - Delete course
706
+
316
707
  ### Types
317
- - `Course` - Course type
318
- - `CourseRaw` - Raw course data type
708
+ - `Course` - Complete course object (with id, timestamps)
709
+ - `CourseRaw` - Course data for create/update requests
710
+ - `CourseEvent` - Individual course event
711
+ - `EnrollmentData` - User enrollment information
712
+ - `CourseRelation` - Course relationship
713
+ - `CoursesApiEndpoints` - API endpoint configuration type
319
714
  - `courseRole` - Course role type
320
715
  - `courseLevel` - Course level type
321
716
  - `courseEventType` - Course event type
322
717
  - `enrollmentStatus` - Enrollment status type
718
+ - `visibilityMode` - Visibility mode type
719
+ - `courseEventFrequency` - Event frequency type
720
+ - `legalBasis` - Legal basis for data processing
721
+ - `courseRelationType` - Course relation type
323
722
 
324
723
  ## Features
325
724
 
@@ -1,6 +1,9 @@
1
1
  import { default as React, ReactNode } from 'react';
2
- interface CourseMicroserviceProps {
2
+ import { CoursesApiEndpoints } from '@mui-toolpad-extended-tuni/core';
3
+ export interface CourseMicroserviceProps {
3
4
  children?: ReactNode;
5
+ /** API endpoint configuration for the courses microservice */
6
+ apiEndpoints?: CoursesApiEndpoints;
4
7
  }
5
8
  /**
6
9
  * CourseMicroservice Component
@@ -0,0 +1,15 @@
1
+ import { CoursesApiEndpoints } from '@mui-toolpad-extended-tuni/core';
2
+ /**
3
+ * Hook to access courses API configuration.
4
+ * Returns the courses endpoint configuration merged with defaults.
5
+ *
6
+ * @returns Courses API endpoints configuration, or undefined if not registered
7
+ * @throws Error if used outside of ApiConfigProvider
8
+ *
9
+ * @example
10
+ * ```tsx
11
+ * const coursesConfig = useCoursesApiConfig();
12
+ * const endpoint = coursesConfig?.get; // "api/courses/" or custom value
13
+ * ```
14
+ */
15
+ export declare const useCoursesApiConfig: () => CoursesApiEndpoints | undefined;