@dataclouder/ngx-lessons 0.0.31 → 0.0.33
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 +56 -10
- package/fesm2022/dataclouder-ngx-lessons.mjs +292 -81
- package/fesm2022/dataclouder-ngx-lessons.mjs.map +1 -1
- package/lib/components/dc-lessons/dc-lesson-editor/dc-lesson-editor.component.d.ts +9 -5
- package/lib/components/dc-lessons/dc-lesson-renderer/dc-lesson-renderer.component.d.ts +3 -1
- package/lib/components/lesson-mini-components/components/lessons.clases.d.ts +1 -0
- package/lib/models/simple-agents.d.ts +2 -0
- package/lib/services/lesson-ai.service.d.ts +15 -2
- package/lib/services/lesson-utils.service.d.ts +10 -1
- package/package.json +1 -1
- package/public-api.d.ts +1 -0
- package/src/lib/components/dc-lessons/dc-lesson-card/dc-lesson-card.component.html +0 -40
- package/src/lib/components/dc-lessons/dc-lesson-card/dc-lesson-card.component.scss +0 -120
- package/src/lib/components/dc-lessons/dc-lesson-card/dc-lesson-card.component.ts +0 -82
- package/src/lib/components/dc-lessons/dc-lesson-component-adder/dc-lesson-component-adder.component.css +0 -1
- package/src/lib/components/dc-lessons/dc-lesson-component-adder/dc-lesson-component-adder.component.html +0 -46
- package/src/lib/components/dc-lessons/dc-lesson-component-adder/dc-lesson-component-adder.component.ts +0 -52
- package/src/lib/components/dc-lessons/dc-lesson-editor/dc-lesson-editor.component.css +0 -90
- package/src/lib/components/dc-lessons/dc-lesson-editor/dc-lesson-editor.component.html +0 -67
- package/src/lib/components/dc-lessons/dc-lesson-editor/dc-lesson-editor.component.scss +0 -0
- package/src/lib/components/dc-lessons/dc-lesson-editor/dc-lesson-editor.component.ts +0 -356
- package/src/lib/components/dc-lessons/dc-lesson-metadata-editor/dc-lesson-metadata-editor.component.css +0 -1
- package/src/lib/components/dc-lessons/dc-lesson-metadata-editor/dc-lesson-metadata-editor.component.html +0 -72
- package/src/lib/components/dc-lessons/dc-lesson-metadata-editor/dc-lesson-metadata-editor.component.ts +0 -60
- package/src/lib/components/dc-lessons/dc-lesson-renderer/dc-lesson-renderer.component.html +0 -23
- package/src/lib/components/dc-lessons/dc-lesson-renderer/dc-lesson-renderer.component.scss +0 -3
- package/src/lib/components/dc-lessons/dc-lesson-renderer/dc-lesson-renderer.component.ts +0 -332
- package/src/lib/components/dc-lessons/lesson-form/lesson-form.component.html +0 -5
- package/src/lib/components/dc-lessons/lesson-form/lesson-form.component.scss +0 -3
- package/src/lib/components/dc-lessons/lesson-form/lesson-form.component.ts +0 -14
- package/src/lib/components/dc-lessons/lesson-list/dc-lesson-list.component.html +0 -30
- package/src/lib/components/dc-lessons/lesson-list/dc-lesson-list.component.scss +0 -17
- package/src/lib/components/dc-lessons/lesson-list/dc-lesson-list.component.ts +0 -170
- package/src/lib/components/dc-lessons/lessons.component.ts +0 -10
- package/src/lib/components/lesson-mini-components/components/ComponentBuilder.ts +0 -82
- package/src/lib/components/lesson-mini-components/components/ComponentWithForm.ts +0 -25
- package/src/lib/components/lesson-mini-components/components/lesson-dynamic.component.ts +0 -13
- package/src/lib/components/lesson-mini-components/components/lessons.clases.ts +0 -220
- package/src/lib/components/lesson-mini-components/components/selector/selector-builder/selector-builder.component.html +0 -62
- package/src/lib/components/lesson-mini-components/components/selector/selector-builder/selector-builder.component.scss +0 -15
- package/src/lib/components/lesson-mini-components/components/selector/selector-builder/selector-builder.component.ts +0 -70
- package/src/lib/components/lesson-mini-components/components/selector/selector.component.html +0 -1
- package/src/lib/components/lesson-mini-components/components/selector/selector.component.scss +0 -12
- package/src/lib/components/lesson-mini-components/components/selector/selector.component.spec.ts +0 -25
- package/src/lib/components/lesson-mini-components/components/selector/selector.component.ts +0 -47
- package/src/lib/components/lesson-mini-components/components/speaker/speaker-builder/speaker-builder.component.html +0 -13
- package/src/lib/components/lesson-mini-components/components/speaker/speaker-builder/speaker-builder.component.scss +0 -0
- package/src/lib/components/lesson-mini-components/components/speaker/speaker-builder/speaker-builder.component.ts +0 -40
- package/src/lib/components/lesson-mini-components/components/speaker/speaker.component.html +0 -9
- package/src/lib/components/lesson-mini-components/components/speaker/speaker.component.scss +0 -3
- package/src/lib/components/lesson-mini-components/components/speaker/speaker.component.ts +0 -33
- package/src/lib/components/lesson-mini-components/components/text-writer/text-writer-buider/text-writer-buider.component.html +0 -24
- package/src/lib/components/lesson-mini-components/components/text-writer/text-writer-buider/text-writer-buider.component.scss +0 -15
- package/src/lib/components/lesson-mini-components/components/text-writer/text-writer-buider/text-writer-buider.component.spec.ts +0 -25
- package/src/lib/components/lesson-mini-components/components/text-writer/text-writer-buider/text-writer-buider.component.ts +0 -29
- package/src/lib/components/lesson-mini-components/components/text-writer/text-writer.component.html +0 -4
- package/src/lib/components/lesson-mini-components/components/text-writer/text-writer.component.scss +0 -8
- package/src/lib/components/lesson-mini-components/components/text-writer/text-writer.component.spec.ts +0 -25
- package/src/lib/components/lesson-mini-components/components/text-writer/text-writer.component.ts +0 -61
- package/src/lib/components/lesson-mini-components/components/translationSwitcher/translationSwitcher.component.css +0 -3
- package/src/lib/components/lesson-mini-components/components/translationSwitcher/translationSwitcher.component.html +0 -9
- package/src/lib/components/lesson-mini-components/components/translationSwitcher/translationSwitcher.component.ts +0 -32
- package/src/lib/components/lesson-mini-components/components/translationSwitcher/translationSwitcherBuilder/translationSwitcherBuilder.component.css +0 -3
- package/src/lib/components/lesson-mini-components/components/translationSwitcher/translationSwitcherBuilder/translationSwitcherBuilder.component.html +0 -28
- package/src/lib/components/lesson-mini-components/components/translationSwitcher/translationSwitcherBuilder/translationSwitcherBuilder.component.ts +0 -30
- package/src/lib/components/lesson-mini-components/components/verb-summary/verb-summary-builder/verb-summary-builder.component.html +0 -18
- package/src/lib/components/lesson-mini-components/components/verb-summary/verb-summary-builder/verb-summary-builder.component.scss +0 -3
- package/src/lib/components/lesson-mini-components/components/verb-summary/verb-summary-builder/verb-summary-builder.component.spec.ts +0 -25
- package/src/lib/components/lesson-mini-components/components/verb-summary/verb-summary-builder/verb-summary-builder.component.ts +0 -25
- package/src/lib/components/lesson-mini-components/components/verb-summary/verb-summary.component.html +0 -15
- package/src/lib/components/lesson-mini-components/components/verb-summary/verb-summary.component.scss +0 -27
- package/src/lib/components/lesson-mini-components/components/verb-summary/verb-summary.component.spec.ts +0 -25
- package/src/lib/components/lesson-mini-components/components/verb-summary/verb-summary.component.ts +0 -46
- package/src/lib/components/lesson-mini-components/components/word-summary/word-summary-builder/word-summary-builder.component.html +0 -19
- package/src/lib/components/lesson-mini-components/components/word-summary/word-summary-builder/word-summary-builder.component.scss +0 -0
- package/src/lib/components/lesson-mini-components/components/word-summary/word-summary-builder/word-summary-builder.component.ts +0 -27
- package/src/lib/components/lesson-mini-components/components/word-summary/word-summary.component.html +0 -14
- package/src/lib/components/lesson-mini-components/components/word-summary/word-summary.component.scss +0 -22
- package/src/lib/components/lesson-mini-components/components/word-summary/word-summary.component.ts +0 -51
- package/src/lib/models/lessons.pipes.ts +0 -38
- package/src/lib/models/models.ts +0 -92
- package/src/lib/models/notion.models.ts +0 -43
- package/src/lib/services/lesson-ai.service.ts +0 -103
- package/src/lib/services/lesson-notion.service.ts +0 -161
- package/src/lib/services/lesson-utils.service.ts +0 -181
- package/src/public-api.ts +0 -25
|
@@ -1,332 +0,0 @@
|
|
|
1
|
-
import { Component, ComponentRef, ElementRef, Renderer2, ViewChild, ViewContainerRef, computed, effect, inject, input, signal } from '@angular/core'; // Added signal imports
|
|
2
|
-
import { FormGroup, FormControl, Validators } from '@angular/forms'; // Use typed forms
|
|
3
|
-
import { KeyValuePipe } from '@angular/common';
|
|
4
|
-
import { ButtonModule } from 'primeng/button';
|
|
5
|
-
import { LessonAIService } from '../../../services/lesson-ai.service'; // Import the new service
|
|
6
|
-
|
|
7
|
-
import {
|
|
8
|
-
getLessonComponentClass,
|
|
9
|
-
ILesson,
|
|
10
|
-
LessonComponentConfiguration,
|
|
11
|
-
LessonComponentsType,
|
|
12
|
-
LESSONS_TOKEN,
|
|
13
|
-
LessonsAbstractService,
|
|
14
|
-
} from '../../lesson-mini-components/components/lessons.clases';
|
|
15
|
-
|
|
16
|
-
import { TOAST_ALERTS_TOKEN, ToastAlertsAbstractService } from '@dataclouder/ngx-core';
|
|
17
|
-
import { LessonComponentInterface } from '../../lesson-mini-components/components/lessons.clases';
|
|
18
|
-
import { DCChatComponent, IAgentCard, IMiniAgentCard } from '@dataclouder/ngx-agent-cards';
|
|
19
|
-
|
|
20
|
-
import { DrawerModule } from 'primeng/drawer';
|
|
21
|
-
|
|
22
|
-
@Component({
|
|
23
|
-
selector: 'dc-lesson-renderer',
|
|
24
|
-
templateUrl: './dc-lesson-renderer.component.html',
|
|
25
|
-
styleUrls: ['./dc-lesson-renderer.component.scss'],
|
|
26
|
-
standalone: true,
|
|
27
|
-
imports: [KeyValuePipe, ButtonModule, DCChatComponent, DrawerModule],
|
|
28
|
-
})
|
|
29
|
-
export class DCLessonRendererComponent {
|
|
30
|
-
// --- Signal Inputs ---
|
|
31
|
-
lessonInput = input<ILesson>(); // Input signal for lesson object
|
|
32
|
-
lessonIdInput = input<string>(); // Input signal for lesson ID
|
|
33
|
-
test = input<boolean>(false);
|
|
34
|
-
|
|
35
|
-
// --- View Childs ---
|
|
36
|
-
@ViewChild('dynamicLesson', { static: true }) dynamicLesson: ElementRef<HTMLElement>;
|
|
37
|
-
|
|
38
|
-
// --- Injected Services (using inject function) ---
|
|
39
|
-
private readonly renderer = inject(Renderer2);
|
|
40
|
-
private readonly viewContainerRef = inject(ViewContainerRef);
|
|
41
|
-
private readonly toastrService = inject<ToastAlertsAbstractService>(TOAST_ALERTS_TOKEN);
|
|
42
|
-
private readonly lessonService = inject<LessonsAbstractService>(LESSONS_TOKEN);
|
|
43
|
-
private readonly lessonAIService = inject(LessonAIService); // Inject the new service
|
|
44
|
-
|
|
45
|
-
// --- State Signals ---
|
|
46
|
-
lesson = signal<ILesson | undefined>(undefined); // Internal lesson state signal
|
|
47
|
-
chatVisible = signal(false); // Signal for chat visibility
|
|
48
|
-
agentMasterLesson = signal<IAgentCard | undefined>(undefined); // Signal for agent card
|
|
49
|
-
evaluatorAgentCard = signal<IMiniAgentCard | undefined>(undefined); // Signal for evaluator card
|
|
50
|
-
|
|
51
|
-
// --- Computed Signals ---
|
|
52
|
-
imageCover = computed(() => this.lesson()?.media?.images?.find((img) => img.type === 'cover')?.url); // Computed signal for imageCover
|
|
53
|
-
|
|
54
|
-
// --- Properties ---
|
|
55
|
-
private components: { [key: string]: ComponentRef<LessonComponentInterface> } = {};
|
|
56
|
-
public mainForm: FormGroup<{ [key: string]: FormControl<any> }> = new FormGroup({});
|
|
57
|
-
|
|
58
|
-
constructor() {
|
|
59
|
-
// Effect to fetch lesson data if ID is provided and lesson object isn't
|
|
60
|
-
effect(
|
|
61
|
-
async () => {
|
|
62
|
-
const lessonInput = this.lessonInput();
|
|
63
|
-
const lessonId = this.lessonIdInput();
|
|
64
|
-
|
|
65
|
-
if (lessonInput) {
|
|
66
|
-
this.lesson.set(lessonInput); // Use input lesson directly
|
|
67
|
-
} else if (lessonId && !this.lesson()) {
|
|
68
|
-
// Fetch only if ID exists and internal lesson is not set
|
|
69
|
-
console.log(`Fetching lesson with ID: ${lessonId}`);
|
|
70
|
-
try {
|
|
71
|
-
// Consider adding a loading state signal here
|
|
72
|
-
const fetchedLesson = await this.lessonService.getLesson(lessonId);
|
|
73
|
-
this.lesson.set(fetchedLesson);
|
|
74
|
-
console.log('Fetched lesson:', fetchedLesson);
|
|
75
|
-
} catch (error) {
|
|
76
|
-
console.error(`Failed to fetch lesson with ID: ${lessonId}`, error);
|
|
77
|
-
this.toastrService.error({ subtitle: 'Failed to load lesson data.', title: 'Error' });
|
|
78
|
-
this.lesson.set(undefined); // Reset lesson on error
|
|
79
|
-
} finally {
|
|
80
|
-
// Reset loading state signal here
|
|
81
|
-
}
|
|
82
|
-
} else if (!lessonInput && !lessonId) {
|
|
83
|
-
// Handle case where neither input is provided, maybe clear the lesson?
|
|
84
|
-
this.lesson.set(undefined);
|
|
85
|
-
}
|
|
86
|
-
},
|
|
87
|
-
{ allowSignalWrites: true },
|
|
88
|
-
); // Allow signal writes inside effect
|
|
89
|
-
|
|
90
|
-
// Effect to render the lesson whenever the lesson signal changes
|
|
91
|
-
effect(() => {
|
|
92
|
-
const currentLesson = this.lesson();
|
|
93
|
-
if (currentLesson) {
|
|
94
|
-
this._renderLesson(currentLesson);
|
|
95
|
-
} else {
|
|
96
|
-
// Clear previous rendering if lesson becomes undefined
|
|
97
|
-
this._clearLessonRendering();
|
|
98
|
-
}
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// --- Rendering Logic ---
|
|
103
|
-
|
|
104
|
-
private _clearLessonRendering(): void {
|
|
105
|
-
// Destroy previously created dynamic components
|
|
106
|
-
Object.values(this.components).forEach((compRef) => compRef.destroy());
|
|
107
|
-
this.components = {};
|
|
108
|
-
// Clear the form
|
|
109
|
-
this.mainForm = new FormGroup({});
|
|
110
|
-
// Clear the HTML content
|
|
111
|
-
if (this.dynamicLesson?.nativeElement) {
|
|
112
|
-
this.dynamicLesson.nativeElement.innerHTML = '';
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
private _renderLesson(lessonData: ILesson): void {
|
|
117
|
-
this._clearLessonRendering(); // Clear previous state first
|
|
118
|
-
|
|
119
|
-
console.log('Rendering lesson:', lessonData.id);
|
|
120
|
-
// console.log('Image cover URL:', this.imageCover()); // Access computed signal
|
|
121
|
-
|
|
122
|
-
// 1) Parse textCoded, create components, and build HTML structure
|
|
123
|
-
const { htmlContent, components } = this._parseAndCreateComponents(lessonData);
|
|
124
|
-
this.components = components;
|
|
125
|
-
|
|
126
|
-
// 2) Aggregate form controls from created components
|
|
127
|
-
this._aggregateFormControls(this.components);
|
|
128
|
-
|
|
129
|
-
// 3) Set the innerHTML of the target element
|
|
130
|
-
this.dynamicLesson.nativeElement.innerHTML = htmlContent;
|
|
131
|
-
|
|
132
|
-
// 4) Inject the component views into the DOM
|
|
133
|
-
this._injectComponentsIntoDom(this.components);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
private _parseAndCreateComponents(lessonData: ILesson): { htmlContent: string; components: { [key: string]: ComponentRef<LessonComponentInterface> } } {
|
|
137
|
-
const r1 = new RegExp('~(.+?)~', 'g');
|
|
138
|
-
let count = 0;
|
|
139
|
-
const createdComponents: { [key: string]: ComponentRef<LessonComponentInterface> } = {};
|
|
140
|
-
|
|
141
|
-
const htmlContent = lessonData.textCoded.replace(r1, (_matching, jsonCoded) => {
|
|
142
|
-
const componentName = `dynamicComp${count}`;
|
|
143
|
-
count++;
|
|
144
|
-
const componentRef = this._createComponentReferenceWithJson(jsonCoded, lessonData);
|
|
145
|
-
if (!componentRef) {
|
|
146
|
-
console.error(`Failed to create component for: ${jsonCoded}`);
|
|
147
|
-
return '<!-- component creation failed -->'; // Placeholder in HTML
|
|
148
|
-
}
|
|
149
|
-
createdComponents[componentName] = componentRef;
|
|
150
|
-
return `<span id="${componentName}"></span>`; // Return span placeholder
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
return { htmlContent, components: createdComponents };
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
private _aggregateFormControls(components: { [key: string]: ComponentRef<LessonComponentInterface> }): void {
|
|
157
|
-
const newFormControls: { [key: string]: FormControl<any> } = {};
|
|
158
|
-
Object.entries(components).forEach(([name, componentRef]) => {
|
|
159
|
-
// Check if the instance has a control property that is a FormControl
|
|
160
|
-
if (componentRef.instance?.control instanceof FormControl) {
|
|
161
|
-
newFormControls[name] = componentRef.instance.control;
|
|
162
|
-
// Add required validator (consider making this configurable via component config?)
|
|
163
|
-
newFormControls[name].addValidators(Validators.required);
|
|
164
|
-
}
|
|
165
|
-
});
|
|
166
|
-
this.mainForm = new FormGroup(newFormControls); // Create the typed FormGroup
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
private _injectComponentsIntoDom(components: { [key: string]: ComponentRef<LessonComponentInterface> }): void {
|
|
170
|
-
Object.entries(components).forEach(([name, componentRef]) => {
|
|
171
|
-
const elementRef = document.getElementById(name); // Find the placeholder span
|
|
172
|
-
if (elementRef) {
|
|
173
|
-
this._addComponentToNode(componentRef, elementRef);
|
|
174
|
-
} else {
|
|
175
|
-
console.warn(`Placeholder element with ID '${name}' not found in the DOM.`);
|
|
176
|
-
}
|
|
177
|
-
});
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
private _addComponentToNode(componentRef: ComponentRef<LessonComponentInterface>, nodeDOM: HTMLElement): void {
|
|
181
|
-
this.renderer.appendChild(nodeDOM, componentRef.location.nativeElement);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
private _createComponentReferenceWithJson(json: string, currentLesson: ILesson): ComponentRef<LessonComponentInterface> | null {
|
|
185
|
-
try {
|
|
186
|
-
let lessonCodedConfig: LessonComponentConfiguration = JSON.parse(json);
|
|
187
|
-
debugger;
|
|
188
|
-
// Attempt to find pre-configured component data in the lesson object by ID
|
|
189
|
-
if (lessonCodedConfig.id && currentLesson?.dynamicComponents[lessonCodedConfig.id]) {
|
|
190
|
-
const foundConfig = currentLesson.dynamicComponents[lessonCodedConfig.id];
|
|
191
|
-
if (foundConfig) {
|
|
192
|
-
// Merge configurations: Start with coded, override/add with found lesson config
|
|
193
|
-
lessonCodedConfig = { ...lessonCodedConfig, ...foundConfig };
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
const LessonClass = getLessonComponentClass(<LessonComponentsType>lessonCodedConfig.component);
|
|
198
|
-
|
|
199
|
-
if (!LessonClass) {
|
|
200
|
-
console.error(`Component class not found for type: ${lessonCodedConfig.component}. JSON: ${json}`);
|
|
201
|
-
return null; // Return null if class doesn't exist
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
// Create component instance
|
|
205
|
-
const componentRef = this.viewContainerRef.createComponent<LessonComponentInterface>(LessonClass);
|
|
206
|
-
|
|
207
|
-
if (lessonCodedConfig.inputs) {
|
|
208
|
-
for (const key in lessonCodedConfig.inputs) {
|
|
209
|
-
if (lessonCodedConfig.inputs.hasOwnProperty(key)) {
|
|
210
|
-
componentRef.instance[key] = lessonCodedConfig.inputs[key];
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
// i think i can improve this to pass only settings not all config, Assign the configuration to the component instance
|
|
215
|
-
// settings data i defined in form interface, config will be all the component data including id and component type
|
|
216
|
-
if (lessonCodedConfig.settings) {
|
|
217
|
-
componentRef.instance.config = lessonCodedConfig;
|
|
218
|
-
}
|
|
219
|
-
return componentRef;
|
|
220
|
-
} catch (error) {
|
|
221
|
-
console.error(`Error processing component JSON: ${json}`, error);
|
|
222
|
-
return null; // Return null on JSON parsing or other errors
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
// --- Evaluation Logic ---
|
|
227
|
-
|
|
228
|
-
public async evaluateForms() {
|
|
229
|
-
this.mainForm.markAllAsTouched(); // Mark all controls for validation feedback
|
|
230
|
-
|
|
231
|
-
if (!this.mainForm.valid) {
|
|
232
|
-
// Trigger validation feedback on individual components visually if needed
|
|
233
|
-
Object.keys(this.mainForm.controls).forEach((controlName) => {
|
|
234
|
-
if (this.components[controlName]?.instance?.validate) {
|
|
235
|
-
this.components[controlName].instance.validate(); // Assuming validate method handles visual feedback
|
|
236
|
-
}
|
|
237
|
-
});
|
|
238
|
-
this.toastrService.warn({ subtitle: 'Por favor completa todos los ejercicios', title: 'Incompleto' });
|
|
239
|
-
return;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
const rates = { correct: 0, incorrect: 0, score: 0 };
|
|
243
|
-
|
|
244
|
-
// Evaluate each component associated with a form control
|
|
245
|
-
Object.keys(this.mainForm.controls).forEach((controlName) => {
|
|
246
|
-
const instance = this.components[controlName]?.instance;
|
|
247
|
-
// Check if the instance has an evaluate method (duck typing is okay here)
|
|
248
|
-
if (instance && typeof instance.evaluate === 'function') {
|
|
249
|
-
try {
|
|
250
|
-
const result = instance.evaluate();
|
|
251
|
-
if (result) {
|
|
252
|
-
rates.correct++;
|
|
253
|
-
} else {
|
|
254
|
-
rates.incorrect++;
|
|
255
|
-
}
|
|
256
|
-
} catch (err) {
|
|
257
|
-
console.error('Error during evaluation for component:', controlName, instance, err);
|
|
258
|
-
rates.incorrect++; // Count errors as incorrect
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
});
|
|
262
|
-
|
|
263
|
-
if (this.test()) {
|
|
264
|
-
// Access signal value
|
|
265
|
-
console.log('Test mode: Evaluation skipped saving.');
|
|
266
|
-
this.toastrService.info({ subtitle: `Test Results: ${rates.correct} correct, ${rates.incorrect} incorrect`, title: 'Test Mode' });
|
|
267
|
-
return;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
const totalQuestions = rates.correct + rates.incorrect;
|
|
271
|
-
rates.score = totalQuestions > 0 ? rates.correct / totalQuestions : 0; // Avoid division by zero
|
|
272
|
-
|
|
273
|
-
const status = rates.score >= 0.7 ? 'passed' : 'failed'; // Use >= for threshold
|
|
274
|
-
|
|
275
|
-
const currentLesson = this.lesson();
|
|
276
|
-
if (!currentLesson) {
|
|
277
|
-
console.error('Cannot save result, lesson data is missing.');
|
|
278
|
-
this.toastrService.error({ subtitle: 'Cannot save result, lesson data missing.', title: 'Error' });
|
|
279
|
-
return;
|
|
280
|
-
}
|
|
281
|
-
const takenLesson = { lessonId: currentLesson.id, status: status, score: rates.score };
|
|
282
|
-
|
|
283
|
-
console.log('Lesson evaluation result:', takenLesson);
|
|
284
|
-
// TODO: Re-implement saving the taken lesson status via lessonService
|
|
285
|
-
// try {
|
|
286
|
-
// await this.lessonService.saveTakenLesson(takenLesson);
|
|
287
|
-
// if (status === 'passed') {
|
|
288
|
-
// this.toastrService.success({ subtitle: `Calificación: ${Math.round(rates.score * 100)}%. Se guardó tu progreso.`, title: '¡Muy bien!' });
|
|
289
|
-
// } else {
|
|
290
|
-
// this.toastrService.warn({ subtitle: `Calificación: ${Math.round(rates.score * 100)}%. Revisa tus respuestas.`, title: 'Casi lo logras' });
|
|
291
|
-
// }
|
|
292
|
-
// } catch (error) {
|
|
293
|
-
// console.error('Failed to save taken lesson', error);
|
|
294
|
-
// this.toastrService.error({ subtitle: 'No se pudo guardar tu progreso.', title: 'Error' });
|
|
295
|
-
// }
|
|
296
|
-
if (status === 'passed') {
|
|
297
|
-
this.toastrService.success({ subtitle: `Calificación: ${Math.round(rates.score * 100)}%.`, title: '¡Muy bien!' });
|
|
298
|
-
} else {
|
|
299
|
-
this.toastrService.warn({ subtitle: `Calificación: ${Math.round(rates.score * 100)}%. Revisa tus respuestas.`, title: 'Casi lo logras' });
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
// --- AI Chat Logic ---
|
|
304
|
-
|
|
305
|
-
public async startAI() {
|
|
306
|
-
const currentLesson = this.lesson();
|
|
307
|
-
if (!currentLesson) {
|
|
308
|
-
console.error('Cannot start AI without a lesson.');
|
|
309
|
-
this.toastrService.error({ subtitle: 'Lesson data not available.', title: 'Cannot Start Chat' });
|
|
310
|
-
return;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
console.log('Requesting agent cards from LessonAIService...');
|
|
314
|
-
try {
|
|
315
|
-
// Call the service to get the agent cards
|
|
316
|
-
const agentCards = await this.lessonAIService.generateAgentCards(currentLesson);
|
|
317
|
-
|
|
318
|
-
if (agentCards) {
|
|
319
|
-
this.agentMasterLesson.set(agentCards.masterAgent);
|
|
320
|
-
this.evaluatorAgentCard.set(agentCards.evaluatorAgent);
|
|
321
|
-
this.chatVisible.set(true);
|
|
322
|
-
console.log('Agent cards received and set.');
|
|
323
|
-
} else {
|
|
324
|
-
console.error('Failed to generate agent cards (service returned null).');
|
|
325
|
-
this.toastrService.error({ subtitle: 'Could not prepare the AI chat session.', title: 'Error' });
|
|
326
|
-
}
|
|
327
|
-
} catch (error) {
|
|
328
|
-
console.error('Error generating agent cards:', error);
|
|
329
|
-
this.toastrService.error({ subtitle: 'An error occurred while preparing the AI chat.', title: 'Error' });
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { Component } from '@angular/core';
|
|
2
|
-
|
|
3
|
-
import { ReactiveFormsModule } from '@angular/forms';
|
|
4
|
-
|
|
5
|
-
@Component({
|
|
6
|
-
selector: 'dc-lesson-form',
|
|
7
|
-
templateUrl: './lesson-form.component.html',
|
|
8
|
-
styleUrls: ['./lesson-form.component.scss'],
|
|
9
|
-
standalone: true,
|
|
10
|
-
imports: [ReactiveFormsModule],
|
|
11
|
-
})
|
|
12
|
-
export class DCLessonFormComponent {
|
|
13
|
-
// Form implementation will go here
|
|
14
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
<dc-filter-bar [customFilters]="customFilters" (onFilterAction)="applyFilterBarEvent($event)" (onNew)="newLesson()"></dc-filter-bar>
|
|
2
|
-
|
|
3
|
-
@if(viewType === 'table') {
|
|
4
|
-
<app-quick-table [columns]="columns" [tableData]="lessons" (onAction)="doOrEmitAction($event)"></app-quick-table>
|
|
5
|
-
} @else {
|
|
6
|
-
<div class="lesson-list-container">
|
|
7
|
-
@if (!isLoadingLessons && lessons?.length > 0) { @for (lesson of lessons; track lesson._id) {
|
|
8
|
-
<ng-container
|
|
9
|
-
#outlet="ngComponentOutlet"
|
|
10
|
-
[ngComponentOutlet]="cardComponent"
|
|
11
|
-
[ngComponentOutletInputs]="{
|
|
12
|
-
lesson: lesson,
|
|
13
|
-
showOptions: showOptions
|
|
14
|
-
}">
|
|
15
|
-
</ng-container>
|
|
16
|
-
} } @else {
|
|
17
|
-
<p>No se encontraron lecciones disponibles</p>
|
|
18
|
-
}
|
|
19
|
-
</div>
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
<p-paginator
|
|
23
|
-
currentPageReportTemplate="{{ totalRecords }} lecciones"
|
|
24
|
-
[showCurrentPageReport]="true"
|
|
25
|
-
(onPageChange)="onPageChange($event)"
|
|
26
|
-
[first]="paginatorFirst"
|
|
27
|
-
[rows]="paginatorRows"
|
|
28
|
-
[totalRecords]="totalRecords"
|
|
29
|
-
[rowsPerPageOptions]="[10, 20, 30]">
|
|
30
|
-
</p-paginator>
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
:host {
|
|
2
|
-
display: flex;
|
|
3
|
-
flex-direction: column;
|
|
4
|
-
height: 100%;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
.lesson-list-container {
|
|
8
|
-
padding: 1rem;
|
|
9
|
-
flex: 1;
|
|
10
|
-
overflow-y: auto;
|
|
11
|
-
min-height: 0; /* This is important for flex containers to respect overflow */
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
p-paginator {
|
|
15
|
-
margin-top: auto;
|
|
16
|
-
padding: 0.5rem 1rem;
|
|
17
|
-
}
|
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
import { ChangeDetectorRef, Component, EventEmitter, Inject, Input, OnInit, Output, Type, ViewChildren, QueryList, OnDestroy, input } from '@angular/core';
|
|
2
|
-
|
|
3
|
-
import { PaginatorModule } from 'primeng/paginator';
|
|
4
|
-
import { NgComponentOutlet } from '@angular/common';
|
|
5
|
-
import { ActivatedRoute, Router, RouterModule } from '@angular/router';
|
|
6
|
-
|
|
7
|
-
import { Subscription } from 'rxjs';
|
|
8
|
-
import {
|
|
9
|
-
DCFilterBarComponent,
|
|
10
|
-
ICustomFilter,
|
|
11
|
-
OnActionEvent,
|
|
12
|
-
PaginationBase,
|
|
13
|
-
PColumn,
|
|
14
|
-
QuickTableComponent,
|
|
15
|
-
TOAST_ALERTS_TOKEN,
|
|
16
|
-
ToastAlertsAbstractService,
|
|
17
|
-
} from '@dataclouder/ngx-core';
|
|
18
|
-
|
|
19
|
-
import { LESSONS_TOKEN, LessonsAbstractService } from '../../lesson-mini-components/components/lessons.clases';
|
|
20
|
-
import { DcLessonCardComponent } from '../dc-lesson-card/dc-lesson-card.component';
|
|
21
|
-
import { MenuItem } from 'node_modules/primeng/api/menuitem';
|
|
22
|
-
|
|
23
|
-
const tableViewColumns: PColumn[] = [
|
|
24
|
-
{ field: 'media.images[0].url', header: 'Image', type: 'image' },
|
|
25
|
-
{ field: 'title', header: 'Título' },
|
|
26
|
-
{ field: 'description', header: 'Descripción' },
|
|
27
|
-
];
|
|
28
|
-
|
|
29
|
-
const TableViewActions: MenuItem[] = [
|
|
30
|
-
{ title: 'select', label: 'Select', icon: 'pi pi-check', severity: 'primary' },
|
|
31
|
-
{ title: 'qr', label: 'QR', icon: 'pi pi-qrcode', severity: 'info' },
|
|
32
|
-
{ title: 'edit', label: 'Edit', icon: 'pi pi-pencil', severity: 'info' },
|
|
33
|
-
{ title: 'delete', label: 'Delete', icon: 'pi pi-trash', severity: 'danger' },
|
|
34
|
-
];
|
|
35
|
-
|
|
36
|
-
const returnProperties: Record<string, 0 | 1> = { id: 1, title: 1, assets: 1 };
|
|
37
|
-
|
|
38
|
-
@Component({
|
|
39
|
-
selector: 'dc-lesson-list',
|
|
40
|
-
templateUrl: './dc-lesson-list.component.html',
|
|
41
|
-
styleUrls: ['./dc-lesson-list.component.scss'],
|
|
42
|
-
standalone: true,
|
|
43
|
-
imports: [RouterModule, DCFilterBarComponent, PaginatorModule, NgComponentOutlet, QuickTableComponent],
|
|
44
|
-
})
|
|
45
|
-
export class DCLessonListComponent extends PaginationBase implements OnInit, OnDestroy {
|
|
46
|
-
@Input() public showOptions: boolean = true;
|
|
47
|
-
@Input() public customCardComponent?: Type<DcLessonCardComponent>;
|
|
48
|
-
@Input() public customFilters: ICustomFilter[] = [];
|
|
49
|
-
@Input() public viewType: 'table' | 'cards' = 'cards';
|
|
50
|
-
|
|
51
|
-
// readonly actions = input<MenuItem[]>(TableViewActions);
|
|
52
|
-
|
|
53
|
-
public override columns: PColumn[] = tableViewColumns;
|
|
54
|
-
|
|
55
|
-
@ViewChildren('outlet') outlets!: QueryList<NgComponentOutlet>;
|
|
56
|
-
|
|
57
|
-
public cardComponent: Type<DcLessonCardComponent> = null;
|
|
58
|
-
public cardEventSubs: Subscription[] = [];
|
|
59
|
-
|
|
60
|
-
public lessons: any[] = [];
|
|
61
|
-
public isLoadingLessons = false;
|
|
62
|
-
|
|
63
|
-
constructor(
|
|
64
|
-
private cdr: ChangeDetectorRef,
|
|
65
|
-
public override router: Router,
|
|
66
|
-
public override route: ActivatedRoute,
|
|
67
|
-
@Inject(LESSONS_TOKEN) private lessonsService: LessonsAbstractService,
|
|
68
|
-
@Inject(TOAST_ALERTS_TOKEN) private toastrService: ToastAlertsAbstractService,
|
|
69
|
-
) {
|
|
70
|
-
super(route, router);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
ngOnInit(): void {
|
|
74
|
-
this.filterConfig.returnProps = returnProperties;
|
|
75
|
-
this.cardComponent = this.customCardComponent || DcLessonCardComponent;
|
|
76
|
-
|
|
77
|
-
this.getPaginatedLessons(this.filterConfig);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
public subscribeDinamicInstantToEvents() {
|
|
81
|
-
this.clearcardEventSubs();
|
|
82
|
-
this.subscribeToCardEvents();
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
private subscribeToCardEvents() {
|
|
86
|
-
this.outlets.forEach((outlet) => {
|
|
87
|
-
const instance: DcLessonCardComponent = outlet.componentInstance;
|
|
88
|
-
|
|
89
|
-
this.cardEventSubs.push(
|
|
90
|
-
instance.onAction.subscribe((lesson: any) => {
|
|
91
|
-
this.doOrEmitAction(lesson);
|
|
92
|
-
}),
|
|
93
|
-
);
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
private clearcardEventSubs() {
|
|
98
|
-
this.cardEventSubs.forEach((sub) => sub.unsubscribe());
|
|
99
|
-
this.cardEventSubs = [];
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
ngOnDestroy() {
|
|
103
|
-
this.clearcardEventSubs();
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
public async getPaginatedLessons(paginator: any) {
|
|
107
|
-
try {
|
|
108
|
-
this.lessons = null;
|
|
109
|
-
this.isLoadingLessons = true;
|
|
110
|
-
this.cdr.detectChanges();
|
|
111
|
-
const lessons = await this.lessonsService.getLessons(paginator);
|
|
112
|
-
|
|
113
|
-
this.lessons = lessons['rows'] || lessons;
|
|
114
|
-
this.totalRecords = lessons['count'] || this.lessons.length;
|
|
115
|
-
|
|
116
|
-
console.log('lessons', lessons);
|
|
117
|
-
|
|
118
|
-
setTimeout(() => {
|
|
119
|
-
this.subscribeDinamicInstantToEvents();
|
|
120
|
-
});
|
|
121
|
-
} finally {
|
|
122
|
-
this.isLoadingLessons = false;
|
|
123
|
-
this.cdr.detectChanges();
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
public search(searchText: string) {
|
|
128
|
-
this.filterConfig['text'] = searchText;
|
|
129
|
-
this.getPaginatedLessons(this.filterConfig);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
private removeLesson(lesson: any) {
|
|
133
|
-
const response = confirm('¿Estás seguro de querer eliminar esta lección?');
|
|
134
|
-
if (response) {
|
|
135
|
-
this.lessonsService.deleteLesson(lesson._id);
|
|
136
|
-
this.lessons = this.lessons.filter((l) => l._id !== lesson._id);
|
|
137
|
-
this.cdr.detectChanges();
|
|
138
|
-
this.toastrService.success({ title: 'Adios a la lección', subtitle: 'La lección ha sido eliminada correctamente' });
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
public newLesson() {
|
|
143
|
-
this.onAction.emit({ action: 'new' });
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
public applyFilterBarEvent(filterEvent: OnActionEvent) {
|
|
147
|
-
if (filterEvent.action == 'changeView') {
|
|
148
|
-
this.viewType = this.viewType === 'table' ? 'cards' : 'table';
|
|
149
|
-
return;
|
|
150
|
-
} else {
|
|
151
|
-
console.log('filterChanged in dc-lesson-list', filterEvent);
|
|
152
|
-
this.filterConfig = filterEvent.item;
|
|
153
|
-
this.filterConfig.returnProps = returnProperties;
|
|
154
|
-
|
|
155
|
-
this.getPaginatedLessons(this.filterConfig);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
protected override loadData(): Promise<void> {
|
|
160
|
-
return this.getPaginatedLessons(this.filterConfig);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
public doOrEmitAction(actionEvent: OnActionEvent) {
|
|
164
|
-
if (actionEvent.action === 'delete') {
|
|
165
|
-
this.removeLesson(actionEvent.item);
|
|
166
|
-
} else {
|
|
167
|
-
this.onAction.emit(actionEvent);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { Component } from '@angular/core';
|
|
2
|
-
import { RouterOutlet } from '@angular/router';
|
|
3
|
-
|
|
4
|
-
@Component({
|
|
5
|
-
selector: 'app-lessonsv2',
|
|
6
|
-
template: '<router-outlet></router-outlet>',
|
|
7
|
-
standalone: true,
|
|
8
|
-
imports: [RouterOutlet],
|
|
9
|
-
})
|
|
10
|
-
export class LessonsV2Component {}
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import { Component } from '@angular/core';
|
|
2
|
-
import { FormBuilder, FormControl } from '@angular/forms';
|
|
3
|
-
import { DynamicDialogRef } from 'primeng/dynamicdialog';
|
|
4
|
-
|
|
5
|
-
import { LessonComponentBuilders, LessonComponentConfiguration, LessonComponentEnum, LessonCompSettings } from './lessons.clases';
|
|
6
|
-
import { nanoid } from 'nanoid';
|
|
7
|
-
|
|
8
|
-
// Create a type that maps the interface to FormControls
|
|
9
|
-
export type LessonCompSettingsForm = {
|
|
10
|
-
[K in keyof Required<LessonCompSettings>]: FormControl<LessonCompSettings[K]>;
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
export interface ComponentBuildData {
|
|
14
|
-
str: string;
|
|
15
|
-
obj: LessonComponentConfiguration;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
@Component({
|
|
19
|
-
selector: 'app-component-builder',
|
|
20
|
-
template: '<div>no template</div>',
|
|
21
|
-
})
|
|
22
|
-
export class ComponentBuilder {
|
|
23
|
-
constructor(protected formBuilder: FormBuilder, protected ref: DynamicDialogRef) {}
|
|
24
|
-
|
|
25
|
-
// Sobreescribir si es necesario
|
|
26
|
-
// public formGroup = this.formBuilder.group<LessonCompSettings>({});
|
|
27
|
-
|
|
28
|
-
public formGroup = this.formBuilder.group({
|
|
29
|
-
response: new FormControl<string | null>(null),
|
|
30
|
-
responses: new FormControl<string | null>(null),
|
|
31
|
-
options: this.formBuilder.array([]),
|
|
32
|
-
text: new FormControl<string | null>(null),
|
|
33
|
-
hint: new FormControl<string | null>(null),
|
|
34
|
-
explanation: new FormControl<string | null>(null),
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
// Every component knows its type by comparing agains LessonComponentBuilders
|
|
38
|
-
get questionType(): LessonComponentEnum {
|
|
39
|
-
const self = this;
|
|
40
|
-
|
|
41
|
-
const name = Object.keys(LessonComponentBuilders).find((componentName: any) => {
|
|
42
|
-
const componentClass = LessonComponentBuilders[componentName];
|
|
43
|
-
if (self instanceof componentClass) {
|
|
44
|
-
return componentName;
|
|
45
|
-
}
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
return <LessonComponentEnum>name;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
protected getCode(): LessonComponentConfiguration {
|
|
52
|
-
const data = this.formGroup.value;
|
|
53
|
-
// Deleting null values
|
|
54
|
-
Object.keys(data).forEach((key) => {
|
|
55
|
-
if (data[key] === null) {
|
|
56
|
-
delete data[key];
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
const code: LessonComponentConfiguration = { component: this.questionType, settings: { ...data } as unknown as LessonCompSettings };
|
|
60
|
-
return code;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
public showCode() {
|
|
64
|
-
const code = this.getCode();
|
|
65
|
-
const stringCode = `~${JSON.stringify(code)}~`;
|
|
66
|
-
alert(stringCode);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
public getComponentData(): ComponentBuildData {
|
|
70
|
-
const code = this.getCode();
|
|
71
|
-
const id = nanoid().replace(/-/g, '_');
|
|
72
|
-
code.id = id;
|
|
73
|
-
return { str: `~${JSON.stringify(code)}~`, obj: code };
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// TODO: for now copyToClipboard is the that that closes modal and return data.
|
|
77
|
-
public async copyToClipboard() {
|
|
78
|
-
const data = this.getComponentData();
|
|
79
|
-
await navigator.clipboard.writeText(data.str);
|
|
80
|
-
this.ref.close(data);
|
|
81
|
-
}
|
|
82
|
-
}
|