@dataclouder/ngx-lessons 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/fesm2022/dataclouder-ngx-lessons.mjs +1020 -1008
  2. package/fesm2022/dataclouder-ngx-lessons.mjs.map +1 -1
  3. package/index.d.ts +706 -5
  4. package/package.json +1 -1
  5. package/lib/components/courses/course-detail/course-detail.component.d.ts +0 -5
  6. package/lib/components/courses/course-form/course-form.component.d.ts +0 -35
  7. package/lib/components/courses/course-list/course-list.component.d.ts +0 -25
  8. package/lib/components/courses/courses.component.d.ts +0 -5
  9. package/lib/components/courses/courses.service.d.ts +0 -14
  10. package/lib/components/courses/models/courses.model.d.ts +0 -24
  11. package/lib/components/courses-admin/courses-admin.component.d.ts +0 -8
  12. package/lib/components/dc-lessons/dc-lesson-card/dc-lesson-card.component.d.ts +0 -25
  13. package/lib/components/dc-lessons/dc-lesson-component-adder/dc-lesson-component-adder.component.d.ts +0 -11
  14. package/lib/components/dc-lessons/dc-lesson-editor/dc-lesson-editor.component.d.ts +0 -67
  15. package/lib/components/dc-lessons/dc-lesson-metadata-editor/dc-lesson-metadata-editor.component.d.ts +0 -43
  16. package/lib/components/dc-lessons/dc-lesson-renderer/dc-lesson-renderer.component.d.ts +0 -51
  17. package/lib/components/dc-lessons/dc-lesson-renderer/eval-agents-skills.d.ts +0 -1
  18. package/lib/components/dc-lessons/lesson-form/lesson-form.component.d.ts +0 -5
  19. package/lib/components/dc-lessons/lesson-list/dc-lesson-list.component.d.ts +0 -36
  20. package/lib/components/dynamic-components/dynamic-components-builder.service.d.ts +0 -8
  21. package/lib/components/dynamic-components/dynamic-components.service.d.ts +0 -30
  22. package/lib/components/dynamic-components/selector/selector-builder/selector-builder.component.d.ts +0 -16
  23. package/lib/components/dynamic-components/selector/selector.component.d.ts +0 -12
  24. package/lib/components/lesson-mini-components/components/ComponentBuilder.d.ts +0 -33
  25. package/lib/components/lesson-mini-components/components/ComponentWithForm.d.ts +0 -12
  26. package/lib/components/lesson-mini-components/components/lesson-dynamic.component.d.ts +0 -7
  27. package/lib/components/lesson-mini-components/components/lessons.clases.d.ts +0 -159
  28. package/lib/components/lesson-mini-components/components/speaker/speaker-builder/speaker-builder.component.d.ts +0 -14
  29. package/lib/components/lesson-mini-components/components/speaker/speaker.component.d.ts +0 -12
  30. package/lib/components/lesson-mini-components/components/text-writer/text-writer-buider/text-writer-buider.component.d.ts +0 -7
  31. package/lib/components/lesson-mini-components/components/text-writer/text-writer.component.d.ts +0 -16
  32. package/lib/components/lesson-mini-components/components/translationSwitcher/translationSwitcher.component.d.ts +0 -11
  33. package/lib/components/lesson-mini-components/components/translationSwitcher/translationSwitcherBuilder/translationSwitcherBuilder.component.d.ts +0 -7
  34. package/lib/models/lessons.pipes.d.ts +0 -28
  35. package/lib/models/notion.models.d.ts +0 -41
  36. package/lib/models/simple-agents.d.ts +0 -2
  37. package/lib/services/courses.service.d.ts +0 -7
  38. package/lib/services/default-lessons.service.d.ts +0 -20
  39. package/lib/services/lesson-ai.service.d.ts +0 -32
  40. package/lib/services/lesson-notion.service.d.ts +0 -35
  41. package/lib/services/lesson-utils.service.d.ts +0 -56
  42. package/public-api.d.ts +0 -27
@@ -1,11 +1,9 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Pipe, InjectionToken, inject, Input, Component, ChangeDetectionStrategy, signal, EventEmitter, Output, ChangeDetectorRef, ViewChildren, Injectable, input, Renderer2, ViewContainerRef, computed, effect, ViewChild, output } from '@angular/core';
3
- import * as i1$2 from 'primeng/paginator';
4
- import { PaginatorModule } from 'primeng/paginator';
2
+ import { Pipe, InjectionToken, inject, Input, Component, ChangeDetectionStrategy, signal, EventEmitter, Output, Injectable, effect, ViewChildren, input, viewChild, Renderer2, ViewContainerRef, computed, ChangeDetectorRef, output } from '@angular/core';
5
3
  import { DatePipe, NgComponentOutlet, KeyValuePipe, CommonModule, SlicePipe } from '@angular/common';
6
- import * as i1$3 from '@angular/router';
7
- import { RouterModule, ActivatedRoute, Router } from '@angular/router';
8
- import { PaginationBase, TOAST_ALERTS_TOKEN, DCFilterBarComponent, QuickTableComponent, LoadingBarService, HttpCoreService, PromptService } from '@dataclouder/ngx-core';
4
+ import * as i1$4 from '@angular/router';
5
+ import { RouterModule, ActivatedRoute, RouterOutlet, RouterLink } from '@angular/router';
6
+ import { EntityCommunicationService, EntityBaseListComponent, DCFilterBarComponent, QuickTableComponent, TOAST_ALERTS_TOKEN, EModelQuality, UiStateService, LoadingBarService, LangDescTranslation, FormUtilsService, EntityBaseFormComponent, PromptService, DcExtensionsViewerComponent, DcLearnableViewerComponent, DcAuditableViewerComponent, DcReactionsViewerComponent, DcManageableFormComponent, DcLearnableFormComponent, HttpCoreService, PaginationBase, getSupportedLanguageOptions } from '@dataclouder/ngx-core';
9
7
  import * as i1 from '@angular/forms';
10
8
  import { FormBuilder, FormControl, FormArray, FormsModule, ReactiveFormsModule, UntypedFormControl, FormGroup, Validators } from '@angular/forms';
11
9
  import * as i1$1 from 'primeng/button';
@@ -14,49 +12,55 @@ import * as i3 from 'primeng/inputtext';
14
12
  import { InputTextModule } from 'primeng/inputtext';
15
13
  import { DynamicDialogRef, DialogService } from 'primeng/dynamicdialog';
16
14
  import { nanoid } from 'nanoid';
17
- import { DropdownModule } from 'primeng/dropdown';
18
- import { NgxTtsComponent, getRandomQuickVoice } from '@dataclouder/ngx-tts';
19
- import * as i4 from 'primeng/message';
20
- import { MessageModule } from 'primeng/message';
21
15
  import * as i2 from 'primeng/select';
22
16
  import { SelectModule } from 'primeng/select';
17
+ import { TTSPlayground, getRandomQuickVoice, NgxVertexService, ChatRoleVertex } from '@dataclouder/ngx-vertex';
18
+ import * as i4 from 'primeng/message';
19
+ import { MessageModule } from 'primeng/message';
23
20
  import { PopoverModule } from 'primeng/popover';
24
21
  import * as i4$1 from 'primeng/tag';
25
22
  import { TagModule } from 'primeng/tag';
26
23
  import * as i2$1 from 'primeng/speeddial';
27
24
  import { SpeedDialModule } from 'primeng/speeddial';
28
- import * as i3$1 from 'primeng/card';
25
+ import * as i1$2 from 'primeng/card';
29
26
  import { CardModule } from 'primeng/card';
30
- import { toSignal } from '@angular/core/rxjs-interop';
31
- import { map } from 'rxjs';
27
+ import { UserService } from '@dataclouder/ngx-users';
28
+ import * as i1$3 from 'primeng/paginator';
29
+ import { PaginatorModule } from 'primeng/paginator';
32
30
  import BalloonEditor from '@ckeditor/ckeditor5-build-balloon-block';
33
- import * as i3$2 from '@ckeditor/ckeditor5-angular';
31
+ import * as i3$1 from '@ckeditor/ckeditor5-angular';
34
32
  import { CKEditorModule } from '@ckeditor/ckeditor5-angular';
35
- import * as i5$1 from 'primeng/splitter';
33
+ import * as i5$1 from 'primeng/selectbutton';
34
+ import { SelectButtonModule } from 'primeng/selectbutton';
35
+ import * as i6$1 from 'primeng/splitter';
36
36
  import { SplitterModule } from 'primeng/splitter';
37
- import * as i6 from 'primeng/tooltip';
37
+ import * as i7 from 'primeng/tooltip';
38
38
  import { TooltipModule } from 'primeng/tooltip';
39
- import { ResolutionType, AspectType, CropperComponentModal } from '@dataclouder/ngx-cloud-storage';
40
- import { TextEngines, ConversationType, USER_DATA_EXCHANGE, ChatRole, EvalResultStringDefinition, ConversationEvents, ChatEventType, DCChatComponent, CONVERSATION_AI_TOKEN } from '@dataclouder/ngx-agent-cards';
39
+ import { ResolutionType, AspectType, AssetsLoaderComponent, CropperComponentModal } from '@dataclouder/ngx-cloud-storage';
40
+ import { TextEngines, ConversationType, USER_DATA_EXCHANGE, SystemPromptType, ChatRole, EvalResultStringDefinition, EDoActionType, ConditionOperator, ConditionType, ConversationEvents, ChatEventType, DCChatComponent, CONVERSATION_AI_TOKEN } from '@dataclouder/ngx-agent-cards';
41
41
  import * as i2$2 from 'primeng/drawer';
42
42
  import { DrawerModule } from 'primeng/drawer';
43
- import * as i7 from 'primeng/dialog';
43
+ import { MarkdownComponent, MarkdownService } from 'ngx-markdown';
44
44
  import { DialogModule } from 'primeng/dialog';
45
45
  import TurndownService from 'turndown';
46
46
  import { marked } from 'marked';
47
47
  import * as i5 from 'primeng/inputgroup';
48
48
  import { InputGroupModule } from 'primeng/inputgroup';
49
- import * as i6$1 from 'primeng/divider';
49
+ import * as i6 from 'primeng/divider';
50
50
  import { DividerModule } from 'primeng/divider';
51
- import { NgxVertexService, ChatRoleVertex } from '@dataclouder/ngx-vertex';
52
51
  import * as i2$3 from 'primeng/api';
52
+ import { MessageService } from 'primeng/api';
53
+ import { TableModule } from 'primeng/table';
54
+ import * as i3$2 from 'primeng/panel';
55
+ import { PanelModule } from 'primeng/panel';
56
+ import * as i5$2 from 'primeng/progressspinner';
57
+ import { ProgressSpinnerModule } from 'primeng/progressspinner';
58
+ import { ToastModule } from 'primeng/toast';
53
59
  import * as i3$3 from 'primeng/textarea';
54
60
  import { TextareaModule } from 'primeng/textarea';
55
61
  import { ChipModule } from 'primeng/chip';
56
62
  import { FormlyModule } from '@ngx-formly/core';
57
- import { TableModule } from 'primeng/table';
58
63
 
59
- // import { LangCodeDescription, LangCodeDescriptionEs } from '../components/lesson-mini-components/components/lessons.clases';
60
64
  // This pipe should not be here in the lessons, refactor when is posible and remove LangCodeDescription
61
65
  const LangCodeDescription = {
62
66
  es: 'Spanish',
@@ -74,25 +78,6 @@ const LangCodeDescriptionEs = {
74
78
  fr: 'Frances',
75
79
  ja: 'Japonés',
76
80
  };
77
- class LangDescTranslationPipe {
78
- transform(value, lang) {
79
- if (lang === 'es') {
80
- return LangCodeDescriptionEs[value];
81
- }
82
- else {
83
- return LangCodeDescription[value];
84
- }
85
- }
86
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: LangDescTranslationPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
87
- static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.4", ngImport: i0, type: LangDescTranslationPipe, isStandalone: true, name: "langDesc" }); }
88
- }
89
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: LangDescTranslationPipe, decorators: [{
90
- type: Pipe,
91
- args: [{
92
- name: 'langDesc',
93
- standalone: true,
94
- }]
95
- }] });
96
81
  class FlagLanguagePipe {
97
82
  transform(lang) {
98
83
  if (lang === 'en') {
@@ -114,10 +99,10 @@ class FlagLanguagePipe {
114
99
  return '';
115
100
  }
116
101
  }
117
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: FlagLanguagePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
118
- static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.4", ngImport: i0, type: FlagLanguagePipe, isStandalone: true, name: "flagEmoji" }); }
102
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: FlagLanguagePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
103
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.1.6", ngImport: i0, type: FlagLanguagePipe, isStandalone: true, name: "flagEmoji" }); }
119
104
  }
120
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: FlagLanguagePipe, decorators: [{
105
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: FlagLanguagePipe, decorators: [{
121
106
  type: Pipe,
122
107
  args: [{
123
108
  name: 'flagEmoji',
@@ -289,10 +274,10 @@ class ComponentBuilder {
289
274
  await navigator.clipboard.writeText(data.str);
290
275
  this.ref.close(data);
291
276
  }
292
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: ComponentBuilder, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
293
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.4", type: ComponentBuilder, isStandalone: true, selector: "app-component-builder", inputs: { inputs: "inputs", id: "id" }, ngImport: i0, template: '<div>no template</div>', isInline: true }); }
277
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: ComponentBuilder, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
278
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.6", type: ComponentBuilder, isStandalone: true, selector: "app-component-builder", inputs: { inputs: "inputs", id: "id" }, ngImport: i0, template: '<div>no template</div>', isInline: true }); }
294
279
  }
295
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: ComponentBuilder, decorators: [{
280
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: ComponentBuilder, decorators: [{
296
281
  type: Component,
297
282
  args: [{
298
283
  selector: 'app-component-builder',
@@ -309,10 +294,10 @@ class TextWriterBuiderComponent extends ComponentBuilder {
309
294
  super(...arguments);
310
295
  this.componentName = 'TextWriter';
311
296
  }
312
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: TextWriterBuiderComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
313
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.4", type: TextWriterBuiderComponent, isStandalone: true, selector: "app-text-writer-buider", usesInheritance: true, ngImport: i0, template: "<div>\r\n <div>\r\n <h5>Constructor de formulario con texto</h5>\r\n </div>\r\n\r\n <div>\r\n <form class=\"builder-form\" [formGroup]=\"formGroup\">\r\n <input pInputText type=\"text\" nbInput fullWidth formControlName=\"response\" placeholder=\"Respuesta\" />\r\n\r\n <input pInputText class=\"form-input\" type=\"\" nbInput fullWidth formControlName=\"hint\"\r\n placeholder=\"Escribe una pista para esta pregunta\" />\r\n\r\n <input pInputText class=\"form-input\" type=\"text\" nbInput fullWidth formControlName=\"explanation\"\r\n placeholder=\"Excribe una explicaci\u00F3n para la respuesta\" />\r\n </form>\r\n </div>\r\n\r\n <div>\r\n <p-button (click)=\"copyToClipboard()\" [disabled]=\"formGroup.invalid\" label=\"Copia C\u00F3digo\"\r\n [rounded]=\"true\"></p-button>\r\n <p-button (click)=\"showCode()\" [disabled]=\"formGroup.invalid\" label=\"Mostrar\" [rounded]=\"true\"\r\n severity=\"secondary\"></p-button>\r\n </div>\r\n</div>", styles: ["nb-card{width:60vw}.builder-form{padding:5px}.form-input{margin-top:10px}.mar-top{margin:5px}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i3.InputText, selector: "[pInputText]", inputs: ["variant", "fluid", "pSize"] }] }); }
297
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: TextWriterBuiderComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
298
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.6", type: TextWriterBuiderComponent, isStandalone: true, selector: "app-text-writer-buider", usesInheritance: true, ngImport: i0, template: "<div>\r\n <div>\r\n <h5>Constructor de formulario con texto</h5>\r\n </div>\r\n\r\n <div>\r\n <form class=\"builder-form\" [formGroup]=\"formGroup\">\r\n <input pInputText type=\"text\" nbInput fullWidth formControlName=\"response\" placeholder=\"Respuesta\" />\r\n\r\n <input pInputText class=\"form-input\" type=\"\" nbInput fullWidth formControlName=\"hint\"\r\n placeholder=\"Escribe una pista para esta pregunta\" />\r\n\r\n <input pInputText class=\"form-input\" type=\"text\" nbInput fullWidth formControlName=\"explanation\"\r\n placeholder=\"Excribe una explicaci\u00F3n para la respuesta\" />\r\n </form>\r\n </div>\r\n\r\n <div>\r\n <p-button (click)=\"copyToClipboard()\" [disabled]=\"formGroup.invalid\" label=\"Copia C\u00F3digo\"\r\n [rounded]=\"true\"></p-button>\r\n <p-button (click)=\"showCode()\" [disabled]=\"formGroup.invalid\" label=\"Mostrar\" [rounded]=\"true\"\r\n severity=\"secondary\"></p-button>\r\n </div>\r\n</div>", styles: ["nb-card{width:60vw}.builder-form{padding:5px}.form-input{margin-top:10px}.mar-top{margin:5px}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i3.InputText, selector: "[pInputText]", inputs: ["pSize", "variant", "fluid", "invalid"] }] }); }
314
299
  }
315
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: TextWriterBuiderComponent, decorators: [{
300
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: TextWriterBuiderComponent, decorators: [{
316
301
  type: Component,
317
302
  args: [{ selector: 'app-text-writer-buider', standalone: true, imports: [FormsModule, ReactiveFormsModule, ButtonModule, InputTextModule], template: "<div>\r\n <div>\r\n <h5>Constructor de formulario con texto</h5>\r\n </div>\r\n\r\n <div>\r\n <form class=\"builder-form\" [formGroup]=\"formGroup\">\r\n <input pInputText type=\"text\" nbInput fullWidth formControlName=\"response\" placeholder=\"Respuesta\" />\r\n\r\n <input pInputText class=\"form-input\" type=\"\" nbInput fullWidth formControlName=\"hint\"\r\n placeholder=\"Escribe una pista para esta pregunta\" />\r\n\r\n <input pInputText class=\"form-input\" type=\"text\" nbInput fullWidth formControlName=\"explanation\"\r\n placeholder=\"Excribe una explicaci\u00F3n para la respuesta\" />\r\n </form>\r\n </div>\r\n\r\n <div>\r\n <p-button (click)=\"copyToClipboard()\" [disabled]=\"formGroup.invalid\" label=\"Copia C\u00F3digo\"\r\n [rounded]=\"true\"></p-button>\r\n <p-button (click)=\"showCode()\" [disabled]=\"formGroup.invalid\" label=\"Mostrar\" [rounded]=\"true\"\r\n severity=\"secondary\"></p-button>\r\n </div>\r\n</div>", styles: ["nb-card{width:60vw}.builder-form{padding:5px}.form-input{margin-top:10px}.mar-top{margin:5px}\n"] }]
318
303
  }] });
@@ -330,10 +315,10 @@ class ComponentWithForm {
330
315
  validate() {
331
316
  // TODO: generic method to evaluate
332
317
  }
333
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: ComponentWithForm, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
334
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.4", type: ComponentWithForm, isStandalone: true, selector: "app-component-form", ngImport: i0, template: '<div>no template</div>', isInline: true }); }
318
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: ComponentWithForm, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
319
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.6", type: ComponentWithForm, isStandalone: true, selector: "app-component-form", ngImport: i0, template: '<div>no template</div>', isInline: true }); }
335
320
  }
336
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: ComponentWithForm, decorators: [{
321
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: ComponentWithForm, decorators: [{
337
322
  type: Component,
338
323
  args: [{
339
324
  selector: 'app-component-form',
@@ -376,10 +361,10 @@ class TextWriterComponent extends ComponentWithForm {
376
361
  }
377
362
  return true;
378
363
  }
379
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: TextWriterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
380
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.4", type: TextWriterComponent, isStandalone: true, selector: "app-text-writer", inputs: { config: "config" }, usesInheritance: true, ngImport: i0, template: "<input [class]=\"this.status\" pInputText [formControl]=\"control\" fieldSize=\"small\" type=\"text\" placeholder=\"Respuesta\"\n [size]=\"size\" />\n\n<!-- [ngClass]=\"{ 'selected-radio': 'true']}\" -->", styles: [".warning{border-color:#f0ad4e}.danger{border-color:#e1211b}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i3.InputText, selector: "[pInputText]", inputs: ["variant", "fluid", "pSize"] }] }); }
364
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: TextWriterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
365
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.6", type: TextWriterComponent, isStandalone: true, selector: "app-text-writer", inputs: { config: "config" }, usesInheritance: true, ngImport: i0, template: "<input [class]=\"this.status\" pInputText [formControl]=\"control\" fieldSize=\"small\" type=\"text\" placeholder=\"Respuesta\"\n [size]=\"size\" />\n\n<!-- [ngClass]=\"{ 'selected-radio': 'true']}\" -->", styles: [".warning{border-color:#f0ad4e}.danger{border-color:#e1211b}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i3.InputText, selector: "[pInputText]", inputs: ["pSize", "variant", "fluid", "invalid"] }] }); }
381
366
  }
382
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: TextWriterComponent, decorators: [{
367
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: TextWriterComponent, decorators: [{
383
368
  type: Component,
384
369
  args: [{ selector: 'app-text-writer', standalone: true, imports: [FormsModule, ReactiveFormsModule, InputTextModule], template: "<input [class]=\"this.status\" pInputText [formControl]=\"control\" fieldSize=\"small\" type=\"text\" placeholder=\"Respuesta\"\n [size]=\"size\" />\n\n<!-- [ngClass]=\"{ 'selected-radio': 'true']}\" -->", styles: [".warning{border-color:#f0ad4e}.danger{border-color:#e1211b}\n"] }]
385
370
  }], ctorParameters: () => [], propDecorators: { config: [{
@@ -391,10 +376,10 @@ class TranslationSwitcherBuilderComponent extends ComponentBuilder {
391
376
  super(...arguments);
392
377
  this.componentName = 'TranslationSwitcher';
393
378
  }
394
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: TranslationSwitcherBuilderComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
395
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.4", type: TranslationSwitcherBuilderComponent, isStandalone: true, selector: "app-translation-switcher-builder", usesInheritance: true, ngImport: i0, template: "<div>\n <div>\n <h5>Constructor de translation switcher</h5>\n </div>\n\n <div>\n <form class=\"builder-form\" [formGroup]=\"formGroup\">\n <input style=\"width: 100%\" pInputText type=\"text\" nbInput fullWidth formControlName=\"text\" placeholder=\"Texto para visualizar\" />\n\n <br /><br />\n\n <input\n style=\"width: 100%\"\n pInputText\n class=\"form-input\"\n type=\"\"\n nbInput\n fullWidth\n formControlName=\"response\"\n placeholder=\"Traducci\u00F3n al hacer clic\" />\n </form>\n </div>\n <br />\n <div>\n <p-button (click)=\"copyToClipboard()\" [disabled]=\"formGroup.invalid\" label=\"Copia C\u00F3digo\" [rounded]=\"true\"></p-button>\n <p-button (click)=\"showCode()\" [disabled]=\"formGroup.invalid\" label=\"Mostrar\" [rounded]=\"true\" severity=\"secondary\"></p-button>\n </div>\n</div>\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i3.InputText, selector: "[pInputText]", inputs: ["variant", "fluid", "pSize"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
379
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: TranslationSwitcherBuilderComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
380
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.6", type: TranslationSwitcherBuilderComponent, isStandalone: true, selector: "app-translation-switcher-builder", usesInheritance: true, ngImport: i0, template: "<div>\n <div>\n <h5>Constructor de translation switcher</h5>\n </div>\n\n <div>\n <form class=\"builder-form\" [formGroup]=\"formGroup\">\n <input style=\"width: 100%\" pInputText type=\"text\" nbInput fullWidth formControlName=\"text\" placeholder=\"Texto para visualizar\" />\n\n <br /><br />\n\n <input\n style=\"width: 100%\"\n pInputText\n class=\"form-input\"\n type=\"\"\n nbInput\n fullWidth\n formControlName=\"response\"\n placeholder=\"Traducci\u00F3n al hacer clic\" />\n </form>\n </div>\n <br />\n <div>\n <p-button (click)=\"copyToClipboard()\" [disabled]=\"formGroup.invalid\" label=\"Copia C\u00F3digo\" [rounded]=\"true\"></p-button>\n <p-button (click)=\"showCode()\" [disabled]=\"formGroup.invalid\" label=\"Mostrar\" [rounded]=\"true\" severity=\"secondary\"></p-button>\n </div>\n</div>\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i3.InputText, selector: "[pInputText]", inputs: ["pSize", "variant", "fluid", "invalid"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
396
381
  }
397
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: TranslationSwitcherBuilderComponent, decorators: [{
382
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: TranslationSwitcherBuilderComponent, decorators: [{
398
383
  type: Component,
399
384
  args: [{ selector: 'app-translation-switcher-builder', standalone: true, imports: [FormsModule, ReactiveFormsModule, ButtonModule, InputTextModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div>\n <div>\n <h5>Constructor de translation switcher</h5>\n </div>\n\n <div>\n <form class=\"builder-form\" [formGroup]=\"formGroup\">\n <input style=\"width: 100%\" pInputText type=\"text\" nbInput fullWidth formControlName=\"text\" placeholder=\"Texto para visualizar\" />\n\n <br /><br />\n\n <input\n style=\"width: 100%\"\n pInputText\n class=\"form-input\"\n type=\"\"\n nbInput\n fullWidth\n formControlName=\"response\"\n placeholder=\"Traducci\u00F3n al hacer clic\" />\n </form>\n </div>\n <br />\n <div>\n <p-button (click)=\"copyToClipboard()\" [disabled]=\"formGroup.invalid\" label=\"Copia C\u00F3digo\" [rounded]=\"true\"></p-button>\n <p-button (click)=\"showCode()\" [disabled]=\"formGroup.invalid\" label=\"Mostrar\" [rounded]=\"true\" severity=\"secondary\"></p-button>\n </div>\n</div>\n", styles: [":host{display:block}\n"] }]
400
385
  }] });
@@ -415,10 +400,10 @@ class TranslationSwitcherComponent {
415
400
  this.visibleText = this.config.settings.text;
416
401
  }
417
402
  }
418
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: TranslationSwitcherComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
419
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.4", type: TranslationSwitcherComponent, isStandalone: true, selector: "app-translation-switcher", inputs: { config: "config" }, ngImport: i0, template: "<button\n pButton\n style=\"padding: 0px 2px\"\n severity=\"help\"\n size=\"small\"\n (click)=\"switchTranslation()\"\n [label]=\"visibleText\"\n [text]=\"true\"\n [rounded]=\"true\"></button>\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i1$1.ButtonDirective, selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "fluid", "label", "icon", "buttonProps"] }], changeDetection: i0.ChangeDetectionStrategy.Default }); }
403
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: TranslationSwitcherComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
404
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.6", type: TranslationSwitcherComponent, isStandalone: true, selector: "app-translation-switcher", inputs: { config: "config" }, ngImport: i0, template: "<button\n pButton\n style=\"padding: 0px 2px\"\n severity=\"help\"\n size=\"small\"\n (click)=\"switchTranslation()\"\n [label]=\"visibleText\"\n [text]=\"true\"\n [rounded]=\"true\"></button>\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i1$1.ButtonDirective, selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "fluid", "label", "icon", "buttonProps"] }], changeDetection: i0.ChangeDetectionStrategy.Default }); }
420
405
  }
421
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: TranslationSwitcherComponent, decorators: [{
406
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: TranslationSwitcherComponent, decorators: [{
422
407
  type: Component,
423
408
  args: [{ selector: 'app-translation-switcher', standalone: true, imports: [ButtonModule], changeDetection: ChangeDetectionStrategy.Default, template: "<button\n pButton\n style=\"padding: 0px 2px\"\n severity=\"help\"\n size=\"small\"\n (click)=\"switchTranslation()\"\n [label]=\"visibleText\"\n [text]=\"true\"\n [rounded]=\"true\"></button>\n", styles: [":host{display:block}\n"] }]
424
409
  }], propDecorators: { config: [{
@@ -429,7 +414,7 @@ class SpeakerBuilderComponent extends ComponentBuilder {
429
414
  constructor() {
430
415
  super(...arguments);
431
416
  this.componentName = 'Speaker';
432
- this.tts = signal(undefined);
417
+ this.tts = signal(undefined, ...(ngDevMode ? [{ debugName: "tts" }] : []));
433
418
  }
434
419
  handleTtsGenerated(event) {
435
420
  console.log('TTS generated:', event);
@@ -450,16 +435,15 @@ class SpeakerBuilderComponent extends ComponentBuilder {
450
435
  };
451
436
  return code;
452
437
  }
453
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: SpeakerBuilderComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
454
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.4", type: SpeakerBuilderComponent, isStandalone: true, selector: "app-speaker-builder", usesInheritance: true, ngImport: i0, template: "<div>\r\n <div>\r\n <h5>Constructor de Speaker</h5>\r\n </div>\r\n\r\n <lib-ngx-tts (ttsGenerated)=\"handleTtsGenerated($event)\"></lib-ngx-tts>\r\n\r\n <br />\r\n <div>\r\n <p-button (click)=\"copyToClipboard()\" [disabled]=\"formGroup.invalid\" label=\"Copia C\u00F3digo\" [rounded]=\"true\"></p-button>\r\n <p-button (click)=\"showCode()\" [disabled]=\"!tts()\" label=\"Mostrar\" [rounded]=\"true\" severity=\"secondary\"></p-button>\r\n </div>\r\n</div>\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: InputTextModule }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: DropdownModule }, { kind: "component", type: NgxTtsComponent, selector: "lib-ngx-tts", inputs: ["path"], outputs: ["ttsGenerated"] }] }); }
438
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: SpeakerBuilderComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
439
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.6", type: SpeakerBuilderComponent, isStandalone: true, selector: "app-speaker-builder", usesInheritance: true, ngImport: i0, template: "<div>\r\n <div>\r\n <h5>Constructor de Speaker</h5>\r\n </div>\r\n\r\n <tts-playground (ttsGenerated)=\"handleTtsGenerated($event)\"></tts-playground>\r\n\r\n <br />\r\n <div>\r\n <p-button (click)=\"copyToClipboard()\" [disabled]=\"formGroup.invalid\" label=\"Copia C\u00F3digo\" [rounded]=\"true\"></p-button>\r\n <p-button (click)=\"showCode()\" [disabled]=\"!tts()\" label=\"Mostrar\" [rounded]=\"true\" severity=\"secondary\"></p-button>\r\n </div>\r\n</div>\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: InputTextModule }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: TTSPlayground, selector: "tts-playground", inputs: ["path"], outputs: ["ttsGenerated"] }] }); }
455
440
  }
456
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: SpeakerBuilderComponent, decorators: [{
441
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: SpeakerBuilderComponent, decorators: [{
457
442
  type: Component,
458
- args: [{ selector: 'app-speaker-builder', standalone: true, imports: [FormsModule, ReactiveFormsModule, InputTextModule, ButtonModule, DropdownModule, NgxTtsComponent], template: "<div>\r\n <div>\r\n <h5>Constructor de Speaker</h5>\r\n </div>\r\n\r\n <lib-ngx-tts (ttsGenerated)=\"handleTtsGenerated($event)\"></lib-ngx-tts>\r\n\r\n <br />\r\n <div>\r\n <p-button (click)=\"copyToClipboard()\" [disabled]=\"formGroup.invalid\" label=\"Copia C\u00F3digo\" [rounded]=\"true\"></p-button>\r\n <p-button (click)=\"showCode()\" [disabled]=\"!tts()\" label=\"Mostrar\" [rounded]=\"true\" severity=\"secondary\"></p-button>\r\n </div>\r\n</div>\r\n" }]
443
+ args: [{ selector: 'app-speaker-builder', standalone: true, imports: [FormsModule, ReactiveFormsModule, InputTextModule, ButtonModule, SelectModule, TTSPlayground], template: "<div>\r\n <div>\r\n <h5>Constructor de Speaker</h5>\r\n </div>\r\n\r\n <tts-playground (ttsGenerated)=\"handleTtsGenerated($event)\"></tts-playground>\r\n\r\n <br />\r\n <div>\r\n <p-button (click)=\"copyToClipboard()\" [disabled]=\"formGroup.invalid\" label=\"Copia C\u00F3digo\" [rounded]=\"true\"></p-button>\r\n <p-button (click)=\"showCode()\" [disabled]=\"!tts()\" label=\"Mostrar\" [rounded]=\"true\" severity=\"secondary\"></p-button>\r\n </div>\r\n</div>\r\n" }]
459
444
  }] });
460
445
 
461
446
  // ❌ can use this until i copy services to this lib
462
- // import { CONVERSATION_AI_TOKEN } from '@dataclouder/ngx-agent-cards';
463
447
  class SpeakerComponent {
464
448
  ngOnInit() {
465
449
  // throw new Error('Method not implemented.');
@@ -469,16 +453,11 @@ class SpeakerComponent {
469
453
  // ngOnInit(): void {}
470
454
  speach() {
471
455
  console.log('should speech but will do in next version');
472
- // if (this.config.audio) {
473
- // this.audioService.playAudio(this.config.audio.url);
474
- // } else {
475
- // this.speachService.speach(this.config.settings.text);
476
- // }
477
- }
478
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: SpeakerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
479
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.4", type: SpeakerComponent, isStandalone: true, selector: "app-speaker", inputs: { config: "config", tts: "tts" }, ngImport: i0, template: "<button\r\n pButton\r\n style=\"padding: 0px 2px\"\r\n severity=\"help\"\r\n size=\"small\"\r\n (click)=\"speach()\"\r\n [label]=\"config?.settings?.text\"\r\n [text]=\"true\"\r\n [rounded]=\"true\"></button>\r\n", styles: [".lisen{cursor:pointer}\n"], dependencies: [{ kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i1$1.ButtonDirective, selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "fluid", "label", "icon", "buttonProps"] }] }); }
456
+ }
457
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: SpeakerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
458
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.6", type: SpeakerComponent, isStandalone: true, selector: "app-speaker", inputs: { config: "config", tts: "tts" }, ngImport: i0, template: "<button\r\n pButton\r\n style=\"padding: 0px 2px\"\r\n severity=\"help\"\r\n size=\"small\"\r\n (click)=\"speach()\"\r\n [label]=\"config?.settings?.text\"\r\n [text]=\"true\"\r\n [rounded]=\"true\"></button>\r\n", styles: [".lisen{cursor:pointer}\n"], dependencies: [{ kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i1$1.ButtonDirective, selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "fluid", "label", "icon", "buttonProps"] }] }); }
480
459
  }
481
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: SpeakerComponent, decorators: [{
460
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: SpeakerComponent, decorators: [{
482
461
  type: Component,
483
462
  args: [{ selector: 'app-speaker', standalone: true, imports: [ButtonModule], template: "<button\r\n pButton\r\n style=\"padding: 0px 2px\"\r\n severity=\"help\"\r\n size=\"small\"\r\n (click)=\"speach()\"\r\n [label]=\"config?.settings?.text\"\r\n [text]=\"true\"\r\n [rounded]=\"true\"></button>\r\n", styles: [".lisen{cursor:pointer}\n"] }]
484
463
  }], propDecorators: { config: [{
@@ -515,10 +494,10 @@ class SelectorComponent extends ComponentWithForm {
515
494
  }
516
495
  return true;
517
496
  }
518
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: SelectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
519
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.4", type: SelectorComponent, isStandalone: true, selector: "app-selector", inputs: { config: "config" }, usesInheritance: true, ngImport: i0, template: "<p-select [class]=\"status\" placeholder=\"Selecciona\" [options]=\"config.settings.options\" [formControl]=\"control\"></p-select>\r\n", styles: ["::ng-deep .comp-selector button{min-width:80px}.warning{border-color:#f0ad4e}.danger{border-color:#e1211b}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i2.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "name", "style", "panelStyle", "styleClass", "panelStyleClass", "readonly", "required", "editable", "appendTo", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "variant", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "autoDisplayFirst", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "size", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "maxlength", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "fluid", "disabled", "itemSize", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "filterValue", "options"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }] }); }
497
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: SelectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
498
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.6", type: SelectorComponent, isStandalone: true, selector: "app-selector", inputs: { config: "config" }, usesInheritance: true, ngImport: i0, template: "<p-select [class]=\"status\" placeholder=\"Selecciona\" [options]=\"config.settings.options\" [formControl]=\"control\"></p-select>\r\n", styles: ["::ng-deep .comp-selector button{min-width:80px}.warning{border-color:#f0ad4e}.danger{border-color:#e1211b}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i2.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }] }); }
520
499
  }
521
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: SelectorComponent, decorators: [{
500
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: SelectorComponent, decorators: [{
522
501
  type: Component,
523
502
  args: [{ selector: 'app-selector', standalone: true, imports: [FormsModule, ReactiveFormsModule, SelectModule], template: "<p-select [class]=\"status\" placeholder=\"Selecciona\" [options]=\"config.settings.options\" [formControl]=\"control\"></p-select>\r\n", styles: ["::ng-deep .comp-selector button{min-width:80px}.warning{border-color:#f0ad4e}.danger{border-color:#e1211b}\n"] }]
524
503
  }], ctorParameters: () => [], propDecorators: { config: [{
@@ -563,10 +542,10 @@ class SelectorBuilderComponent extends ComponentBuilder {
563
542
  get optionsForm() {
564
543
  return this.formGroup.get('options');
565
544
  }
566
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: SelectorBuilderComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
567
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.4", type: SelectorBuilderComponent, isStandalone: true, selector: "app-selector-builder", usesInheritance: true, ngImport: i0, template: "<div>\n <div>\n <p-message>Construcci\u00F3n del componente de Selecci\u00F3n, sirve para hacer una pregunta y mostrar varias opciones, ejemplo:</p-message>\n </div>\n\n <div>\n <span>En que a\u00F1o lleg\u00F3 cristobal colon a america?</span>\n <app-selector [config]=\"sampleConfig\"></app-selector>\n </div>\n\n <hr />\n\n <div>\n <form class=\"builder-form\" [formGroup]=\"formGroup\">\n <input class=\"form-input\" type=\"text\" pInputText fullWidth formControlName=\"response\" placeholder=\"Respuesta Correcta...\" />\n <br />\n\n <input class=\"form-input\" type=\"\" pInputText fullWidth formControlName=\"hint\" placeholder=\"Escribe una pista para esta pregunta\" />\n\n <br />\n <input\n class=\"form-input\"\n type=\"text\"\n pInputText\n fullWidth\n formControlName=\"explanation\"\n placeholder=\"Excribe una explicaci\u00F3n para la respuesta\" />\n\n <hr />\n <h6>Opciones</h6>\n\n <div class=\"form-group\" formArrayName=\"options\">\n @for (item of optionsForm.controls; track item; let i = $index) {\n <div\n style=\"display: flex; gap: 10px; align-items: center; justify-content: space-between; margin-bottom: 10px; flex-direction: column\"\n >\n <div>\n <input type=\"text\" pInputText fullWidth [formControlName]=\"i\" />\n <p-button (click)=\"deleteFormArrayByIndex('options', i)\" icon=\"pi pi-times\" severity=\"danger\"></p-button>\n </div>\n </div>\n }\n </div>\n\n <p-button (click)=\"pushControlToFormArray('options')\" label=\"Agregar Opci\u00F3n\" [text]=\"true\" severity=\"help\"></p-button>\n </form>\n\n <!-- <button nbButton (click)=\"isRendered = !isRendered\"> Renderizar </button> -->\n\n @if (isRendered) {\n <div>\n <!-- TODO: probably i need to pass some params -->\n <app-selector></app-selector>\n </div>\n }\n </div>\n\n <div>\n <p-button (click)=\"copyToClipboard()\" [disabled]=\"formGroup.invalid\" label=\"Copia C\u00F3digo\" [rounded]=\"true\"></p-button>\n <p-button (click)=\"showCode()\" [disabled]=\"formGroup.invalid\" label=\"Mostrar\" [rounded]=\"true\" severity=\"secondary\"></p-button>\n </div>\n </div>\n", styles: ["nb-card{width:60vw}.builder-form{padding:5px}.form-input{margin-top:10px}.mar-top{margin:5px}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i1.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "component", type: SelectorComponent, selector: "app-selector", inputs: ["config"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i3.InputText, selector: "[pInputText]", inputs: ["variant", "fluid", "pSize"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: MessageModule }, { kind: "component", type: i4.Message, selector: "p-message", inputs: ["severity", "text", "escape", "style", "styleClass", "closable", "icon", "closeIcon", "life", "showTransitionOptions", "hideTransitionOptions", "size", "variant"], outputs: ["onClose"] }] }); }
545
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: SelectorBuilderComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
546
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.6", type: SelectorBuilderComponent, isStandalone: true, selector: "app-selector-builder", usesInheritance: true, ngImport: i0, template: "<div>\n <div>\n <p-message>Construcci\u00F3n del componente de Selecci\u00F3n, sirve para hacer una pregunta y mostrar varias opciones, ejemplo:</p-message>\n </div>\n\n <div>\n <span>En que a\u00F1o lleg\u00F3 cristobal colon a america?</span>\n <app-selector [config]=\"sampleConfig\"></app-selector>\n </div>\n\n <hr />\n\n <div>\n <form class=\"builder-form\" [formGroup]=\"formGroup\">\n <input class=\"form-input\" type=\"text\" pInputText fullWidth formControlName=\"response\" placeholder=\"Respuesta Correcta...\" />\n <br />\n\n <input class=\"form-input\" type=\"\" pInputText fullWidth formControlName=\"hint\" placeholder=\"Escribe una pista para esta pregunta\" />\n\n <br />\n <input\n class=\"form-input\"\n type=\"text\"\n pInputText\n fullWidth\n formControlName=\"explanation\"\n placeholder=\"Excribe una explicaci\u00F3n para la respuesta\" />\n\n <hr />\n <h6>Opciones</h6>\n\n <div class=\"form-group\" formArrayName=\"options\">\n @for (item of optionsForm.controls; track item; let i = $index) {\n <div\n style=\"display: flex; gap: 10px; align-items: center; justify-content: space-between; margin-bottom: 10px; flex-direction: column\"\n >\n <div>\n <input type=\"text\" pInputText fullWidth [formControlName]=\"i\" />\n <p-button (click)=\"deleteFormArrayByIndex('options', i)\" icon=\"pi pi-times\" severity=\"danger\"></p-button>\n </div>\n </div>\n }\n </div>\n\n <p-button (click)=\"pushControlToFormArray('options')\" label=\"Agregar Opci\u00F3n\" [text]=\"true\" severity=\"help\"></p-button>\n </form>\n\n <!-- <button nbButton (click)=\"isRendered = !isRendered\"> Renderizar </button> -->\n\n @if (isRendered) {\n <div>\n <!-- TODO: probably i need to pass some params -->\n <app-selector></app-selector>\n </div>\n }\n </div>\n\n <div>\n <p-button (click)=\"copyToClipboard()\" [disabled]=\"formGroup.invalid\" label=\"Copia C\u00F3digo\" [rounded]=\"true\"></p-button>\n <p-button (click)=\"showCode()\" [disabled]=\"formGroup.invalid\" label=\"Mostrar\" [rounded]=\"true\" severity=\"secondary\"></p-button>\n </div>\n </div>\n", styles: ["nb-card{width:60vw}.builder-form{padding:5px}.form-input{margin-top:10px}.mar-top{margin:5px}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i1.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "component", type: SelectorComponent, selector: "app-selector", inputs: ["config"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i3.InputText, selector: "[pInputText]", inputs: ["pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: MessageModule }, { kind: "component", type: i4.Message, selector: "p-message", inputs: ["severity", "text", "escape", "style", "styleClass", "closable", "icon", "closeIcon", "life", "showTransitionOptions", "hideTransitionOptions", "size", "variant"], outputs: ["onClose"] }] }); }
568
547
  }
569
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: SelectorBuilderComponent, decorators: [{
548
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: SelectorBuilderComponent, decorators: [{
570
549
  type: Component,
571
550
  args: [{ selector: 'app-selector-builder', standalone: true, imports: [FormsModule, ReactiveFormsModule, SelectorComponent, InputTextModule, ButtonModule, MessageModule], template: "<div>\n <div>\n <p-message>Construcci\u00F3n del componente de Selecci\u00F3n, sirve para hacer una pregunta y mostrar varias opciones, ejemplo:</p-message>\n </div>\n\n <div>\n <span>En que a\u00F1o lleg\u00F3 cristobal colon a america?</span>\n <app-selector [config]=\"sampleConfig\"></app-selector>\n </div>\n\n <hr />\n\n <div>\n <form class=\"builder-form\" [formGroup]=\"formGroup\">\n <input class=\"form-input\" type=\"text\" pInputText fullWidth formControlName=\"response\" placeholder=\"Respuesta Correcta...\" />\n <br />\n\n <input class=\"form-input\" type=\"\" pInputText fullWidth formControlName=\"hint\" placeholder=\"Escribe una pista para esta pregunta\" />\n\n <br />\n <input\n class=\"form-input\"\n type=\"text\"\n pInputText\n fullWidth\n formControlName=\"explanation\"\n placeholder=\"Excribe una explicaci\u00F3n para la respuesta\" />\n\n <hr />\n <h6>Opciones</h6>\n\n <div class=\"form-group\" formArrayName=\"options\">\n @for (item of optionsForm.controls; track item; let i = $index) {\n <div\n style=\"display: flex; gap: 10px; align-items: center; justify-content: space-between; margin-bottom: 10px; flex-direction: column\"\n >\n <div>\n <input type=\"text\" pInputText fullWidth [formControlName]=\"i\" />\n <p-button (click)=\"deleteFormArrayByIndex('options', i)\" icon=\"pi pi-times\" severity=\"danger\"></p-button>\n </div>\n </div>\n }\n </div>\n\n <p-button (click)=\"pushControlToFormArray('options')\" label=\"Agregar Opci\u00F3n\" [text]=\"true\" severity=\"help\"></p-button>\n </form>\n\n <!-- <button nbButton (click)=\"isRendered = !isRendered\"> Renderizar </button> -->\n\n @if (isRendered) {\n <div>\n <!-- TODO: probably i need to pass some params -->\n <app-selector></app-selector>\n </div>\n }\n </div>\n\n <div>\n <p-button (click)=\"copyToClipboard()\" [disabled]=\"formGroup.invalid\" label=\"Copia C\u00F3digo\" [rounded]=\"true\"></p-button>\n <p-button (click)=\"showCode()\" [disabled]=\"formGroup.invalid\" label=\"Mostrar\" [rounded]=\"true\" severity=\"secondary\"></p-button>\n </div>\n </div>\n", styles: ["nb-card{width:60vw}.builder-form{padding:5px}.form-input{margin-top:10px}.mar-top{margin:5px}\n"] }]
572
551
  }] });
@@ -603,8 +582,19 @@ function getLessonComponentClass(type) {
603
582
  return LessonComponents[type];
604
583
  }
605
584
  const LESSONS_TOKEN = new InjectionToken('Lessons Service');
606
- class LessonsAbstractService {
607
- }
585
+ // export abstract class LessonsAbstractService extends EntityCommunicationService<ILesson> {
586
+ // abstract getLessons(paginator?: any): Promise<any>;
587
+ // abstract getLesson(id: string): Promise<any>;
588
+ // abstract postLesson(lesson: ILesson): Promise<any>;
589
+ // abstract updateLesson(lesson: ILesson): Promise<any>;
590
+ // abstract deleteLesson(id: string): Promise<any>;
591
+ // abstract generateLesson(lesson: ILesson): Promise<any>;
592
+ // abstract postGenerateByAI(id: string): Promise<any>;
593
+ // abstract extractTextFromHtml(html: string): string;
594
+ // abstract postImproveMDWithAI(lessonId: string, markdownText: string): Promise<any>; // Added for AI Markdown improvement
595
+ // abstract saveTakenLesson(lesson: ILessonTaken): Promise<any>;
596
+ // abstract getPrompts(): LessonPrompts;
597
+ // }
608
598
  // my-service.provider.ts
609
599
  function provideLessonsService(serviceImplementation) {
610
600
  return [
@@ -621,64 +611,35 @@ var EventCard;
621
611
  EventCard["Delete"] = "delete";
622
612
  EventCard["Select"] = "select";
623
613
  EventCard["Qr"] = "qr";
614
+ EventCard["Clone"] = "clone";
624
615
  })(EventCard || (EventCard = {}));
625
616
  class DcLessonCardComponent {
626
617
  constructor() {
618
+ this.userService = inject(UserService);
627
619
  this.showOptions = true;
628
620
  this.cardHeight = '200px';
629
621
  this.onAction = new EventEmitter();
630
622
  this.coverUrl = 'assets/background/default-background.webp';
631
623
  this.eventType = EventCard;
632
624
  this.items = [
633
- {
634
- label: 'Editar',
635
- icon: 'pi pi-pencil',
636
- command: () => {
637
- this.eventCard(EventCard.Edit);
638
- },
639
- },
640
- {
641
- label: 'Eliminar',
642
- icon: 'pi pi-trash',
643
- command: () => {
644
- this.eventCard(EventCard.Delete);
645
- },
646
- },
647
- {
648
- label: 'Tomar lección',
649
- icon: 'pi pi-play',
650
- command: () => {
651
- this.eventCard(EventCard.Select);
652
- },
653
- },
625
+ { label: 'Clonar', icon: 'pi pi-copy', command: () => this.eventCard(EventCard.Clone) },
626
+ { label: 'Editar', icon: 'pi pi-pencil', command: () => this.eventCard(EventCard.Edit) },
627
+ { label: 'Eliminar', icon: 'pi pi-trash', command: () => this.eventCard(EventCard.Delete) },
654
628
  ];
655
629
  }
656
630
  ngOnInit() {
657
- this.coverUrl =
658
- this.lesson?.banner?.url || this.lesson?.metadata?.banner?.url || this.lesson?.media?.images?.[0]?.url || 'assets/background/default-background.webp';
631
+ this.coverUrl = this.lesson?.assets?.banner?.url || this.lesson?.media?.images?.[0]?.url || 'assets/background/default-background.webp';
632
+ console.log(this.lesson);
659
633
  }
660
634
  eventCard(eventType) {
661
- switch (eventType) {
662
- case EventCard.Edit:
663
- this.onAction.emit({ action: 'edit', item: this.lesson });
664
- break;
665
- case EventCard.Delete:
666
- this.onAction.emit({ action: 'delete', item: this.lesson });
667
- break;
668
- case EventCard.Select:
669
- this.onAction.emit({ action: 'select', item: this.lesson });
670
- break;
671
- case EventCard.Qr:
672
- this.onAction.emit({ action: 'qr', item: this.lesson });
673
- break;
674
- }
635
+ this.onAction.emit({ action: eventType, item: this.lesson });
675
636
  }
676
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DcLessonCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
677
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.4", type: DcLessonCardComponent, isStandalone: true, selector: "dc-lesson-card", inputs: { lesson: "lesson", showOptions: "showOptions", cardHeight: "cardHeight" }, outputs: { onAction: "onAction" }, ngImport: i0, template: "<div class=\"card-container\">\n @if(showOptions){\n <p-speeddial\n class=\"dial-button\"\n [model]=\"items\"\n [radius]=\"70\"\n type=\"quarter-circle\"\n direction=\"down-left\"\n [buttonProps]=\"{ severity: 'primary', rounded: true, outlined: true, raised: true }\" />\n }\n <p-card>\n <div class=\"lesson-card\" [style.height]=\"cardHeight\">\n <div class=\"photo\">\n <img [src]=\"coverUrl\" alt=\"\" />\n </div>\n\n <span class=\"date\">{{ lesson.createdAt | date : 'dd/MM/yyyy' }}</span>\n\n <div class=\"description\">\n <h1>{{ lesson.title || lesson.metadata?.title || 'No title available' }}</h1>\n <p>{{ lesson.description || lesson.metadata?.description || 'No description available' }}</p>\n <div class=\"card-footer\">\n <div class=\"status-tags\">\n <span class=\"level-tag\">Nivel {{ lesson.level }}</span>\n @if (lesson.taken?.status == 'passed') {\n <p-tag severity=\"success\" value=\"Tomada\" [rounded]=\"true\" />\n } @if (lesson.taken?.status == 'failed') {\n <p-tag severity=\"danger\" value=\"Fallida\" [rounded]=\"true\" />\n } @if (lesson.taken) {\n <p-tag severity=\"success\" value=\"Tomada \uD83D\uDCD6\" [rounded]=\"true\" />\n } @if (!lesson.metadata?.isPublished) {\n <p-tag severity=\"danger\" value=\"No publicada\" [rounded]=\"true\" />\n }\n </div>\n\n <div style=\"position: absolute; bottom: 0px; right: 0px\">\n <p-button label=\"Tomar lecci\u00F3n\" (onClick)=\"eventCard(eventType.Select)\" severity=\"primary\"> </p-button>\n </div>\n </div>\n </div>\n </div>\n </p-card>\n</div>\n", styles: [".card-container{position:relative;margin-bottom:20px;margin-left:10px}.dial-button{position:absolute;top:10px;right:20px;z-index:10}.lesson-card{border-radius:.5rem;height:100%}.lesson-card .photo{position:absolute;inset:0;z-index:1}.lesson-card .photo img{width:100%;height:100%;object-fit:cover;object-position:center}.lesson-card .photo:after{content:\"\";position:absolute;top:0;left:0;width:100%;height:100%;background:linear-gradient(to bottom,rgb(0,0,0) 50%,var(--p-primary-color) 100%);opacity:.4;z-index:2;pointer-events:none}.description{position:relative;z-index:2;color:#fff;height:100%;display:flex;flex-direction:column}.description h1{margin-top:0;margin-bottom:.5rem;font-size:1.5rem;font-weight:900;text-shadow:1px 1px 2px rgba(0,0,0,.7)}.description p{margin-bottom:1rem;flex-grow:1;font-weight:500;text-shadow:1px 1px 2px rgba(0,0,0,.9)}.date{position:absolute;top:1rem;left:1rem;z-index:3;background-color:#000000b3;color:#fff;padding:.3rem .6rem;border-radius:.25rem;font-size:.8rem}.card-footer{display:flex;justify-content:space-between;align-items:center;margin-top:auto}.status-tags{display:flex;gap:.5rem}.status-tags .level-tag,.status-tags .status-tag{padding:.3rem .6rem;border-radius:.25rem;font-size:.8rem}.status-tags .level-tag{background-color:#fff3}.status-tags .status-tag.success{background-color:#28a745b3}.status-tags .status-tag.danger{background-color:#dc3545b3}\n"], dependencies: [{ kind: "pipe", type: DatePipe, name: "date" }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: PopoverModule }, { kind: "ngmodule", type: SpeedDialModule }, { kind: "component", type: i2$1.SpeedDial, selector: "p-speeddial, p-speedDial, p-speed-dial", inputs: ["id", "model", "visible", "style", "className", "direction", "transitionDelay", "type", "radius", "mask", "disabled", "hideOnClickOutside", "buttonStyle", "buttonClassName", "maskStyle", "maskClassName", "showIcon", "hideIcon", "rotateAnimation", "ariaLabel", "ariaLabelledBy", "tooltipOptions", "buttonProps"], outputs: ["onVisibleChange", "visibleChange", "onClick", "onShow", "onHide"] }, { kind: "ngmodule", type: CardModule }, { kind: "component", type: i3$1.Card, selector: "p-card", inputs: ["header", "subheader", "style", "styleClass"] }, { kind: "ngmodule", type: TagModule }, { kind: "component", type: i4$1.Tag, selector: "p-tag", inputs: ["style", "styleClass", "severity", "value", "icon", "rounded"] }] }); }
637
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DcLessonCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
638
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.6", type: DcLessonCardComponent, isStandalone: true, selector: "dc-lesson-card", inputs: { lesson: "lesson", showOptions: "showOptions", cardHeight: "cardHeight" }, outputs: { onAction: "onAction" }, ngImport: i0, template: "<div class=\"card-container\">\n @if(showOptions){\n <p-speeddial\n class=\"dial-button\"\n [model]=\"items\"\n [radius]=\"70\"\n type=\"quarter-circle\"\n direction=\"down-left\"\n [buttonProps]=\"{ severity: 'primary', rounded: true, outlined: true, raised: true }\"\n [tooltipOptions]=\"{ tooltipPosition: 'top' }\" />\n }\n <p-card>\n <div class=\"lesson-card\" [style.height]=\"cardHeight\">\n <div class=\"photo\">\n <img [src]=\"coverUrl\" alt=\"\" />\n </div>\n\n <span class=\"date\">{{ lesson.createdAt | date : 'dd/MM/yyyy' }}</span>\n\n <div class=\"description\">\n <h1>{{ lesson.title || lesson.metadata?.title || 'No title available' }}</h1>\n <p>{{ lesson.description || lesson.metadata?.description || 'No description available' }}</p>\n <div class=\"card-footer\">\n <div class=\"status-tags\">\n @if (lesson.learnable?.level){\n <p-tag>Nivel {{ lesson.learnable?.level }}</p-tag>\n } @if (lesson.taken?.status == 'passed') {\n <p-tag severity=\"success\" value=\"Tomada\" [rounded]=\"true\" />\n } @if (lesson.taken?.status == 'failed') {\n <p-tag severity=\"danger\" value=\"Fallida\" [rounded]=\"true\" />\n } @if (lesson.taken) {\n <p-tag severity=\"success\" value=\"Tomada \uD83D\uDCD6\" [rounded]=\"true\" />\n } @if ( userService.isAdmin()) {\n <p-tag severity=\"contrast\" [value]=\"lesson.manageable?.isPublic ? 'P\u00FAblica' : 'No p\u00FAblica'\" [rounded]=\"true\" />\n <p-tag severity=\"contrast\" [value]=\"lesson.manageable?.status\" [rounded]=\"true\" />\n }\n </div>\n\n <div style=\"position: absolute; bottom: 0px; right: 0px\">\n <p-button label=\"Tomar lecci\u00F3n\" (onClick)=\"eventCard(eventType.Select)\" severity=\"primary\"> </p-button>\n </div>\n </div>\n </div>\n </div>\n </p-card>\n</div>\n", styles: [".card-container{position:relative;margin-bottom:20px;margin-left:10px}.dial-button{position:absolute;top:10px;right:20px;z-index:10}.lesson-card{border-radius:.5rem;height:100%}.lesson-card .photo{position:absolute;inset:0;z-index:1}.lesson-card .photo img{width:100%;height:100%;object-fit:cover;object-position:center}.lesson-card .photo:after{content:\"\";position:absolute;top:0;left:0;width:100%;height:100%;background:linear-gradient(to bottom,rgb(0,0,0) 50%,var(--p-primary-color) 100%);opacity:.4;z-index:2;pointer-events:none}.description{position:relative;z-index:2;color:#fff;height:100%;display:flex;flex-direction:column}.description h1{margin-top:0;margin-bottom:.5rem;font-size:1.5rem;font-weight:900;text-shadow:1px 1px 2px rgba(0,0,0,.7)}.description p{margin-bottom:1rem;flex-grow:1;font-weight:500;text-shadow:1px 1px 2px rgba(0,0,0,.9)}.date{position:absolute;top:1rem;left:1rem;z-index:3;background-color:#000000b3;color:#fff;padding:.3rem .6rem;border-radius:.25rem;font-size:.8rem}.card-footer{display:flex;justify-content:space-between;align-items:center;margin-top:auto}.status-tags{display:flex;gap:.5rem}.status-tags .level-tag,.status-tags .status-tag{padding:.3rem .6rem;border-radius:.25rem;font-size:.8rem}.status-tags .level-tag{background-color:#fff3}.status-tags .status-tag.success{background-color:#28a745b3}.status-tags .status-tag.danger{background-color:#dc3545b3}\n"], dependencies: [{ kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: PopoverModule }, { kind: "ngmodule", type: SpeedDialModule }, { kind: "component", type: i2$1.SpeedDial, selector: "p-speeddial, p-speedDial, p-speed-dial", inputs: ["id", "model", "visible", "style", "className", "direction", "transitionDelay", "type", "radius", "mask", "disabled", "hideOnClickOutside", "buttonStyle", "buttonClassName", "maskStyle", "maskClassName", "showIcon", "hideIcon", "rotateAnimation", "ariaLabel", "ariaLabelledBy", "tooltipOptions", "buttonProps"], outputs: ["onVisibleChange", "visibleChange", "onClick", "onShow", "onHide"] }, { kind: "ngmodule", type: CardModule }, { kind: "component", type: i1$2.Card, selector: "p-card", inputs: ["header", "subheader", "style", "styleClass"] }, { kind: "ngmodule", type: TagModule }, { kind: "component", type: i4$1.Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }, { kind: "pipe", type: DatePipe, name: "date" }] }); }
678
639
  }
679
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DcLessonCardComponent, decorators: [{
640
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DcLessonCardComponent, decorators: [{
680
641
  type: Component,
681
- args: [{ selector: 'dc-lesson-card', standalone: true, imports: [DatePipe, ButtonModule, PopoverModule, SpeedDialModule, CardModule, TagModule], template: "<div class=\"card-container\">\n @if(showOptions){\n <p-speeddial\n class=\"dial-button\"\n [model]=\"items\"\n [radius]=\"70\"\n type=\"quarter-circle\"\n direction=\"down-left\"\n [buttonProps]=\"{ severity: 'primary', rounded: true, outlined: true, raised: true }\" />\n }\n <p-card>\n <div class=\"lesson-card\" [style.height]=\"cardHeight\">\n <div class=\"photo\">\n <img [src]=\"coverUrl\" alt=\"\" />\n </div>\n\n <span class=\"date\">{{ lesson.createdAt | date : 'dd/MM/yyyy' }}</span>\n\n <div class=\"description\">\n <h1>{{ lesson.title || lesson.metadata?.title || 'No title available' }}</h1>\n <p>{{ lesson.description || lesson.metadata?.description || 'No description available' }}</p>\n <div class=\"card-footer\">\n <div class=\"status-tags\">\n <span class=\"level-tag\">Nivel {{ lesson.level }}</span>\n @if (lesson.taken?.status == 'passed') {\n <p-tag severity=\"success\" value=\"Tomada\" [rounded]=\"true\" />\n } @if (lesson.taken?.status == 'failed') {\n <p-tag severity=\"danger\" value=\"Fallida\" [rounded]=\"true\" />\n } @if (lesson.taken) {\n <p-tag severity=\"success\" value=\"Tomada \uD83D\uDCD6\" [rounded]=\"true\" />\n } @if (!lesson.metadata?.isPublished) {\n <p-tag severity=\"danger\" value=\"No publicada\" [rounded]=\"true\" />\n }\n </div>\n\n <div style=\"position: absolute; bottom: 0px; right: 0px\">\n <p-button label=\"Tomar lecci\u00F3n\" (onClick)=\"eventCard(eventType.Select)\" severity=\"primary\"> </p-button>\n </div>\n </div>\n </div>\n </div>\n </p-card>\n</div>\n", styles: [".card-container{position:relative;margin-bottom:20px;margin-left:10px}.dial-button{position:absolute;top:10px;right:20px;z-index:10}.lesson-card{border-radius:.5rem;height:100%}.lesson-card .photo{position:absolute;inset:0;z-index:1}.lesson-card .photo img{width:100%;height:100%;object-fit:cover;object-position:center}.lesson-card .photo:after{content:\"\";position:absolute;top:0;left:0;width:100%;height:100%;background:linear-gradient(to bottom,rgb(0,0,0) 50%,var(--p-primary-color) 100%);opacity:.4;z-index:2;pointer-events:none}.description{position:relative;z-index:2;color:#fff;height:100%;display:flex;flex-direction:column}.description h1{margin-top:0;margin-bottom:.5rem;font-size:1.5rem;font-weight:900;text-shadow:1px 1px 2px rgba(0,0,0,.7)}.description p{margin-bottom:1rem;flex-grow:1;font-weight:500;text-shadow:1px 1px 2px rgba(0,0,0,.9)}.date{position:absolute;top:1rem;left:1rem;z-index:3;background-color:#000000b3;color:#fff;padding:.3rem .6rem;border-radius:.25rem;font-size:.8rem}.card-footer{display:flex;justify-content:space-between;align-items:center;margin-top:auto}.status-tags{display:flex;gap:.5rem}.status-tags .level-tag,.status-tags .status-tag{padding:.3rem .6rem;border-radius:.25rem;font-size:.8rem}.status-tags .level-tag{background-color:#fff3}.status-tags .status-tag.success{background-color:#28a745b3}.status-tags .status-tag.danger{background-color:#dc3545b3}\n"] }]
642
+ args: [{ selector: 'dc-lesson-card', standalone: true, imports: [DatePipe, ButtonModule, PopoverModule, SpeedDialModule, CardModule, TagModule], template: "<div class=\"card-container\">\n @if(showOptions){\n <p-speeddial\n class=\"dial-button\"\n [model]=\"items\"\n [radius]=\"70\"\n type=\"quarter-circle\"\n direction=\"down-left\"\n [buttonProps]=\"{ severity: 'primary', rounded: true, outlined: true, raised: true }\"\n [tooltipOptions]=\"{ tooltipPosition: 'top' }\" />\n }\n <p-card>\n <div class=\"lesson-card\" [style.height]=\"cardHeight\">\n <div class=\"photo\">\n <img [src]=\"coverUrl\" alt=\"\" />\n </div>\n\n <span class=\"date\">{{ lesson.createdAt | date : 'dd/MM/yyyy' }}</span>\n\n <div class=\"description\">\n <h1>{{ lesson.title || lesson.metadata?.title || 'No title available' }}</h1>\n <p>{{ lesson.description || lesson.metadata?.description || 'No description available' }}</p>\n <div class=\"card-footer\">\n <div class=\"status-tags\">\n @if (lesson.learnable?.level){\n <p-tag>Nivel {{ lesson.learnable?.level }}</p-tag>\n } @if (lesson.taken?.status == 'passed') {\n <p-tag severity=\"success\" value=\"Tomada\" [rounded]=\"true\" />\n } @if (lesson.taken?.status == 'failed') {\n <p-tag severity=\"danger\" value=\"Fallida\" [rounded]=\"true\" />\n } @if (lesson.taken) {\n <p-tag severity=\"success\" value=\"Tomada \uD83D\uDCD6\" [rounded]=\"true\" />\n } @if ( userService.isAdmin()) {\n <p-tag severity=\"contrast\" [value]=\"lesson.manageable?.isPublic ? 'P\u00FAblica' : 'No p\u00FAblica'\" [rounded]=\"true\" />\n <p-tag severity=\"contrast\" [value]=\"lesson.manageable?.status\" [rounded]=\"true\" />\n }\n </div>\n\n <div style=\"position: absolute; bottom: 0px; right: 0px\">\n <p-button label=\"Tomar lecci\u00F3n\" (onClick)=\"eventCard(eventType.Select)\" severity=\"primary\"> </p-button>\n </div>\n </div>\n </div>\n </div>\n </p-card>\n</div>\n", styles: [".card-container{position:relative;margin-bottom:20px;margin-left:10px}.dial-button{position:absolute;top:10px;right:20px;z-index:10}.lesson-card{border-radius:.5rem;height:100%}.lesson-card .photo{position:absolute;inset:0;z-index:1}.lesson-card .photo img{width:100%;height:100%;object-fit:cover;object-position:center}.lesson-card .photo:after{content:\"\";position:absolute;top:0;left:0;width:100%;height:100%;background:linear-gradient(to bottom,rgb(0,0,0) 50%,var(--p-primary-color) 100%);opacity:.4;z-index:2;pointer-events:none}.description{position:relative;z-index:2;color:#fff;height:100%;display:flex;flex-direction:column}.description h1{margin-top:0;margin-bottom:.5rem;font-size:1.5rem;font-weight:900;text-shadow:1px 1px 2px rgba(0,0,0,.7)}.description p{margin-bottom:1rem;flex-grow:1;font-weight:500;text-shadow:1px 1px 2px rgba(0,0,0,.9)}.date{position:absolute;top:1rem;left:1rem;z-index:3;background-color:#000000b3;color:#fff;padding:.3rem .6rem;border-radius:.25rem;font-size:.8rem}.card-footer{display:flex;justify-content:space-between;align-items:center;margin-top:auto}.status-tags{display:flex;gap:.5rem}.status-tags .level-tag,.status-tags .status-tag{padding:.3rem .6rem;border-radius:.25rem;font-size:.8rem}.status-tags .level-tag{background-color:#fff3}.status-tags .status-tag.success{background-color:#28a745b3}.status-tags .status-tag.danger{background-color:#dc3545b3}\n"] }]
682
643
  }], propDecorators: { lesson: [{
683
644
  type: Input
684
645
  }], showOptions: [{
@@ -689,145 +650,430 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImpor
689
650
  type: Output
690
651
  }] } });
691
652
 
653
+ class DefaultLessonsService extends EntityCommunicationService {
654
+ constructor() {
655
+ super('lesson');
656
+ // --- Endpoint Definitions for methods not in EntityCommunicationService ---
657
+ this.endpoints = {
658
+ saveTakenLesson: `api/user/saveLesson`,
659
+ generateLesson: `api/lesson/generate`,
660
+ generateByAI: `api/lesson/generate-ai`,
661
+ improveMDWithAI: `api/lesson/improve-markdown-ai`,
662
+ GenerateBanner: 'api/lesson/generate-banner',
663
+ };
664
+ }
665
+ // --- Method Implementations from LessonsAbstractService ---
666
+ async getLessons(filters = {}) {
667
+ if (!filters.returnProps) {
668
+ filters.returnProps = {
669
+ level: 1,
670
+ title: 1,
671
+ name: 1,
672
+ description: 1,
673
+ createdDate: 1,
674
+ banner: 1, // deprecated
675
+ metadata: 1, // deprecated
676
+ manageable: 1,
677
+ assets: 1,
678
+ learnable: 1,
679
+ appExtensions: 1,
680
+ media: 1, // deprecated
681
+ };
682
+ }
683
+ return this.query(filters);
684
+ }
685
+ async getLesson(id) {
686
+ return this.findOne(id);
687
+ }
688
+ async postLesson(lesson) {
689
+ return this.createOrUpdate(lesson);
690
+ }
691
+ async updateLesson(lesson) {
692
+ if (!lesson._id) {
693
+ throw new Error('Lesson ID is required for update.');
694
+ }
695
+ return this.createOrUpdate(lesson);
696
+ }
697
+ async deleteLesson(id) {
698
+ await this.remove(id);
699
+ }
700
+ // --- Methods specific to lessons ---
701
+ saveTakenLesson(lesson) {
702
+ return this.httpService.post(this.endpoints.saveTakenLesson, lesson);
703
+ }
704
+ async generateLesson(lesson) {
705
+ return this.httpService.post(this.endpoints.generateLesson, lesson);
706
+ }
707
+ async postGenerateByAI(id) {
708
+ return this.httpService.post(this.endpoints.generateByAI, { id });
709
+ }
710
+ async postImproveMDWithAI(lessonId, markdownText) {
711
+ return this.httpService.post(this.endpoints.improveMDWithAI, { id: lessonId, markdown: markdownText });
712
+ }
713
+ generateBanner(prompt, lessonId) {
714
+ return this.httpService.post(this.endpoints.GenerateBanner, { prompt, lessonId });
715
+ }
716
+ extractTextFromHtml(html) {
717
+ const r1 = new RegExp('~(.+?)~', 'g');
718
+ const lessonHtml = html.replace(r1, (_matching, jsonCoded) => {
719
+ try {
720
+ const data = JSON.parse(jsonCoded);
721
+ return `<span>${data?.settings?.text || ''}</span>`;
722
+ }
723
+ catch (e) {
724
+ console.error('Error parsing JSON in extractTextFromHtml:', jsonCoded, e);
725
+ return '';
726
+ }
727
+ });
728
+ let text = lessonHtml.replace(/<[^>]*>/g, ' ');
729
+ text = text.replace(/<style[^>]*>[\s\S]*?<\/style>/gi, ' ');
730
+ text = text.replace(/<script[^>]*>[\s\S]*?<\/script>/gi, ' ');
731
+ text = text.replace(/&nbsp;/g, ' ');
732
+ text = text.replace(/&/g, '&');
733
+ text = text.replace(/</g, '<');
734
+ text = text.replace(/>/g, '>');
735
+ text = text.replace(/\s+/g, ' ').trim();
736
+ return text;
737
+ }
738
+ getPrompts() {
739
+ return null;
740
+ }
741
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DefaultLessonsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
742
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DefaultLessonsService, providedIn: 'root' }); }
743
+ }
744
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DefaultLessonsService, decorators: [{
745
+ type: Injectable,
746
+ args: [{
747
+ providedIn: 'root',
748
+ }]
749
+ }], ctorParameters: () => [] });
750
+
692
751
  const tableViewColumns = [
693
752
  { field: 'media.images[0].url', header: 'Image', type: 'image' },
694
753
  { field: 'title', header: 'Título' },
695
754
  { field: 'description', header: 'Descripción' },
696
755
  ];
697
- const TableViewActions = [
698
- { title: 'select', label: 'Select', icon: 'pi pi-check', severity: 'primary' },
699
- { title: 'qr', label: 'QR', icon: 'pi pi-qrcode', severity: 'info' },
700
- { title: 'edit', label: 'Edit', icon: 'pi pi-pencil', severity: 'info' },
701
- { title: 'delete', label: 'Delete', icon: 'pi pi-trash', severity: 'danger' },
702
- ];
703
- const returnProperties = { id: 1, title: 1, assets: 1 };
704
- class DCLessonListComponent extends PaginationBase {
756
+ class DCLessonListComponent extends EntityBaseListComponent {
705
757
  constructor() {
706
- super(...arguments);
707
- this.showOptions = true;
758
+ super();
708
759
  this.customFilters = [];
709
- this.viewType = 'cards';
710
760
  // Injected Services
711
- this.cdr = inject(ChangeDetectorRef);
712
- this.lessonsService = inject(LESSONS_TOKEN);
713
- this.toastrService = inject(TOAST_ALERTS_TOKEN);
761
+ // I dont rename so use the same in EntityBaseListComponent and Pagination
762
+ this.entityCommunicationService = inject(LESSONS_TOKEN, { optional: true }) ?? inject(DefaultLessonsService);
714
763
  this.columns = tableViewColumns;
715
- this.cardComponent = null;
764
+ // Private properties
716
765
  this.cardEventSubs = [];
717
- this.lessons = [];
718
- this.isLoadingLessons = false;
766
+ this.filterConfig.returnProps = {
767
+ title: 1,
768
+ description: 1,
769
+ media: 1,
770
+ manageable: 1,
771
+ learnable: 1,
772
+ assets: 1,
773
+ _id: 1,
774
+ id: 1,
775
+ };
776
+ effect(() => {
777
+ // When items signal changes, re-subscribe to card events
778
+ this.items(); // a little hack to make the effect run when items change
779
+ setTimeout(() => this.subscribeToCardEvents());
780
+ });
719
781
  }
720
- ngOnInit() {
721
- this.filterConfig.returnProps = returnProperties;
782
+ async ngOnInit() {
722
783
  this.cardComponent = this.customCardComponent || DcLessonCardComponent;
723
- // TODO: i think show options is for admin, but refactor to add ListFilterBarOptions
724
- this.filterBarOptions = { showCreateButton: this.showOptions, showViewButton: this.showOptions, showActions: this.showOptions };
725
- this.getPaginatedLessons(this.filterConfig);
784
+ await super.ngOnInit();
726
785
  }
727
- subscribeDinamicInstantToEvents() {
728
- this.clearcardEventSubs();
729
- this.subscribeToCardEvents();
730
- }
731
- subscribeToCardEvents() {
732
- this.outlets.forEach((outlet) => {
733
- const instance = outlet.componentInstance;
734
- this.cardEventSubs.push(instance.onAction.subscribe((lesson) => {
735
- this.doOrEmitAction(lesson);
736
- }));
737
- });
738
- }
739
- clearcardEventSubs() {
740
- this.cardEventSubs.forEach((sub) => sub.unsubscribe());
741
- this.cardEventSubs = [];
786
+ ngAfterViewInit() {
787
+ this.outlets.changes.subscribe(() => this.subscribeToCardEvents());
742
788
  }
743
789
  ngOnDestroy() {
744
- this.clearcardEventSubs();
790
+ this.clearCardEventSubs();
745
791
  }
746
- async getPaginatedLessons(paginator) {
747
- try {
748
- this.lessons = null;
749
- this.isLoadingLessons = true;
750
- this.cdr.detectChanges();
751
- const lessons = await this.lessonsService.getLessons(paginator);
752
- this.lessons = lessons['rows'] || lessons;
753
- this.totalRecords = lessons['count'] || this.lessons.length;
754
- console.log('lessons', lessons);
755
- setTimeout(() => {
756
- this.subscribeDinamicInstantToEvents();
757
- });
758
- }
759
- finally {
760
- this.isLoadingLessons = false;
761
- this.cdr.detectChanges();
762
- }
763
- }
764
- search(searchText) {
765
- this.filterConfig['text'] = searchText;
766
- this.getPaginatedLessons(this.filterConfig);
792
+ getCustomButtons(item) {
793
+ return [
794
+ { label: 'Select', icon: 'pi pi-check', command: () => this.handleAction({ action: 'select', item }) },
795
+ { label: 'QR', icon: 'pi pi-qrcode', command: () => this.handleAction({ action: 'qr', item }) },
796
+ ];
767
797
  }
768
- removeLesson(lesson) {
769
- const response = confirm('¿Estás seguro de querer eliminar esta lección?');
770
- if (response) {
771
- this.lessonsService.deleteLesson(lesson._id);
772
- this.lessons = this.lessons.filter((l) => l._id !== lesson._id);
773
- this.cdr.detectChanges();
774
- this.toastrService.success({ title: 'Adios a la lección', subtitle: 'La lección ha sido eliminada correctamente' });
798
+ handleAction(actionEvent) {
799
+ if (['select', 'qr'].includes(actionEvent.action)) {
800
+ this.onAction.emit(actionEvent);
801
+ }
802
+ else {
803
+ super.doAction(actionEvent);
775
804
  }
776
- }
777
- newLesson() {
778
- this.onAction.emit({ action: 'new' });
779
805
  }
780
806
  applyFilterBarEvent(filterEvent) {
781
- if (filterEvent.action == 'changeView') {
782
- this.viewType = this.viewType === 'table' ? 'cards' : 'table';
807
+ if (filterEvent.action === 'changeView') {
808
+ this.toggleView();
783
809
  return;
784
810
  }
785
- else {
786
- console.log('filterChanged in dc-lesson-list', filterEvent);
787
- this.filterConfig = filterEvent.item;
788
- this.filterConfig.returnProps = returnProperties;
789
- this.getPaginatedLessons(this.filterConfig);
790
- }
811
+ this.filterConfig = { ...this.filterConfig, ...filterEvent.item };
812
+ this.loadData();
791
813
  }
792
- loadData() {
793
- return this.getPaginatedLessons(this.filterConfig);
814
+ subscribeToCardEvents() {
815
+ this.clearCardEventSubs();
816
+ this.outlets.forEach((outlet) => {
817
+ const instance = outlet.componentInstance;
818
+ if (instance?.onAction) {
819
+ this.cardEventSubs.push(instance.onAction.subscribe((event) => {
820
+ this.handleAction(event);
821
+ }));
822
+ }
823
+ });
824
+ }
825
+ clearCardEventSubs() {
826
+ this.cardEventSubs.forEach((sub) => sub.unsubscribe());
827
+ this.cardEventSubs = [];
794
828
  }
795
- doOrEmitAction(actionEvent) {
796
- if (actionEvent.action === 'delete') {
797
- this.removeLesson(actionEvent.item);
829
+ async loadData() {
830
+ try {
831
+ this.isLoading = true;
832
+ const response = await this.entityCommunicationService.getLessons(this.filterConfig);
833
+ this.items.set(response.rows);
834
+ this.totalRecordsSignal.set(response.count);
798
835
  }
799
- else {
800
- this.onAction.emit(actionEvent);
836
+ catch (error) {
837
+ console.error('Error loading data', error);
838
+ }
839
+ finally {
840
+ this.isLoading = false;
801
841
  }
802
842
  }
803
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DCLessonListComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
804
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.4", type: DCLessonListComponent, isStandalone: true, selector: "dc-lesson-list", inputs: { showOptions: "showOptions", customCardComponent: "customCardComponent", customFilters: "customFilters", viewType: "viewType" }, viewQueries: [{ propertyName: "outlets", predicate: ["outlet"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<dc-filter-bar\n [options]=\"filterBarOptions\"\n [customFilters]=\"customFilters\"\n (onFilterAction)=\"applyFilterBarEvent($event)\"\n (onNew)=\"newLesson()\"></dc-filter-bar>\n@if(viewType === 'table') {\n\n<app-quick-table [tableData]=\"lessons\" (onAction)=\"doOrEmitAction($event)\"></app-quick-table>\n\n} @else {\n<div class=\"lesson-list-container\">\n @if (!isLoadingLessons && lessons?.length > 0) { @for (lesson of lessons; track lesson._id) {\n <ng-container\n #outlet=\"ngComponentOutlet\"\n [ngComponentOutlet]=\"cardComponent\"\n [ngComponentOutletInputs]=\"{\n lesson: lesson,\n showOptions: showOptions\n }\">\n </ng-container>\n } } @else {\n <p>No se encontraron lecciones disponibles</p>\n }\n</div>\n}\n\n<p-paginator\n currentPageReportTemplate=\"{{ totalRecords }} lecciones\"\n [showCurrentPageReport]=\"true\"\n (onPageChange)=\"onPageChange($event)\"\n [first]=\"paginatorFirst\"\n [rows]=\"paginatorRows\"\n [totalRecords]=\"totalRecords\"\n [rowsPerPageOptions]=\"[10, 20, 30]\">\n</p-paginator>\n", styles: [":host{display:flex;flex-direction:column;height:100%}.lesson-list-container{padding:1.5rem;flex:1;overflow-y:auto;min-height:0}@media (max-width: 768px){.lesson-list-container{margin-top:1rem;padding:0rem}}p-paginator{margin-top:auto;padding:.5rem 1rem}\n"], dependencies: [{ kind: "ngmodule", type: RouterModule }, { kind: "component", type: DCFilterBarComponent, selector: "dc-filter-bar", inputs: ["items", "options", "customFilters"], outputs: ["onFilterAction", "onChangeSort", "onNew"] }, { kind: "ngmodule", type: PaginatorModule }, { kind: "component", type: i1$2.Paginator, selector: "p-paginator", inputs: ["pageLinkSize", "style", "styleClass", "alwaysShow", "dropdownAppendTo", "templateLeft", "templateRight", "appendTo", "dropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showFirstLastIcon", "totalRecords", "rows", "rowsPerPageOptions", "showJumpToPageDropdown", "showJumpToPageInput", "jumpToPageItemTemplate", "showPageLinks", "locale", "dropdownItemTemplate", "first"], outputs: ["onPageChange"] }, { kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"], exportAs: ["ngComponentOutlet"] }, { kind: "component", type: QuickTableComponent, selector: "app-quick-table", inputs: ["columns", "tableData", "actions"], outputs: ["onAction"] }] }); }
843
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DCLessonListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
844
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.6", type: DCLessonListComponent, isStandalone: true, selector: "dc-lesson-list", inputs: { customCardComponent: "customCardComponent", customFilters: "customFilters" }, viewQueries: [{ propertyName: "outlets", predicate: ["outlet"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<dc-filter-bar [options]=\"filterBarOptions\" [customFilters]=\"customFilters\" (onFilterAction)=\"applyFilterBarEvent($event)\" (onNew)=\"onNew()\"></dc-filter-bar>\n@if(viewType() === 'table') {\n\n<app-quick-table [tableData]=\"items()\" (onAction)=\"doAction($event)\"></app-quick-table>\n\n} @else {\n<div class=\"lesson-list-container\">\n @if (items()?.length > 0) { @for (lesson of items(); track lesson._id) {\n <ng-container\n #outlet=\"ngComponentOutlet\"\n [ngComponentOutlet]=\"cardComponent\"\n [ngComponentOutletInputs]=\"{\n lesson: lesson,\n showOptions: true\n }\">\n </ng-container>\n\n } } @else {\n <p>No se encontraron lecciones disponibles</p>\n }\n</div>\n}\n\n<p-paginator\n class=\"paginator-container\"\n currentPageReportTemplate=\"{{ totalRecords }} lecciones\"\n [showCurrentPageReport]=\"true\"\n (onPageChange)=\"onPageChange($event)\"\n [totalRecords]=\"totalRecords\"\n [first]=\"first\"\n [rows]=\"rows\"\n [rowsPerPageOptions]=\"[10, 20, 30]\">\n</p-paginator>\n", styles: [":host{display:flex;flex-direction:column;height:100%}.lesson-list-container{padding:1.5rem;flex:1;overflow-y:auto;min-height:0}@media (max-width: 768px){.lesson-list-container{margin-top:1rem;padding:0rem}}p-paginator{margin-top:auto;padding:.5rem 1rem}.paginator-container{background:transparent}\n"], dependencies: [{ kind: "ngmodule", type: RouterModule }, { kind: "component", type: DCFilterBarComponent, selector: "dc-filter-bar", inputs: ["items", "options", "customFilters"], outputs: ["onFilterAction", "onChangeSort", "onNew"] }, { kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"], exportAs: ["ngComponentOutlet"] }, { kind: "component", type: QuickTableComponent, selector: "app-quick-table", inputs: ["columns", "tableData", "actions"], outputs: ["onAction"] }, { kind: "ngmodule", type: PaginatorModule }, { kind: "component", type: i1$3.Paginator, selector: "p-paginator", inputs: ["pageLinkSize", "styleClass", "alwaysShow", "dropdownAppendTo", "templateLeft", "templateRight", "dropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showFirstLastIcon", "totalRecords", "rows", "rowsPerPageOptions", "showJumpToPageDropdown", "showJumpToPageInput", "jumpToPageItemTemplate", "showPageLinks", "locale", "dropdownItemTemplate", "first", "appendTo"], outputs: ["onPageChange"] }] }); }
805
845
  }
806
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DCLessonListComponent, decorators: [{
846
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DCLessonListComponent, decorators: [{
807
847
  type: Component,
808
- args: [{ selector: 'dc-lesson-list', standalone: true, imports: [RouterModule, DCFilterBarComponent, PaginatorModule, NgComponentOutlet, QuickTableComponent], template: "<dc-filter-bar\n [options]=\"filterBarOptions\"\n [customFilters]=\"customFilters\"\n (onFilterAction)=\"applyFilterBarEvent($event)\"\n (onNew)=\"newLesson()\"></dc-filter-bar>\n@if(viewType === 'table') {\n\n<app-quick-table [tableData]=\"lessons\" (onAction)=\"doOrEmitAction($event)\"></app-quick-table>\n\n} @else {\n<div class=\"lesson-list-container\">\n @if (!isLoadingLessons && lessons?.length > 0) { @for (lesson of lessons; track lesson._id) {\n <ng-container\n #outlet=\"ngComponentOutlet\"\n [ngComponentOutlet]=\"cardComponent\"\n [ngComponentOutletInputs]=\"{\n lesson: lesson,\n showOptions: showOptions\n }\">\n </ng-container>\n } } @else {\n <p>No se encontraron lecciones disponibles</p>\n }\n</div>\n}\n\n<p-paginator\n currentPageReportTemplate=\"{{ totalRecords }} lecciones\"\n [showCurrentPageReport]=\"true\"\n (onPageChange)=\"onPageChange($event)\"\n [first]=\"paginatorFirst\"\n [rows]=\"paginatorRows\"\n [totalRecords]=\"totalRecords\"\n [rowsPerPageOptions]=\"[10, 20, 30]\">\n</p-paginator>\n", styles: [":host{display:flex;flex-direction:column;height:100%}.lesson-list-container{padding:1.5rem;flex:1;overflow-y:auto;min-height:0}@media (max-width: 768px){.lesson-list-container{margin-top:1rem;padding:0rem}}p-paginator{margin-top:auto;padding:.5rem 1rem}\n"] }]
809
- }], propDecorators: { showOptions: [{
810
- type: Input
811
- }], customCardComponent: [{
848
+ args: [{ selector: 'dc-lesson-list', standalone: true, imports: [RouterModule, DCFilterBarComponent, NgComponentOutlet, QuickTableComponent, PaginatorModule], template: "<dc-filter-bar [options]=\"filterBarOptions\" [customFilters]=\"customFilters\" (onFilterAction)=\"applyFilterBarEvent($event)\" (onNew)=\"onNew()\"></dc-filter-bar>\n@if(viewType() === 'table') {\n\n<app-quick-table [tableData]=\"items()\" (onAction)=\"doAction($event)\"></app-quick-table>\n\n} @else {\n<div class=\"lesson-list-container\">\n @if (items()?.length > 0) { @for (lesson of items(); track lesson._id) {\n <ng-container\n #outlet=\"ngComponentOutlet\"\n [ngComponentOutlet]=\"cardComponent\"\n [ngComponentOutletInputs]=\"{\n lesson: lesson,\n showOptions: true\n }\">\n </ng-container>\n\n } } @else {\n <p>No se encontraron lecciones disponibles</p>\n }\n</div>\n}\n\n<p-paginator\n class=\"paginator-container\"\n currentPageReportTemplate=\"{{ totalRecords }} lecciones\"\n [showCurrentPageReport]=\"true\"\n (onPageChange)=\"onPageChange($event)\"\n [totalRecords]=\"totalRecords\"\n [first]=\"first\"\n [rows]=\"rows\"\n [rowsPerPageOptions]=\"[10, 20, 30]\">\n</p-paginator>\n", styles: [":host{display:flex;flex-direction:column;height:100%}.lesson-list-container{padding:1.5rem;flex:1;overflow-y:auto;min-height:0}@media (max-width: 768px){.lesson-list-container{margin-top:1rem;padding:0rem}}p-paginator{margin-top:auto;padding:.5rem 1rem}.paginator-container{background:transparent}\n"] }]
849
+ }], ctorParameters: () => [], propDecorators: { customCardComponent: [{
812
850
  type: Input
813
851
  }], customFilters: [{
814
852
  type: Input
815
- }], viewType: [{
816
- type: Input
817
853
  }], outlets: [{
818
854
  type: ViewChildren,
819
855
  args: ['outlet']
820
856
  }] } });
821
857
 
822
858
  class DCLessonFormComponent {
823
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DCLessonFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
824
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.4", type: DCLessonFormComponent, isStandalone: true, selector: "dc-lesson-form", ngImport: i0, template: "<div class=\"lesson-form-container\">\n <h2>Lesson Form</h2>\n <p>Esto es dentro del componente de la leccion</p>\n <!-- Form implementation will go here -->\n</div>\n", styles: [".lesson-form-container{padding:1rem}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }] }); }
859
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DCLessonFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
860
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.6", type: DCLessonFormComponent, isStandalone: true, selector: "dc-lesson-form", ngImport: i0, template: "<div class=\"lesson-form-container\">\n <h2>Lesson Form</h2>\n <p>Esto es dentro del componente de la leccion</p>\n <!-- Form implementation will go here -->\n</div>\n", styles: [".lesson-form-container{padding:1rem}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }] }); }
825
861
  }
826
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DCLessonFormComponent, decorators: [{
862
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DCLessonFormComponent, decorators: [{
827
863
  type: Component,
828
864
  args: [{ selector: 'dc-lesson-form', standalone: true, imports: [ReactiveFormsModule], template: "<div class=\"lesson-form-container\">\n <h2>Lesson Form</h2>\n <p>Esto es dentro del componente de la leccion</p>\n <!-- Form implementation will go here -->\n</div>\n", styles: [".lesson-form-container{padding:1rem}\n"] }]
829
865
  }] });
830
866
 
867
+ // TODO: check LessonComponentBuilders in lessons.clases.ts for origianl implementation
868
+ const DynamicComponentBuilders = {
869
+ [LessonComponentEnum.Speaker]: SpeakerBuilderComponent,
870
+ };
871
+ const DynamicComponents = {
872
+ [LessonComponentEnum.Speaker]: SpeakerComponent,
873
+ };
874
+ class DynamicComponentsService {
875
+ constructor() {
876
+ this._dynamicComponentBuilders = { ...DynamicComponentBuilders };
877
+ this._dynamicComponents = { ...DynamicComponents };
878
+ }
879
+ registerCustomComponent(component, name) {
880
+ // this._dynamicComponentBuilders[name || component.name] = component;
881
+ this._dynamicComponents[name || component.name] = component;
882
+ }
883
+ registerCustomComponentBuilder(component, name) {
884
+ this._dynamicComponentBuilders[name || component.name] = component;
885
+ }
886
+ getDynamicComponentBuilders(type) {
887
+ return this._dynamicComponentBuilders[type];
888
+ }
889
+ getDynamicComponentClass(type) {
890
+ return this._dynamicComponents[type];
891
+ }
892
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DynamicComponentsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
893
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DynamicComponentsService, providedIn: 'root' }); }
894
+ }
895
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DynamicComponentsService, decorators: [{
896
+ type: Injectable,
897
+ args: [{
898
+ providedIn: 'root',
899
+ }]
900
+ }] });
901
+
902
+ class LessonRendererService {
903
+ constructor() {
904
+ this.dynamicComponentsService = inject(DynamicComponentsService);
905
+ this.toastrService = inject(TOAST_ALERTS_TOKEN);
906
+ this.components = {};
907
+ this.mainForm = new FormGroup({});
908
+ }
909
+ renderLesson(lessonData, viewContainerRef, dynamicLessonElement, renderer) {
910
+ this.clearLessonRendering(dynamicLessonElement);
911
+ console.log('Rendering lesson:', lessonData.id);
912
+ const { htmlContent, components } = this.parseAndCreateComponents(lessonData, viewContainerRef);
913
+ this.components = components;
914
+ this.aggregateFormControls(this.components);
915
+ dynamicLessonElement.innerHTML = htmlContent;
916
+ this.injectComponentsIntoDom(this.components, renderer);
917
+ return this.components;
918
+ }
919
+ clearLessonRendering(dynamicLessonElement) {
920
+ Object.values(this.components).forEach((compRef) => compRef.destroy());
921
+ this.components = {};
922
+ this.mainForm = new FormGroup({});
923
+ if (dynamicLessonElement) {
924
+ dynamicLessonElement.innerHTML = '';
925
+ }
926
+ }
927
+ parseAndCreateComponents(lessonData, viewContainerRef) {
928
+ const r1 = new RegExp('~(.+?)~', 'g');
929
+ let count = 0;
930
+ const createdComponents = {};
931
+ const htmlContent = lessonData.textCoded.replace(r1, (_matching, jsonCoded) => {
932
+ const componentName = `dynamicComp${count}`;
933
+ count++;
934
+ const componentRef = this.createComponentReferenceWithJson(jsonCoded, lessonData, viewContainerRef);
935
+ if (!componentRef) {
936
+ console.error(`Failed to create component for: ${jsonCoded}`);
937
+ return '<!-- component creation failed -->';
938
+ }
939
+ createdComponents[componentName] = componentRef;
940
+ return `<span id="${componentName}"></span>`;
941
+ });
942
+ return { htmlContent, components: createdComponents };
943
+ }
944
+ createComponentReferenceWithJson(json, currentLesson, viewContainerRef) {
945
+ try {
946
+ let lessonCodedConfig = JSON.parse(json);
947
+ if (lessonCodedConfig.id && currentLesson?.dynamicComponents[lessonCodedConfig.id]) {
948
+ const foundConfig = currentLesson.dynamicComponents[lessonCodedConfig.id];
949
+ if (foundConfig) {
950
+ lessonCodedConfig = { ...lessonCodedConfig, ...foundConfig };
951
+ }
952
+ }
953
+ const LessonClass = this.dynamicComponentsService.getDynamicComponentClass(lessonCodedConfig.component);
954
+ if (!LessonClass) {
955
+ console.error(`Component class not found for type: ${lessonCodedConfig.component}. JSON: ${json}`);
956
+ return null;
957
+ }
958
+ const componentRef = viewContainerRef.createComponent(LessonClass);
959
+ if (lessonCodedConfig.inputs) {
960
+ for (const key in lessonCodedConfig.inputs) {
961
+ if (lessonCodedConfig.inputs.hasOwnProperty(key)) {
962
+ componentRef.instance[key] = lessonCodedConfig.inputs[key];
963
+ }
964
+ }
965
+ }
966
+ if (lessonCodedConfig.settings) {
967
+ componentRef.instance.config = lessonCodedConfig;
968
+ }
969
+ return componentRef;
970
+ }
971
+ catch (error) {
972
+ console.error(`Error processing component JSON: ${json}`, error);
973
+ return null;
974
+ }
975
+ }
976
+ aggregateFormControls(components) {
977
+ const newFormControls = {};
978
+ Object.entries(components).forEach(([name, componentRef]) => {
979
+ if (componentRef.instance?.control instanceof FormControl) {
980
+ newFormControls[name] = componentRef.instance.control;
981
+ newFormControls[name].addValidators(Validators.required);
982
+ }
983
+ });
984
+ this.mainForm = new FormGroup(newFormControls);
985
+ }
986
+ injectComponentsIntoDom(components, renderer) {
987
+ Object.entries(components).forEach(([name, componentRef]) => {
988
+ const elementRef = document.getElementById(name);
989
+ if (elementRef) {
990
+ this.addComponentToNode(componentRef, elementRef, renderer);
991
+ }
992
+ else {
993
+ console.warn(`Placeholder element with ID '${name}' not found in the DOM.`);
994
+ }
995
+ });
996
+ }
997
+ addComponentToNode(componentRef, nodeDOM, renderer) {
998
+ renderer.appendChild(nodeDOM, componentRef.location.nativeElement);
999
+ }
1000
+ evaluateForms() {
1001
+ this.mainForm.markAllAsTouched();
1002
+ if (!this.mainForm.valid) {
1003
+ Object.keys(this.mainForm.controls).forEach((controlName) => {
1004
+ if (this.components[controlName]?.instance?.validate) {
1005
+ this.components[controlName].instance.validate();
1006
+ }
1007
+ });
1008
+ this.toastrService.warn({ subtitle: 'Por favor completa todos los ejercicios', title: 'Incompleto' });
1009
+ return null;
1010
+ }
1011
+ const rates = { correct: 0, incorrect: 0, score: 0 };
1012
+ Object.keys(this.mainForm.controls).forEach((controlName) => {
1013
+ const instance = this.components[controlName]?.instance;
1014
+ if (instance && typeof instance.evaluate === 'function') {
1015
+ try {
1016
+ const result = instance.evaluate();
1017
+ if (result) {
1018
+ rates.correct++;
1019
+ }
1020
+ else {
1021
+ rates.incorrect++;
1022
+ }
1023
+ }
1024
+ catch (err) {
1025
+ console.error('Error during evaluation for component:', controlName, instance, err);
1026
+ rates.incorrect++;
1027
+ }
1028
+ }
1029
+ });
1030
+ const totalQuestions = rates.correct + rates.incorrect;
1031
+ rates.score = totalQuestions > 0 ? rates.correct / totalQuestions : 0;
1032
+ const status = rates.score >= 0.7 ? 'passed' : 'failed';
1033
+ if (status === 'passed') {
1034
+ this.toastrService.success({ subtitle: `Calificación: ${Math.round(rates.score * 100)}%.`, title: '¡Muy bien!' });
1035
+ }
1036
+ else {
1037
+ this.toastrService.warn({ subtitle: `Calificación: ${Math.round(rates.score * 100)}%. Revisa tus respuestas.`, title: 'Casi lo logras' });
1038
+ }
1039
+ return { rates, takenLesson: null };
1040
+ }
1041
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: LessonRendererService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1042
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: LessonRendererService, providedIn: 'root' }); }
1043
+ }
1044
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: LessonRendererService, decorators: [{
1045
+ type: Injectable,
1046
+ args: [{
1047
+ providedIn: 'root',
1048
+ }]
1049
+ }] });
1050
+
1051
+ const EnglishEvaluationSkill = `
1052
+ You are a virtual professor for the Polilan English learning app. Your primary role is to evaluate a student's English conversational performance.
1053
+
1054
+ You will be provided with two pieces of information for each evaluation:
1055
+ 1. **The student's English level:** This will be one of "Beginner", "Intermediate", or "Advanced".
1056
+ 2. **A conversation transcript:** This will be the dialogue between the Student and an Assistant, with each turn clearly labeled (e.g., "Student or User: ...", "Assistant: ...").
1057
+
1058
+ Your sole task is to evaluate the *Student's* contribution to the conversation. **Do NOT evaluate the Assistant's turns.**
1059
+
1060
+ Evaluate the student's performance based on the following aspects, *always keeping the student's provided level in mind* and adjusting your expectations accordingly specially with beginners give them credits just for trying:
1061
+
1062
+ * **Grammar & Syntax:** Evaluate accuracy and complexity *relative to the expected level*. (Beginners: focus on basic accuracy; Advanced: expect complex structures with high accuracy).
1063
+ * **Vocabulary & Usage:** Evaluate the range and appropriateness of words used *relative to the expected level*. (Beginners: focus on using basic words correctly; Advanced: expect varied and idiomatic language).
1064
+ * **Cohesion & Coherence:** Evaluate how well their turns connect and make sense within the conversation *relative to the expected level*. (Beginners: focus on simple, clear responses; Advanced: expect logical flow and detailed contributions).
1065
+ * **Task Completion/Relevance:** Evaluate how effectively they participate and respond to the conversation's goals or topics *relative to the expected level*.
1066
+
1067
+ Assign a rating from 0 to 3 based on how well the student performs *compared to the typical expectations for their provided level*:
1068
+
1069
+ * **0: Bad** - Performance is significantly below what is expected for this level. Many errors impede communication.
1070
+ * **1: Not Bad** - Performance is below expectations for this level, but communication is sometimes possible despite frequent errors.
1071
+ * **2: Good** - Performance meets expectations for this level, demonstrating solid understanding and usage with only occasional minor errors.
1072
+ * **3: Very Good** - Performance exceeds expectations for this level, demonstrating a strong command and potential to progress quickly.
1073
+
1074
+ Provide detailed, constructive feedback that explains the rating. Point out specific strengths and areas for improvement based on their performance *at their given level*. Use examples from the dialog if helpful. Maintain a supportive, encouraging, and educational tone appropriate for a virtual professor guiding a student at their specific stage.
1075
+ `;
1076
+
831
1077
  // Re-define or import constants if they are not exported from the component file
832
1078
  const DEFAULT_LESSON_AGENT_CARD = {
833
1079
  conversationSettings: {
@@ -843,7 +1089,6 @@ const DEFAULT_LESSON_AGENT_CARD = {
843
1089
  post_history_instructions: 'Your reply should be always short, 1 or 2 paragraphs at most, and to the point, and you should ask friendly questions all the time',
844
1090
  },
845
1091
  },
846
- model: { provider: 'google' },
847
1092
  };
848
1093
  const AppRolePlaySkill = `
849
1094
  You are an app role play assistant from Polilan App. The user is reading lessons through this app interface. They will now talk with you, and you need to evaluate their understanding of the lesson.
@@ -854,14 +1099,13 @@ You are an engagement assistant, start by greeting the user, asking something ab
854
1099
  that makes sense for the lesson.
855
1100
  `;
856
1101
  function getDefaultLessonEvaluatorAgentCard(lessonText) {
1102
+ // TODO: probably i need to build in order to add the sources to the task or system.
857
1103
  return {
858
1104
  expectedResponseType: `interface EvalResult {
859
1105
  score: number; // Score of the user's response 0 to 3
860
1106
  feedback: string; // Feedback of the user's understanding of the conversation
861
1107
  }`,
862
- messages: [],
863
1108
  model: { id: 'gpt-4o-mini', provider: 'openai' },
864
- sources: [lessonText],
865
1109
  task: `User is reading a taking a lesson, now their are having a conversation,
866
1110
  you have to evaluate the current conversation, and give a feedback of the user understanding of the lesson,
867
1111
  this is the lesson: ${lessonText}`,
@@ -869,8 +1113,7 @@ function getDefaultLessonEvaluatorAgentCard(lessonText) {
869
1113
  }
870
1114
  class LessonAIService {
871
1115
  constructor() {
872
- this.lessonService = inject(LESSONS_TOKEN);
873
- // TODO: Inject the application-level UserService
1116
+ this.lessonsService = inject(LESSONS_TOKEN, { optional: true }) ?? inject(DefaultLessonsService);
874
1117
  this.userService = inject(USER_DATA_EXCHANGE);
875
1118
  }
876
1119
  /**
@@ -894,7 +1137,7 @@ ${userInformationPrompt}`;
894
1137
  * @returns An object containing the master agent card and the evaluator agent card.
895
1138
  */
896
1139
  async generateAgentCards(lesson) {
897
- const lessonText = this.lessonService.extractTextFromHtml(lesson.textCoded);
1140
+ const lessonText = this.lessonsService.extractTextFromHtml(lesson.textCoded);
898
1141
  const userInformationPrompt = this.userService.getUserDataInformation();
899
1142
  const scenario = this._buildScenarioPrompt(lessonText, userInformationPrompt);
900
1143
  // Create a deep copy of the default card to avoid modifying the constant
@@ -912,7 +1155,13 @@ ${userInformationPrompt}`;
912
1155
  async generateConversationSettingsForLesson(lesson, settings) {
913
1156
  // TODO: Consolidate user fetching logic if possible, or ensure consistency
914
1157
  const baseLang = this.userService.getUserDataExchange()?.baseLang || 'en';
915
- const lessonText = this.lessonService.extractTextFromHtml(lesson.textCoded);
1158
+ let lessonText = '';
1159
+ if (lesson.textCoded) {
1160
+ lessonText = this.lessonsService.extractTextFromHtml(lesson.textCoded);
1161
+ }
1162
+ else {
1163
+ lessonText = lesson.markdown;
1164
+ }
916
1165
  const userInformationPrompt = this.userService.getUserDataInformation();
917
1166
  let scenario = this._buildScenarioPrompt(lessonText, userInformationPrompt);
918
1167
  if (settings.additionalPrompt) {
@@ -921,6 +1170,7 @@ ${userInformationPrompt}`;
921
1170
  const initialMessage = {
922
1171
  role: ChatRole.System,
923
1172
  content: scenario,
1173
+ messageId: SystemPromptType.SystemPrompt,
924
1174
  };
925
1175
  // Use defaults similar to DEFAULT_LESSON_AGENT_CARD but adjust for prompt-based start
926
1176
  const conversationSettings = {
@@ -929,75 +1179,107 @@ ${userInformationPrompt}`;
929
1179
  autoStart: true,
930
1180
  messages: [initialMessage],
931
1181
  model: { provider: 'google' },
932
- voice: getRandomQuickVoice(baseLang || 'en', 'female'),
1182
+ tts: { voice: getRandomQuickVoice(baseLang || 'en', 'female') },
933
1183
  };
934
1184
  return conversationSettings;
935
1185
  }
936
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: LessonAIService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
937
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: LessonAIService, providedIn: 'root' }); }
1186
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: LessonAIService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1187
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: LessonAIService, providedIn: 'root' }); }
938
1188
  }
939
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: LessonAIService, decorators: [{
1189
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: LessonAIService, decorators: [{
940
1190
  type: Injectable,
941
1191
  args: [{
942
1192
  providedIn: 'root', // Or provide appropriately if it's library-specific
943
1193
  }]
944
1194
  }] });
945
1195
 
946
- const EnglishEvaluationSkill = `
947
- You are a virtual professor for the Polilan English learning app. Your primary role is to evaluate a student's English conversational performance.
948
-
949
- You will be provided with two pieces of information for each evaluation:
950
- 1. **The student's English level:** This will be one of "Beginner", "Intermediate", or "Advanced".
951
- 2. **A conversation transcript:** This will be the dialogue between the Student and an Assistant, with each turn clearly labeled (e.g., "Student or User: ...", "Assistant: ...").
952
-
953
- Your sole task is to evaluate the *Student's* contribution to the conversation. **Do NOT evaluate the Assistant's turns.**
954
-
955
- Evaluate the student's performance based on the following aspects, *always keeping the student's provided level in mind* and adjusting your expectations accordingly specially with beginners give them credits just for trying:
956
-
957
- * **Grammar & Syntax:** Evaluate accuracy and complexity *relative to the expected level*. (Beginners: focus on basic accuracy; Advanced: expect complex structures with high accuracy).
958
- * **Vocabulary & Usage:** Evaluate the range and appropriateness of words used *relative to the expected level*. (Beginners: focus on using basic words correctly; Advanced: expect varied and idiomatic language).
959
- * **Cohesion & Coherence:** Evaluate how well their turns connect and make sense within the conversation *relative to the expected level*. (Beginners: focus on simple, clear responses; Advanced: expect logical flow and detailed contributions).
960
- * **Task Completion/Relevance:** Evaluate how effectively they participate and respond to the conversation's goals or topics *relative to the expected level*.
961
-
962
- Assign a rating from 0 to 3 based on how well the student performs *compared to the typical expectations for their provided level*:
963
-
964
- * **0: Bad** - Performance is significantly below what is expected for this level. Many errors impede communication.
965
- * **1: Not Bad** - Performance is below expectations for this level, but communication is sometimes possible despite frequent errors.
966
- * **2: Good** - Performance meets expectations for this level, demonstrating solid understanding and usage with only occasional minor errors.
967
- * **3: Very Good** - Performance exceeds expectations for this level, demonstrating a strong command and potential to progress quickly.
968
-
969
- Provide detailed, constructive feedback that explains the rating. Point out specific strengths and areas for improvement based on their performance *at their given level*. Use examples from the dialog if helpful. Maintain a supportive, encouraging, and educational tone appropriate for a virtual professor guiding a student at their specific stage.
970
- `;
971
-
972
- // TODO: check LessonComponentBuilders in lessons.clases.ts for origianl implementation
973
- const DynamicComponentBuilders = {
974
- [LessonComponentEnum.Speaker]: SpeakerBuilderComponent,
975
- };
976
- const DynamicComponents = {
977
- [LessonComponentEnum.Speaker]: SpeakerComponent,
978
- };
979
- class DynamicComponentsService {
1196
+ class LessonConversationService {
980
1197
  constructor() {
981
- this._dynamicComponentBuilders = { ...DynamicComponentBuilders };
982
- this._dynamicComponents = { ...DynamicComponents };
983
- }
984
- registerCustomComponent(component, name) {
985
- // this._dynamicComponentBuilders[name || component.name] = component;
986
- this._dynamicComponents[name || component.name] = component;
987
- }
988
- registerCustomComponentBuilder(component, name) {
989
- this._dynamicComponentBuilders[name || component.name] = component;
1198
+ this.lessonAIService = inject(LessonAIService);
1199
+ this.userDataExchange = inject(USER_DATA_EXCHANGE);
1200
+ this.conversationSettings = signal(undefined, ...(ngDevMode ? [{ debugName: "conversationSettings" }] : []));
1201
+ this.conversationFlow = signal(undefined, ...(ngDevMode ? [{ debugName: "conversationFlow" }] : []));
1202
+ this.evalAgentTask = signal(undefined, ...(ngDevMode ? [{ debugName: "evalAgentTask" }] : []));
990
1203
  }
991
- getDynamicComponentBuilders(type) {
992
- return this._dynamicComponentBuilders[type];
1204
+ initializeConversationFlow() {
1205
+ this.evalAgentTask.set({
1206
+ systemPrompt: EnglishEvaluationSkill,
1207
+ model: { provider: 'google' },
1208
+ task: `Please evaluate the user conversation student data is: \n ${this.userDataExchange.getUserDataInformation()}`,
1209
+ expectedResponseType: EvalResultStringDefinition,
1210
+ });
1211
+ this.conversationFlow.set({
1212
+ goal: {
1213
+ enabled: true,
1214
+ task: `User is learning is taking a lesson about languages, evaluate how good are the responses.`,
1215
+ model: { quality: EModelQuality.FAST },
1216
+ },
1217
+ triggerTasks: {
1218
+ [ConversationEvents.OnUserMessage]: {
1219
+ enabled: true,
1220
+ ...this.evalAgentTask(),
1221
+ },
1222
+ },
1223
+ challenges: null,
1224
+ dynamicConditions: [
1225
+ {
1226
+ what: ConditionType.Goal,
1227
+ when: ConditionOperator.GreaterThanOrEqual,
1228
+ value: 100,
1229
+ do: [
1230
+ {
1231
+ actionType: EDoActionType.ChangePrompt,
1232
+ systemPromptType: SystemPromptType.SystemPrompt,
1233
+ prompt: 'You were talking with the user, user finish the conversation, in the next message you must try to finish the conversation and say good bye.',
1234
+ },
1235
+ {
1236
+ actionType: EDoActionType.ChangePrompt,
1237
+ systemPromptType: SystemPromptType.CharacterDescription,
1238
+ prompt: '',
1239
+ },
1240
+ {
1241
+ actionType: EDoActionType.ChangePrompt,
1242
+ systemPromptType: SystemPromptType.UserInformation,
1243
+ prompt: '',
1244
+ },
1245
+ {
1246
+ actionType: EDoActionType.ChangePrompt,
1247
+ systemPromptType: SystemPromptType.MessageExamples,
1248
+ prompt: '',
1249
+ },
1250
+ {
1251
+ actionType: EDoActionType.ChangePrompt,
1252
+ systemPromptType: SystemPromptType.ScenarioDescription,
1253
+ prompt: '',
1254
+ },
1255
+ ],
1256
+ },
1257
+ ],
1258
+ });
993
1259
  }
994
- getDynamicComponentClass(type) {
995
- return this._dynamicComponents[type];
1260
+ async startAI(lesson, settings) {
1261
+ console.log('Requesting agent cards from LessonAIService...');
1262
+ try {
1263
+ const conversationSettings = await this.lessonAIService.generateConversationSettingsForLesson(lesson, settings);
1264
+ if (conversationSettings) {
1265
+ this.conversationSettings.set(conversationSettings);
1266
+ console.log('Agent cards received and set.');
1267
+ return conversationSettings;
1268
+ }
1269
+ else {
1270
+ console.error('Failed to generate agent cards (service returned null).');
1271
+ return null;
1272
+ }
1273
+ }
1274
+ catch (error) {
1275
+ console.error('Error generating agent cards:', error);
1276
+ return null;
1277
+ }
996
1278
  }
997
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DynamicComponentsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
998
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DynamicComponentsService, providedIn: 'root' }); }
1279
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: LessonConversationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1280
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: LessonConversationService, providedIn: 'root' }); }
999
1281
  }
1000
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DynamicComponentsService, decorators: [{
1282
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: LessonConversationService, decorators: [{
1001
1283
  type: Injectable,
1002
1284
  args: [{
1003
1285
  providedIn: 'root',
@@ -1007,29 +1289,25 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImpor
1007
1289
  class DCLessonRendererComponent {
1008
1290
  constructor() {
1009
1291
  // --- Signal Inputs ---
1010
- this.lessonInput = input(); // Input signal for lesson object
1011
- this.lessonIdInput = input(); // Input signal for lesson ID
1012
- this.settings = input();
1292
+ this.lessonInput = input(...(ngDevMode ? [undefined, { debugName: "lessonInput" }] : [])); // Input signal for lesson object
1293
+ this.lessonIdInput = input(...(ngDevMode ? [undefined, { debugName: "lessonIdInput" }] : [])); // Input signal for lesson ID
1294
+ this.settings = input(...(ngDevMode ? [undefined, { debugName: "settings" }] : []));
1013
1295
  // --- Outputs ---
1014
1296
  this.wordClicked = new EventEmitter(); // New output event
1297
+ // --- View Childs ---
1298
+ this.dynamicLesson = viewChild('dynamicLesson', ...(ngDevMode ? [{ debugName: "dynamicLesson" }] : []));
1015
1299
  // --- Services ---
1016
1300
  this.renderer = inject(Renderer2);
1017
1301
  this.viewContainerRef = inject(ViewContainerRef);
1018
1302
  this.toastrService = inject(TOAST_ALERTS_TOKEN);
1019
- this.lessonService = inject(LESSONS_TOKEN);
1020
- this.lessonAIService = inject(LessonAIService); // Inject the new service
1021
- this.userDataExchange = inject(USER_DATA_EXCHANGE);
1022
- this.dynamicComponentsService = inject(DynamicComponentsService);
1303
+ this.lessonsService = inject(LESSONS_TOKEN, { optional: true }) ?? inject(DefaultLessonsService);
1304
+ this.uiStateService = inject(UiStateService);
1305
+ this.lessonRendererService = inject(LessonRendererService);
1306
+ this.lessonConversationService = inject(LessonConversationService);
1023
1307
  // --- State Signals ---
1024
- this.lesson = signal(undefined); // Internal lesson state signal
1025
- this.chatVisible = signal(false); // Signal for chat visibility
1026
- this.agentMasterLesson = signal(undefined); // Signal for agent card
1027
- this.evaluatorAgentCard = signal(undefined); // Signal for evaluator card
1028
- this.conversationSettings = signal(undefined);
1029
- this.evalAgentTask = signal(undefined); // Signal for evaluator card
1030
- this.backgroundTasks = {};
1308
+ this.lesson = signal(undefined, ...(ngDevMode ? [{ debugName: "lesson" }] : [])); // Internal lesson state signal
1031
1309
  // --- Computed Signals ---
1032
- this.imageCover = computed(() => this.lesson()?.media?.images?.find((img) => img.type === 'cover')?.url); // Computed signal for imageCover
1310
+ this.imageCover = computed(() => this.lesson()?.media?.images?.find((img) => img.type === 'cover')?.url, ...(ngDevMode ? [{ debugName: "imageCover" }] : [])); // Computed signal for imageCover
1033
1311
  // --- Properties ---
1034
1312
  this.components = {};
1035
1313
  this.mainForm = new FormGroup({});
@@ -1046,7 +1324,7 @@ class DCLessonRendererComponent {
1046
1324
  console.log(`[Renderer] Effect 1: Fetching lesson ${lessonId}`);
1047
1325
  try {
1048
1326
  // Consider adding a loading state signal here
1049
- const fetchedLesson = await this.lessonService.getLesson(lessonId);
1327
+ const fetchedLesson = await this.lessonsService.getLesson(lessonId);
1050
1328
  this.lesson.set(fetchedLesson);
1051
1329
  console.log('Fetched lesson:', fetchedLesson);
1052
1330
  }
@@ -1066,204 +1344,64 @@ class DCLessonRendererComponent {
1066
1344
  }, { allowSignalWrites: true }); // Allow signal writes inside effect
1067
1345
  // Effect to render the lesson only when textCoded value actually changes
1068
1346
  effect(() => {
1347
+ const dynamicLessonEl = this.dynamicLesson();
1069
1348
  const currentLesson = this.lesson(); // Read the lesson signal
1349
+ if (!dynamicLessonEl || !currentLesson) {
1350
+ return;
1351
+ }
1352
+ if (currentLesson?.format === 'markdown') {
1353
+ // If markdown content exists, we clear any dynamically rendered components
1354
+ // and prevent the textCoded logic from running.
1355
+ if (this.previousTextCoded) {
1356
+ this.lessonRendererService.clearLessonRendering(dynamicLessonEl.nativeElement);
1357
+ this.mainForm = this.lessonRendererService.mainForm;
1358
+ this.previousTextCoded = undefined;
1359
+ }
1360
+ return;
1361
+ }
1070
1362
  const newTextCoded = currentLesson?.textCoded; // Get the current textCoded value
1071
- this.evalAgentTask.set({
1072
- systemPrompt: EnglishEvaluationSkill,
1073
- model: { provider: 'google' },
1074
- task: `Please evaluate the user conversation student data is: \n ${this.userDataExchange.getUserDataInformation()}`,
1075
- expectedResponseType: EvalResultStringDefinition,
1076
- });
1077
1363
  // Quick fix to only render on changes textCode not all the lesson
1078
1364
  if (newTextCoded !== this.previousTextCoded) {
1079
1365
  if (newTextCoded !== undefined && newTextCoded !== null && currentLesson) {
1080
- this._renderLesson(currentLesson);
1366
+ this.components = this.lessonRendererService.renderLesson(currentLesson, this.viewContainerRef, dynamicLessonEl.nativeElement, this.renderer);
1367
+ this.mainForm = this.lessonRendererService.mainForm;
1081
1368
  }
1082
1369
  else {
1083
- this._clearLessonRendering();
1084
- }
1085
- // Update the stored previous value *after* comparison and action
1086
- this.previousTextCoded = newTextCoded;
1087
- }
1088
- else {
1089
- console.log('[Renderer] textCoded has NOT changed. Skipping render/clear.');
1090
- }
1091
- });
1092
- }
1093
- ngOnInit() {
1094
- this.backgroundTasks = {
1095
- [ConversationEvents.OnUserMessage]: this.evalAgentTask(),
1096
- };
1097
- }
1098
- // --- Rendering Logic ---
1099
- _clearLessonRendering() {
1100
- // Destroy previously created dynamic components
1101
- Object.values(this.components).forEach((compRef) => compRef.destroy());
1102
- this.components = {};
1103
- // Clear the form
1104
- this.mainForm = new FormGroup({});
1105
- // Clear the HTML content
1106
- if (this.dynamicLesson?.nativeElement) {
1107
- this.dynamicLesson.nativeElement.innerHTML = '';
1108
- }
1109
- }
1110
- _renderLesson(lessonData) {
1111
- this._clearLessonRendering(); // Clear previous state first
1112
- console.log('Rendering lesson:', lessonData.id);
1113
- // 1) Parse textCoded, create components, and build HTML structure
1114
- const { htmlContent, components } = this._parseAndCreateComponents(lessonData);
1115
- this.components = components;
1116
- // 2) Aggregate form controls from created components
1117
- this._aggregateFormControls(this.components);
1118
- // 3) Set the innerHTML of the target element
1119
- this.dynamicLesson.nativeElement.innerHTML = htmlContent;
1120
- // 4) Inject the component views into the DOM
1121
- this._injectComponentsIntoDom(this.components);
1122
- }
1123
- _parseAndCreateComponents(lessonData) {
1124
- const r1 = new RegExp('~(.+?)~', 'g');
1125
- let count = 0;
1126
- const createdComponents = {};
1127
- const htmlContent = lessonData.textCoded.replace(r1, (_matching, jsonCoded) => {
1128
- const componentName = `dynamicComp${count}`;
1129
- count++;
1130
- const componentRef = this._createComponentReferenceWithJson(jsonCoded, lessonData);
1131
- if (!componentRef) {
1132
- console.error(`Failed to create component for: ${jsonCoded}`);
1133
- return '<!-- component creation failed -->'; // Placeholder in HTML
1134
- }
1135
- createdComponents[componentName] = componentRef;
1136
- return `<span id="${componentName}"></span>`; // Return span placeholder
1137
- });
1138
- return { htmlContent, components: createdComponents };
1139
- }
1140
- _aggregateFormControls(components) {
1141
- const newFormControls = {};
1142
- Object.entries(components).forEach(([name, componentRef]) => {
1143
- // Check if the instance has a control property that is a FormControl
1144
- if (componentRef.instance?.control instanceof FormControl) {
1145
- newFormControls[name] = componentRef.instance.control;
1146
- // Add required validator (consider making this configurable via component config?)
1147
- newFormControls[name].addValidators(Validators.required);
1148
- }
1149
- });
1150
- this.mainForm = new FormGroup(newFormControls); // Create the typed FormGroup
1151
- }
1152
- _injectComponentsIntoDom(components) {
1153
- Object.entries(components).forEach(([name, componentRef]) => {
1154
- const elementRef = document.getElementById(name); // Find the placeholder span
1155
- if (elementRef) {
1156
- this._addComponentToNode(componentRef, elementRef);
1157
- }
1158
- else {
1159
- console.warn(`Placeholder element with ID '${name}' not found in the DOM.`);
1160
- }
1161
- });
1162
- }
1163
- _addComponentToNode(componentRef, nodeDOM) {
1164
- this.renderer.appendChild(nodeDOM, componentRef.location.nativeElement);
1165
- }
1166
- _createComponentReferenceWithJson(json, currentLesson) {
1167
- try {
1168
- let lessonCodedConfig = JSON.parse(json);
1169
- //
1170
- // Attempt to find pre-configured component data in the lesson object by ID
1171
- if (lessonCodedConfig.id && currentLesson?.dynamicComponents[lessonCodedConfig.id]) {
1172
- const foundConfig = currentLesson.dynamicComponents[lessonCodedConfig.id];
1173
- if (foundConfig) {
1174
- // Merge configurations: Start with coded, override/add with found lesson config
1175
- lessonCodedConfig = { ...lessonCodedConfig, ...foundConfig };
1176
- }
1177
- }
1178
- const LessonClass = this.dynamicComponentsService.getDynamicComponentClass(lessonCodedConfig.component);
1179
- if (!LessonClass) {
1180
- console.error(`Component class not found for type: ${lessonCodedConfig.component}. JSON: ${json}`);
1181
- return null; // Return null if class doesn't exist
1182
- }
1183
- // Create component instance
1184
- const componentRef = this.viewContainerRef.createComponent(LessonClass);
1185
- if (lessonCodedConfig.inputs) {
1186
- for (const key in lessonCodedConfig.inputs) {
1187
- if (lessonCodedConfig.inputs.hasOwnProperty(key)) {
1188
- componentRef.instance[key] = lessonCodedConfig.inputs[key];
1189
- }
1190
- }
1191
- }
1192
- // i think i can improve this to pass only settings not all config, Assign the configuration to the component instance
1193
- // settings data i defined in form interface, config will be all the component data including id and component type
1194
- if (lessonCodedConfig.settings) {
1195
- componentRef.instance.config = lessonCodedConfig;
1196
- }
1197
- return componentRef;
1198
- }
1199
- catch (error) {
1200
- console.error(`Error processing component JSON: ${json}`, error);
1201
- return null; // Return null on JSON parsing or other errors
1202
- }
1203
- }
1204
- // --- Evaluation Logic ---
1205
- async evaluateForms() {
1206
- this.mainForm.markAllAsTouched(); // Mark all controls for validation feedback
1207
- if (!this.mainForm.valid) {
1208
- // Trigger validation feedback on individual components visually if needed
1209
- Object.keys(this.mainForm.controls).forEach((controlName) => {
1210
- if (this.components[controlName]?.instance?.validate) {
1211
- this.components[controlName].instance.validate(); // Assuming validate method handles visual feedback
1212
- }
1213
- });
1214
- this.toastrService.warn({ subtitle: 'Por favor completa todos los ejercicios', title: 'Incompleto' });
1215
- return;
1216
- }
1217
- const rates = { correct: 0, incorrect: 0, score: 0 };
1218
- // Evaluate each component associated with a form control
1219
- Object.keys(this.mainForm.controls).forEach((controlName) => {
1220
- const instance = this.components[controlName]?.instance;
1221
- // Check if the instance has an evaluate method (duck typing is okay here)
1222
- if (instance && typeof instance.evaluate === 'function') {
1223
- try {
1224
- const result = instance.evaluate();
1225
- if (result) {
1226
- rates.correct++;
1227
- }
1228
- else {
1229
- rates.incorrect++;
1230
- }
1231
- }
1232
- catch (err) {
1233
- console.error('Error during evaluation for component:', controlName, instance, err);
1234
- rates.incorrect++; // Count errors as incorrect
1370
+ this.lessonRendererService.clearLessonRendering(dynamicLessonEl.nativeElement);
1371
+ this.mainForm = this.lessonRendererService.mainForm;
1235
1372
  }
1373
+ // Update the stored previous value *after* comparison and action
1374
+ this.previousTextCoded = newTextCoded;
1375
+ }
1376
+ else {
1377
+ console.log('[Renderer] textCoded has NOT changed. Skipping render/clear.');
1236
1378
  }
1237
1379
  });
1238
- const totalQuestions = rates.correct + rates.incorrect;
1239
- rates.score = totalQuestions > 0 ? rates.correct / totalQuestions : 0; // Avoid division by zero
1240
- const status = rates.score >= 0.7 ? 'passed' : 'failed'; // Use >= for threshold
1380
+ }
1381
+ ngOnInit() {
1382
+ this.lessonConversationService.initializeConversationFlow();
1383
+ }
1384
+ async evaluateForms() {
1385
+ const result = this.lessonRendererService.evaluateForms();
1386
+ if (!result) {
1387
+ return;
1388
+ }
1241
1389
  const currentLesson = this.lesson();
1242
1390
  if (!currentLesson) {
1243
1391
  console.error('Cannot save result, lesson data is missing.');
1244
1392
  this.toastrService.error({ subtitle: 'Cannot save result, lesson data missing.', title: 'Error' });
1245
1393
  return;
1246
1394
  }
1247
- const takenLesson = { id: currentLesson.id, goalCompleted: null, score: rates.score, status: status, lastAccess: new Date() };
1395
+ const status = result.rates.score >= 0.7 ? 'passed' : 'failed';
1396
+ const takenLesson = {
1397
+ id: currentLesson.id,
1398
+ goalCompleted: null,
1399
+ score: result.rates.score,
1400
+ status: status,
1401
+ lastAccess: new Date(),
1402
+ };
1248
1403
  console.log('Lesson evaluation result:', takenLesson);
1249
1404
  // TODO: Re-implement saving the taken lesson status via lessonService
1250
- // try {
1251
- // await this.lessonService.saveTakenLesson(takenLesson);
1252
- // if (status === 'passed') {
1253
- // this.toastrService.success({ subtitle: `Calificación: ${Math.round(rates.score * 100)}%. Se guardó tu progreso.`, title: '¡Muy bien!' });
1254
- // } else {
1255
- // this.toastrService.warn({ subtitle: `Calificación: ${Math.round(rates.score * 100)}%. Revisa tus respuestas.`, title: 'Casi lo logras' });
1256
- // }
1257
- // } catch (error) {
1258
- // console.error('Failed to save taken lesson', error);
1259
- // this.toastrService.error({ subtitle: 'No se pudo guardar tu progreso.', title: 'Error' });
1260
- // }
1261
- if (status === 'passed') {
1262
- this.toastrService.success({ subtitle: `Calificación: ${Math.round(rates.score * 100)}%.`, title: '¡Muy bien!' });
1263
- }
1264
- else {
1265
- this.toastrService.warn({ subtitle: `Calificación: ${Math.round(rates.score * 100)}%. Revisa tus respuestas.`, title: 'Casi lo logras' });
1266
- }
1267
1405
  }
1268
1406
  // --- AI Chat Logic ---
1269
1407
  async startAI() {
@@ -1273,35 +1411,27 @@ class DCLessonRendererComponent {
1273
1411
  this.toastrService.error({ subtitle: 'Lesson data not available.', title: 'Cannot Start Chat' });
1274
1412
  return;
1275
1413
  }
1276
- console.log('Requesting agent cards from LessonAIService...');
1277
- try {
1278
- // Call the service to get the agent cards
1279
- const conversationSettings = await this.lessonAIService.generateConversationSettingsForLesson(currentLesson, this.settings());
1280
- if (conversationSettings) {
1281
- this.conversationSettings.set(conversationSettings);
1282
- this.chatVisible.set(true);
1283
- console.log('Agent cards received and set.');
1284
- }
1285
- else {
1286
- console.error('Failed to generate agent cards (service returned null).');
1287
- this.toastrService.error({ subtitle: 'Could not prepare the AI chat session.', title: 'Error' });
1288
- }
1414
+ const conversationSettings = await this.lessonConversationService.startAI(currentLesson, this.settings());
1415
+ if (conversationSettings) {
1416
+ this.uiStateService.chatDrawerVisible.set(true);
1289
1417
  }
1290
- catch (error) {
1291
- console.error('Error generating agent cards:', error);
1292
- this.toastrService.error({ subtitle: 'An error occurred while preparing the AI chat.', title: 'Error' });
1418
+ else {
1419
+ this.toastrService.error({ subtitle: 'Could not prepare the AI chat session.', title: 'Error' });
1293
1420
  }
1294
1421
  }
1295
1422
  onVisibleChange(isVisible) {
1296
1423
  if (isVisible === false) {
1297
- this.chatVisible.set(false);
1424
+ this.uiStateService.chatDrawerVisible.set(false);
1298
1425
  }
1299
1426
  }
1300
- handleGoalCompleted(event) {
1427
+ async handleGoalCompleted(event = {}) {
1301
1428
  console.log('Goal completed:', event);
1302
1429
  const lesson = this.lesson();
1303
- const dummy = { id: lesson.id, goalCompleted: true, score: 100, status: 'finished', lastAccess: new Date() };
1304
- this.lessonService.saveTakenLesson(dummy);
1430
+ const takenLesson = { id: lesson.id, goalCompleted: true, score: 100, status: 'finished', lastAccess: new Date() };
1431
+ const res = await this.lessonsService.saveTakenLesson(takenLesson);
1432
+ if (res) {
1433
+ // this.lessonsMemStateService.updateUserState(res);
1434
+ }
1305
1435
  this.toastrService.success({ subtitle: '¡Has completado la lección! , pero puedes seguir conversando', title: '¡Muy bien, guardaremos tu progreso!' });
1306
1436
  }
1307
1437
  onChatMessage(event) {
@@ -1318,29 +1448,25 @@ class DCLessonRendererComponent {
1318
1448
  console.log('Unhandled chat event type:', event.type);
1319
1449
  }
1320
1450
  }
1321
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DCLessonRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1322
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.4", type: DCLessonRendererComponent, isStandalone: true, selector: "dc-lesson-renderer", inputs: { lessonInput: { classPropertyName: "lessonInput", publicName: "lessonInput", isSignal: true, isRequired: false, transformFunction: null }, lessonIdInput: { classPropertyName: "lessonIdInput", publicName: "lessonIdInput", isSignal: true, isRequired: false, transformFunction: null }, settings: { classPropertyName: "settings", publicName: "settings", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { wordClicked: "wordClicked" }, viewQueries: [{ propertyName: "dynamicLesson", first: true, predicate: ["dynamicLesson"], descendants: true, static: true }], ngImport: i0, template: "<div>\n <div #dynamicLesson class=\"targetclass\">\n <ng-template #target></ng-template>\n </div>\n</div>\n\n<br />\n<div style=\"display: flex; gap: 10px\">\n @if ((mainForm.controls | keyvalue)?.length) {\n <div>\n <p-button label=\"Calificar Lecci\u00F3n\" icon=\"pi pi-check-circle\" (click)=\"evaluateForms()\" [rounded]=\"true\"></p-button>\n </div>\n }\n\n <p-button icon=\"pi pi-verified\" [rounded]=\"true\" (click)=\"startAI()\" label=\"Repasar con IA\" />\n</div>\n<br /><br />\n\n@if(chatVisible()) {\n<p-drawer header=\"Conversation\" [visible]=\"chatVisible()\" (visibleChange)=\"onVisibleChange($event)\" position=\"bottom\" styleClass=\"app-bottom-overlay\">\n <dc-chat\n [backgroundTasks]=\"backgroundTasks\"\n [conversationSettings]=\"conversationSettings()\"\n (goalCompleted)=\"handleGoalCompleted($event)\"\n (sendMessage)=\"onChatMessage($event)\"></dc-chat>\n</p-drawer>\n}\n", styles: [".evaluate{float:right}\n"], dependencies: [{ kind: "pipe", type: KeyValuePipe, name: "keyvalue" }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: DCChatComponent, selector: "dc-chat", inputs: ["chatUserSettings", "conversationSettings", "agentCard", "backgroundTasks", "taskOnUserMessage", "taskOnAssistantMessage", "parseDict"], outputs: ["sendMessage", "goalCompleted"] }, { kind: "ngmodule", type: DrawerModule }, { kind: "component", type: i2$2.Drawer, selector: "p-drawer", inputs: ["appendTo", "blockScroll", "style", "styleClass", "ariaCloseLabel", "autoZIndex", "baseZIndex", "modal", "closeButtonProps", "dismissible", "showCloseIcon", "closeOnEscape", "transitionOptions", "visible", "position", "fullScreen", "header", "maskStyle", "closable"], outputs: ["onShow", "onHide", "visibleChange"] }] }); }
1451
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DCLessonRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1452
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.6", type: DCLessonRendererComponent, isStandalone: true, selector: "dc-lesson-renderer", inputs: { lessonInput: { classPropertyName: "lessonInput", publicName: "lessonInput", isSignal: true, isRequired: false, transformFunction: null }, lessonIdInput: { classPropertyName: "lessonIdInput", publicName: "lessonIdInput", isSignal: true, isRequired: false, transformFunction: null }, settings: { classPropertyName: "settings", publicName: "settings", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { wordClicked: "wordClicked" }, viewQueries: [{ propertyName: "dynamicLesson", first: true, predicate: ["dynamicLesson"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (lesson()?.format === 'markdown') {\n<h3>Mostrando markdown</h3>\n\n<markdown>\n {{ lesson()?.markdown }}\n</markdown>\n} @else {\n<h5>Lesson not available</h5>\n<div>\n <div #dynamicLesson class=\"targetclass\">\n <ng-template #target></ng-template>\n </div>\n</div>\n}\n\n<br />\n<div style=\"display: flex; gap: 10px\">\n @if ((mainForm.controls | keyvalue)?.length) {\n <div>\n <p-button label=\"Calificar Lecci\u00F3n\" icon=\"pi pi-check-circle\" (click)=\"evaluateForms()\" [rounded]=\"true\"></p-button>\n </div>\n }\n\n <p-button icon=\"pi pi-verified\" [rounded]=\"true\" (click)=\"startAI()\" label=\"Repasar con IA\" />\n</div>\n<br /><br />\n\n@if(uiStateService.chatDrawerVisible()) {\n<p-drawer\n header=\"Conversation\"\n [visible]=\"uiStateService.chatDrawerVisible()\"\n (visibleChange)=\"onVisibleChange($event)\"\n position=\"bottom\"\n styleClass=\"app-bottom-overlay\">\n <dc-chat\n [conversationFlow]=\"lessonConversationService.conversationFlow()\"\n [conversationSettings]=\"lessonConversationService.conversationSettings()\"\n (goalCompleted)=\"handleGoalCompleted($event)\"\n (chatEvent)=\"onChatMessage($event)\"></dc-chat>\n</p-drawer>\n}\n", styles: ["::ng-deep .targetclass *:not(h1,h2,h3,h4,h5,h6){font-family:\"math\",sans-serif,system-ui,monospace!important}\n"], dependencies: [{ kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: DCChatComponent, selector: "dc-chat", inputs: ["chatUserSettings", "conversationSettings", "conversationFlow", "agentCard", "parseDict"], outputs: ["chatEvent", "goalCompleted"] }, { kind: "ngmodule", type: DrawerModule }, { kind: "component", type: i2$2.Drawer, selector: "p-drawer", inputs: ["appendTo", "blockScroll", "style", "styleClass", "ariaCloseLabel", "autoZIndex", "baseZIndex", "modal", "closeButtonProps", "dismissible", "showCloseIcon", "closeOnEscape", "transitionOptions", "visible", "position", "fullScreen", "header", "maskStyle", "closable"], outputs: ["onShow", "onHide", "visibleChange"] }, { kind: "component", type: MarkdownComponent, selector: "markdown, [markdown]", inputs: ["data", "src", "disableSanitizer", "inline", "clipboard", "clipboardButtonComponent", "clipboardButtonTemplate", "emoji", "katex", "katexOptions", "mermaid", "mermaidOptions", "lineHighlight", "line", "lineOffset", "lineNumbers", "start", "commandLine", "filterOutput", "host", "prompt", "output", "user"], outputs: ["error", "load", "ready"] }, { kind: "pipe", type: KeyValuePipe, name: "keyvalue" }] }); }
1323
1453
  }
1324
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DCLessonRendererComponent, decorators: [{
1454
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DCLessonRendererComponent, decorators: [{
1325
1455
  type: Component,
1326
- args: [{ selector: 'dc-lesson-renderer', standalone: true, imports: [KeyValuePipe, ButtonModule, DCChatComponent, DrawerModule], template: "<div>\n <div #dynamicLesson class=\"targetclass\">\n <ng-template #target></ng-template>\n </div>\n</div>\n\n<br />\n<div style=\"display: flex; gap: 10px\">\n @if ((mainForm.controls | keyvalue)?.length) {\n <div>\n <p-button label=\"Calificar Lecci\u00F3n\" icon=\"pi pi-check-circle\" (click)=\"evaluateForms()\" [rounded]=\"true\"></p-button>\n </div>\n }\n\n <p-button icon=\"pi pi-verified\" [rounded]=\"true\" (click)=\"startAI()\" label=\"Repasar con IA\" />\n</div>\n<br /><br />\n\n@if(chatVisible()) {\n<p-drawer header=\"Conversation\" [visible]=\"chatVisible()\" (visibleChange)=\"onVisibleChange($event)\" position=\"bottom\" styleClass=\"app-bottom-overlay\">\n <dc-chat\n [backgroundTasks]=\"backgroundTasks\"\n [conversationSettings]=\"conversationSettings()\"\n (goalCompleted)=\"handleGoalCompleted($event)\"\n (sendMessage)=\"onChatMessage($event)\"></dc-chat>\n</p-drawer>\n}\n", styles: [".evaluate{float:right}\n"] }]
1456
+ args: [{ selector: 'dc-lesson-renderer', standalone: true, imports: [KeyValuePipe, ButtonModule, DCChatComponent, DrawerModule, MarkdownComponent], template: "@if (lesson()?.format === 'markdown') {\n<h3>Mostrando markdown</h3>\n\n<markdown>\n {{ lesson()?.markdown }}\n</markdown>\n} @else {\n<h5>Lesson not available</h5>\n<div>\n <div #dynamicLesson class=\"targetclass\">\n <ng-template #target></ng-template>\n </div>\n</div>\n}\n\n<br />\n<div style=\"display: flex; gap: 10px\">\n @if ((mainForm.controls | keyvalue)?.length) {\n <div>\n <p-button label=\"Calificar Lecci\u00F3n\" icon=\"pi pi-check-circle\" (click)=\"evaluateForms()\" [rounded]=\"true\"></p-button>\n </div>\n }\n\n <p-button icon=\"pi pi-verified\" [rounded]=\"true\" (click)=\"startAI()\" label=\"Repasar con IA\" />\n</div>\n<br /><br />\n\n@if(uiStateService.chatDrawerVisible()) {\n<p-drawer\n header=\"Conversation\"\n [visible]=\"uiStateService.chatDrawerVisible()\"\n (visibleChange)=\"onVisibleChange($event)\"\n position=\"bottom\"\n styleClass=\"app-bottom-overlay\">\n <dc-chat\n [conversationFlow]=\"lessonConversationService.conversationFlow()\"\n [conversationSettings]=\"lessonConversationService.conversationSettings()\"\n (goalCompleted)=\"handleGoalCompleted($event)\"\n (chatEvent)=\"onChatMessage($event)\"></dc-chat>\n</p-drawer>\n}\n", styles: ["::ng-deep .targetclass *:not(h1,h2,h3,h4,h5,h6){font-family:\"math\",sans-serif,system-ui,monospace!important}\n"] }]
1327
1457
  }], ctorParameters: () => [], propDecorators: { wordClicked: [{
1328
1458
  type: Output
1329
- }], dynamicLesson: [{
1330
- type: ViewChild,
1331
- args: ['dynamicLesson', { static: true }]
1332
1459
  }] } });
1333
1460
 
1334
1461
  class LessonNotionService {
1335
1462
  constructor() {
1336
1463
  this.#notionService = inject(NOTION_SERVICE_TOKEN);
1337
- this.#lessonService = inject(LESSONS_TOKEN);
1464
+ this.lessonsService = inject(LESSONS_TOKEN, { optional: true }) ?? inject(DefaultLessonsService);
1338
1465
  this.#toastService = inject(TOAST_ALERTS_TOKEN);
1339
1466
  // Keep track of loading state specific to Notion operations
1340
- this.isLoading = signal(false);
1467
+ this.isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
1341
1468
  }
1342
1469
  #notionService;
1343
- #lessonService;
1344
1470
  #toastService;
1345
1471
  /**
1346
1472
  * Extracts the Notion Page ID from a URL.
@@ -1374,14 +1500,17 @@ class LessonNotionService {
1374
1500
  }
1375
1501
  const updatedLesson = {
1376
1502
  ...lesson,
1377
- extras: {
1378
- ...(lesson.extras || {}),
1379
- notionPageId: notionPageId,
1503
+ extensions: {
1504
+ ...(lesson.extensions || {}),
1505
+ extras: {
1506
+ ...(lesson.extensions?.['extras'] || {}),
1507
+ notionPageId: notionPageId,
1508
+ },
1380
1509
  },
1381
1510
  };
1382
1511
  this.isLoading.set(true);
1383
1512
  try {
1384
- const savedLesson = await this.#lessonService.postLesson(updatedLesson);
1513
+ const savedLesson = await this.lessonsService.postLesson(updatedLesson);
1385
1514
  this.#toastService.success({ title: 'Listo', subtitle: 'Se enlazó la lección con Notion.' });
1386
1515
  return savedLesson;
1387
1516
  }
@@ -1407,10 +1536,10 @@ class LessonNotionService {
1407
1536
  if (!currentLesson)
1408
1537
  return null;
1409
1538
  let notionPageId = null;
1410
- if (currentLesson.extras?.notionPageId) {
1411
- const useExisting = confirm(`Ya tenemos el id ${currentLesson.extras.notionPageId} ¿Quieres usar este id para importar?`);
1539
+ if (currentLesson.extensions?.['extras']?.['notionPageId']) {
1540
+ const useExisting = confirm(`Ya tenemos el id ${currentLesson.extensions?.['extras']?.['notionPageId']} ¿Quieres usar este id para importar?`);
1412
1541
  if (useExisting) {
1413
- notionPageId = currentLesson.extras.notionPageId;
1542
+ notionPageId = currentLesson.extensions?.['extras']?.['notionPageId'];
1414
1543
  }
1415
1544
  else {
1416
1545
  const inputUrl = prompt('Ingresa la NUEVA URL de Notion para importar (este ID NO se guardará automáticamente si la lección ya existe)');
@@ -1465,7 +1594,7 @@ class LessonNotionService {
1465
1594
  async improveLessonWithNotionAI(lesson) {
1466
1595
  if (!lesson)
1467
1596
  return;
1468
- const notionId = lesson.extras?.notionPageId;
1597
+ const notionId = lesson.extensions?.['extras']?.['notionPageId'];
1469
1598
  if (!notionId) {
1470
1599
  this.#toastService.warn({ title: 'Sin ID de Notion', subtitle: 'Enlaza la lección con Notion primero.' });
1471
1600
  return;
@@ -1489,22 +1618,21 @@ class LessonNotionService {
1489
1618
  this.isLoading.set(false);
1490
1619
  }
1491
1620
  }
1492
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: LessonNotionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1493
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: LessonNotionService }); }
1621
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: LessonNotionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1622
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: LessonNotionService }); }
1494
1623
  }
1495
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: LessonNotionService, decorators: [{
1624
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: LessonNotionService, decorators: [{
1496
1625
  type: Injectable
1497
1626
  }] });
1498
1627
 
1499
1628
  // import { UserDataExchangeService } from '@dataclouder/ngx-agent-cards';
1500
1629
  class LessonUtilsService {
1501
1630
  constructor() {
1502
- this.#lessonService = inject(LESSONS_TOKEN);
1631
+ this.lessonsService = inject(LESSONS_TOKEN, { optional: true }) ?? inject(DefaultLessonsService);
1503
1632
  this.#toastService = inject(TOAST_ALERTS_TOKEN);
1504
1633
  this.#agentService = inject(CONVERSATION_AI_TOKEN);
1505
1634
  this.loadingBarService = inject(LoadingBarService);
1506
1635
  }
1507
- #lessonService;
1508
1636
  #toastService;
1509
1637
  #agentService;
1510
1638
  /**
@@ -1529,10 +1657,11 @@ class LessonUtilsService {
1529
1657
  lessonSignal.update((currentLesson) => {
1530
1658
  if (!currentLesson)
1531
1659
  return undefined;
1532
- const updatedMetadata = { ...(currentLesson.metadata ?? {}), banner: imageUploaded };
1660
+ const assets = { ...(currentLesson.assets ?? {}) };
1661
+ assets.banner = imageUploaded;
1533
1662
  return {
1534
1663
  ...currentLesson,
1535
- metadata: updatedMetadata,
1664
+ assets,
1536
1665
  };
1537
1666
  });
1538
1667
  }
@@ -1550,9 +1679,9 @@ class LessonUtilsService {
1550
1679
  }
1551
1680
  // No need to save here, component should ensure it's saved before calling.
1552
1681
  try {
1553
- await this.#lessonService.postGenerateByAI(lessonId);
1682
+ await this.lessonsService.postGenerateByAI(lessonId);
1554
1683
  // Re-fetch the lesson data to get AI updates
1555
- const updatedLesson = await this.#lessonService.getLesson(lessonId);
1684
+ const updatedLesson = await this.lessonsService.getLesson(lessonId);
1556
1685
  if (updatedLesson) {
1557
1686
  this.#toastService.success({ title: 'IA completada', subtitle: 'Lección actualizada con IA.' });
1558
1687
  return updatedLesson;
@@ -1583,7 +1712,7 @@ class LessonUtilsService {
1583
1712
  }
1584
1713
  try {
1585
1714
  this.loadingBarService.showIndeterminate();
1586
- const textPrompt = this.#lessonService.getPrompts().content(lesson);
1715
+ const textPrompt = this.lessonsService.getPrompts().content(lesson);
1587
1716
  const messages = [{ content: textPrompt, role: ChatRole.User }];
1588
1717
  const response = await this.#agentService.callChatCompletion({ messages, model: { provider: 'google' } });
1589
1718
  let improvedMarkdown = response.content?.trim() ?? null;
@@ -1635,7 +1764,7 @@ class LessonUtilsService {
1635
1764
  this.#toastService.warn({ title: 'Texto Vacío', subtitle: 'No se pudo extraer texto útil del contenido de la lección.' });
1636
1765
  return null;
1637
1766
  }
1638
- const descriptionPrompt = this.#lessonService.getPrompts().description(lesson);
1767
+ const descriptionPrompt = this.lessonsService.getPrompts().description(lesson);
1639
1768
  const messages = [{ content: descriptionPrompt, role: ChatRole.User }];
1640
1769
  const response = await this.#agentService.callChatCompletion({ messages, model: { provider: 'google' } });
1641
1770
  let generatedDescription = response.content?.trim() ?? null;
@@ -1742,10 +1871,10 @@ class LessonUtilsService {
1742
1871
  dynamicComponents: cleanedDynamicComponents,
1743
1872
  };
1744
1873
  }
1745
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: LessonUtilsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1746
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: LessonUtilsService, providedIn: 'root' }); }
1874
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: LessonUtilsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1875
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: LessonUtilsService, providedIn: 'root' }); }
1747
1876
  }
1748
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: LessonUtilsService, decorators: [{
1877
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: LessonUtilsService, decorators: [{
1749
1878
  type: Injectable,
1750
1879
  args: [{
1751
1880
  providedIn: 'root', // Provide globally or in a specific module if preferred
@@ -1775,10 +1904,10 @@ class DynamicComponentsBuilderService {
1775
1904
  });
1776
1905
  return dialogRef;
1777
1906
  }
1778
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DynamicComponentsBuilderService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1779
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DynamicComponentsBuilderService, providedIn: 'root' }); }
1907
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DynamicComponentsBuilderService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1908
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DynamicComponentsBuilderService, providedIn: 'root' }); }
1780
1909
  }
1781
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DynamicComponentsBuilderService, decorators: [{
1910
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DynamicComponentsBuilderService, decorators: [{
1782
1911
  type: Injectable,
1783
1912
  args: [{
1784
1913
  providedIn: 'root',
@@ -1812,10 +1941,10 @@ class DCLessonComponentAdderComponent {
1812
1941
  console.warn(`Dialog could not be opened for type via component: ${type}`);
1813
1942
  }
1814
1943
  }
1815
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DCLessonComponentAdderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1816
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.4", type: DCLessonComponentAdderComponent, isStandalone: true, selector: "dc-lesson-component-adder", outputs: { componentAdded: "componentAdded" }, providers: [DialogService], ngImport: i0, template: "<span>Componentes: </span>\n<div style=\"display: flex; gap: 10px; flex-wrap: wrap\">\n <p-button\n severity=\"info\"\n (click)=\"openComponentBuilder(lessonComponentEnum.Selector)\"\n pTooltip=\"Agrega un selector con multiples opciones\"\n tooltipPosition=\"bottom\">\n Selector\n </p-button>\n <p-button\n severity=\"info\"\n (click)=\"openComponentBuilder(lessonComponentEnum.Speaker)\"\n pTooltip=\"Para que una palabra o frase sea reproducible\"\n tooltipPosition=\"bottom\">\n Speaker\n </p-button>\n <p-button\n severity=\"info\"\n (click)=\"openComponentBuilder(lessonComponentEnum.TextWriter)\"\n pTooltip=\"Escribe una respuesta en un cuadro de texto\"\n tooltipPosition=\"bottom\">\n Text\n </p-button>\n <p-button\n severity=\"info\"\n (click)=\"openComponentBuilder(lessonComponentEnum.VerbSummary)\"\n pTooltip=\"Muestra la informaci\u00F3n de un verbo\"\n tooltipPosition=\"bottom\">\n Verb\n </p-button>\n <p-button\n severity=\"info\"\n (click)=\"openComponentBuilder(lessonComponentEnum.WordSummary)\"\n pTooltip=\"Muestra la informaci\u00F3n de una palabra\"\n tooltipPosition=\"bottom\">\n Palabra\n </p-button>\n <p-button\n severity=\"info\"\n (click)=\"openComponentBuilder(lessonComponentEnum.TranslationSwitcher)\"\n pTooltip=\"Muestra el texto pero al pica cambia de idioma\"\n tooltipPosition=\"bottom\">\n Traducci\u00F3n\n </p-button>\n <p-button\n severity=\"info\"\n (click)=\"openComponentBuilder(lessonComponentEnum.PlayWord)\"\n pTooltip=\"Muestra el texto pero al pica cambia de idioma\"\n tooltipPosition=\"bottom\">\n Play Word\n </p-button>\n <!-- Add other buttons here if needed, following the same pattern -->\n</div>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i6.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }] }); }
1944
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DCLessonComponentAdderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1945
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.6", type: DCLessonComponentAdderComponent, isStandalone: true, selector: "dc-lesson-component-adder", outputs: { componentAdded: "componentAdded" }, providers: [DialogService], ngImport: i0, template: "<span>Componentes: </span>\n<div style=\"display: flex; gap: 10px; flex-wrap: wrap\">\n <p-button\n severity=\"info\"\n (click)=\"openComponentBuilder(lessonComponentEnum.Selector)\"\n pTooltip=\"Agrega un selector con multiples opciones\"\n tooltipPosition=\"bottom\">\n Selector\n </p-button>\n <p-button\n severity=\"info\"\n (click)=\"openComponentBuilder(lessonComponentEnum.Speaker)\"\n pTooltip=\"Para que una palabra o frase sea reproducible\"\n tooltipPosition=\"bottom\">\n Speaker\n </p-button>\n <p-button\n severity=\"info\"\n (click)=\"openComponentBuilder(lessonComponentEnum.TextWriter)\"\n pTooltip=\"Escribe una respuesta en un cuadro de texto\"\n tooltipPosition=\"bottom\">\n Text\n </p-button>\n <p-button\n severity=\"info\"\n (click)=\"openComponentBuilder(lessonComponentEnum.VerbSummary)\"\n pTooltip=\"Muestra la informaci\u00F3n de un verbo\"\n tooltipPosition=\"bottom\">\n Verb\n </p-button>\n <p-button\n severity=\"info\"\n (click)=\"openComponentBuilder(lessonComponentEnum.WordSummary)\"\n pTooltip=\"Muestra la informaci\u00F3n de una palabra\"\n tooltipPosition=\"bottom\">\n Palabra\n </p-button>\n <p-button\n severity=\"info\"\n (click)=\"openComponentBuilder(lessonComponentEnum.TranslationSwitcher)\"\n pTooltip=\"Muestra el texto pero al pica cambia de idioma\"\n tooltipPosition=\"bottom\">\n Traducci\u00F3n\n </p-button>\n <p-button\n severity=\"info\"\n (click)=\"openComponentBuilder(lessonComponentEnum.PlayWord)\"\n pTooltip=\"Muestra el texto pero al pica cambia de idioma\"\n tooltipPosition=\"bottom\">\n Play Word\n </p-button>\n <!-- Add other buttons here if needed, following the same pattern -->\n</div>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i7.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo"] }] }); }
1817
1946
  }
1818
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DCLessonComponentAdderComponent, decorators: [{
1947
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DCLessonComponentAdderComponent, decorators: [{
1819
1948
  type: Component,
1820
1949
  args: [{ selector: 'dc-lesson-component-adder', standalone: true, imports: [CommonModule, ButtonModule, TooltipModule], providers: [DialogService], template: "<span>Componentes: </span>\n<div style=\"display: flex; gap: 10px; flex-wrap: wrap\">\n <p-button\n severity=\"info\"\n (click)=\"openComponentBuilder(lessonComponentEnum.Selector)\"\n pTooltip=\"Agrega un selector con multiples opciones\"\n tooltipPosition=\"bottom\">\n Selector\n </p-button>\n <p-button\n severity=\"info\"\n (click)=\"openComponentBuilder(lessonComponentEnum.Speaker)\"\n pTooltip=\"Para que una palabra o frase sea reproducible\"\n tooltipPosition=\"bottom\">\n Speaker\n </p-button>\n <p-button\n severity=\"info\"\n (click)=\"openComponentBuilder(lessonComponentEnum.TextWriter)\"\n pTooltip=\"Escribe una respuesta en un cuadro de texto\"\n tooltipPosition=\"bottom\">\n Text\n </p-button>\n <p-button\n severity=\"info\"\n (click)=\"openComponentBuilder(lessonComponentEnum.VerbSummary)\"\n pTooltip=\"Muestra la informaci\u00F3n de un verbo\"\n tooltipPosition=\"bottom\">\n Verb\n </p-button>\n <p-button\n severity=\"info\"\n (click)=\"openComponentBuilder(lessonComponentEnum.WordSummary)\"\n pTooltip=\"Muestra la informaci\u00F3n de una palabra\"\n tooltipPosition=\"bottom\">\n Palabra\n </p-button>\n <p-button\n severity=\"info\"\n (click)=\"openComponentBuilder(lessonComponentEnum.TranslationSwitcher)\"\n pTooltip=\"Muestra el texto pero al pica cambia de idioma\"\n tooltipPosition=\"bottom\">\n Traducci\u00F3n\n </p-button>\n <p-button\n severity=\"info\"\n (click)=\"openComponentBuilder(lessonComponentEnum.PlayWord)\"\n pTooltip=\"Muestra el texto pero al pica cambia de idioma\"\n tooltipPosition=\"bottom\">\n Play Word\n </p-button>\n <!-- Add other buttons here if needed, following the same pattern -->\n</div>\n" }]
1821
1950
  }], propDecorators: { componentAdded: [{
@@ -1824,111 +1953,80 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImpor
1824
1953
 
1825
1954
  class DCLessonMetadataEditorComponent {
1826
1955
  constructor() {
1827
- // Use signal for input lesson data
1828
- this.lesson = signal(undefined); // The lesson data itself
1829
- this.isLoadingLesson = signal(false); // Shared loading state
1830
1956
  // Outputs for actions
1831
1957
  this.saveRequest = new EventEmitter();
1832
1958
  this.importNotionRequest = new EventEmitter();
1833
1959
  this.improveNotionRequest = new EventEmitter();
1834
- // Removed generateAIRequest Output as it's handled internally now
1835
- // Output removed as the component now updates the input signal directly.
1836
- // @Output() propertyChange = new EventEmitter<{ propertyPath: string; value: any }>();
1837
1960
  // Injected Services
1838
1961
  this.#lessonUtilsService = inject(LessonUtilsService);
1839
1962
  this.#toastService = inject(TOAST_ALERTS_TOKEN);
1840
- this.#lessonService = inject(LESSONS_TOKEN);
1841
- this.#turndownService = new TurndownService(); // Instantiate TurndownService
1963
+ this.lessonsService = inject(LESSONS_TOKEN, { optional: true }) ?? inject(DefaultLessonsService);
1964
+ this.turndownService = new TurndownService(); // Instantiate TurndownService
1842
1965
  }
1843
- // Removed generateAIRequest Output as it's handled internally now
1844
- // Output removed as the component now updates the input signal directly.
1845
- // @Output() propertyChange = new EventEmitter<{ propertyPath: string; value: any }>();
1846
1966
  // Injected Services
1847
1967
  #lessonUtilsService;
1848
1968
  #toastService;
1849
- #lessonService;
1850
- #turndownService; // Instantiate TurndownService
1851
- // Method to handle property changes for ROOT properties (e.g., level)
1852
- onRootPropertyChange(property, value) {
1853
- this.lesson.update((current) => {
1854
- if (!current)
1855
- return undefined;
1856
- // Avoid updating metadata directly here
1857
- if (property === 'metadata') {
1858
- console.warn('Direct metadata updates should use onMetadataPropertyChange');
1859
- return current;
1860
- }
1861
- return { ...current, [property]: value };
1862
- });
1863
- // Emit removed - signal is updated directly above.
1864
- // this.propertyChange.emit({ propertyPath: property, value });
1865
- }
1866
- // Method to handle property changes for METADATA properties
1867
- onMetadataPropertyChange(property, value) {
1868
- this.lesson.update((current) => {
1869
- if (!current)
1870
- return undefined;
1871
- const updatedMetadata = { ...(current.metadata ?? {}), [property]: value };
1872
- return { ...current, metadata: updatedMetadata };
1873
- });
1874
- }
1875
- // Method to handle property changes for APP EXTENSION properties
1876
- onAppExtensionPropChange(property, value) {
1877
- this.lesson.update((current) => {
1878
- if (!current)
1879
- return undefined;
1880
- // Ensure appExtension exists, initialize if not
1881
- // Convert value to number specifically for 'level'
1882
- const finalValue = property === 'level' ? Number(value) : value;
1883
- const updatedAppExtension = { ...(current.appExtension ?? {}), [property]: finalValue };
1884
- return { ...current, appExtension: updatedAppExtension };
1885
- });
1886
- }
1887
- // Methods to emit action requests
1888
- emitSaveRequest() {
1889
- this.saveRequest.emit();
1890
- }
1891
- emitImportNotionRequest() {
1892
- this.importNotionRequest.emit();
1893
- }
1894
- emitImproveNotionRequest() {
1895
- this.improveNotionRequest.emit();
1969
+ ngOnInit() {
1970
+ // console.log(this.lesson(), this.form);
1971
+ }
1972
+ onManageablePropertyChange(property, value) {
1973
+ // this.lesson.update((current) => {
1974
+ // if (!current) return undefined;
1975
+ // const updatedManageable = { ...(current.manageable ?? {}), [property]: value };
1976
+ // return { ...current, manageable: updatedManageable as IManageable };
1977
+ // });
1978
+ }
1979
+ onAuditablePropertyChange(property, value) {
1980
+ // this.lesson.update((current) => {
1981
+ // if (!current) return undefined;
1982
+ // const updatedAuditable = { ...(current.auditable ?? {}), [property]: value };
1983
+ // return { ...current, auditable: updatedAuditable as IAuditable };
1984
+ // });
1985
+ }
1986
+ // New methods to handle events with proper casting
1987
+ handlePromptInputChange(event) {
1988
+ const target = event.target;
1989
+ this.onAuditablePropertyChange('prompt', target.value);
1990
+ }
1991
+ handleStatusChange(event) {
1992
+ const target = event.target;
1993
+ this.onManageablePropertyChange('status', target.checked ? 'published' : 'draft');
1896
1994
  }
1897
1995
  /**
1898
1996
  * Generates lesson content using AI, saving the current state first.
1899
1997
  * Moved from DCLessonEditorComponent.
1900
1998
  */
1901
1999
  async generateByAI() {
1902
- const currentLesson = this.lesson(); // Get current value
2000
+ const currentLesson = this.lesson; // Get current value
1903
2001
  if (!currentLesson?.id) {
1904
2002
  this.#toastService.warn({ title: 'Guardar primero', subtitle: 'Guarda la lección antes de usar IA.' });
1905
2003
  return;
1906
2004
  }
1907
- this.isLoadingLesson.set(true);
2005
+ this.isLoadingLesson = true;
1908
2006
  try {
1909
2007
  const rawHtmlContent = currentLesson.textCoded || '';
1910
2008
  if (!rawHtmlContent) {
1911
2009
  console.warn('No HTML content found in lesson to process. taking just description');
1912
2010
  this.#toastService.info({ title: 'Contenido lección desde 0', subtitle: 'Solo se usará el prompt' });
1913
- const improvedMarkdown = await this.#lessonUtilsService.improveMDWithAI(this.lesson(), 'Create content from description');
2011
+ const improvedMarkdown = await this.#lessonUtilsService.improveMDWithAI(this.lesson, 'Create content from description');
1914
2012
  // Convert and save the generated content
1915
2013
  await this._convertMarkdownToHtmlAndSave(improvedMarkdown); // Use extracted method
1916
2014
  }
1917
2015
  else {
1918
2016
  // Clean orphaned and Save before Improve
1919
2017
  const lessonToSave = this.#lessonUtilsService.cleanOrphanedComponents(currentLesson);
1920
- const savedLesson = await this.#lessonService.postLesson(lessonToSave);
2018
+ const savedLesson = await this.lessonsService.postLesson(lessonToSave);
1921
2019
  if (!savedLesson) {
1922
2020
  this.#toastService.error({ title: 'Error al guardar', subtitle: 'No se pudo guardar antes de generar con IA.' });
1923
2021
  throw new Error('Failed to save before AI generation');
1924
2022
  }
1925
- this.lesson.set(savedLesson);
2023
+ this.lesson = savedLesson;
1926
2024
  // Replace encoded JSON with actual text before Markdown conversion
1927
2025
  const processedHtmlContent = this._extractTextFromEncodedJson(rawHtmlContent);
1928
2026
  // Convert the processed HTML (with text instead of JSON) to Markdown
1929
- const markdownText = this.#turndownService.turndown(processedHtmlContent);
2027
+ const markdownText = this.turndownService.turndown(processedHtmlContent);
1930
2028
  // Use the updated lesson signal value for AI improvement
1931
- const improvedMarkdown = await this.#lessonUtilsService.improveMDWithAI(this.lesson(), markdownText);
2029
+ const improvedMarkdown = await this.#lessonUtilsService.improveMDWithAI(this.lesson, markdownText);
1932
2030
  // Convert and save the improved content
1933
2031
  await this._convertMarkdownToHtmlAndSave(improvedMarkdown); // Use extracted method
1934
2032
  }
@@ -1939,7 +2037,7 @@ class DCLessonMetadataEditorComponent {
1939
2037
  // this.#toastService.error({ title: 'Error General', subtitle: 'Ocurrió un problema durante el proceso de IA.' });
1940
2038
  }
1941
2039
  finally {
1942
- this.isLoadingLesson.set(false); // Stop loading
2040
+ this.isLoadingLesson = false; // Stop loading
1943
2041
  }
1944
2042
  }
1945
2043
  /**
@@ -1975,12 +2073,12 @@ class DCLessonMetadataEditorComponent {
1975
2073
  // Convert the improved Markdown back to HTML before setting it
1976
2074
  const improvedHtml = marked(improvedMarkdown);
1977
2075
  // Update the signal directly
1978
- this.lesson.update((current) => (current ? { ...current, textCoded: improvedHtml } : undefined));
2076
+ // this.lesson.update((current) => (current ? { ...current, textCoded: improvedHtml } : undefined));
1979
2077
  // Save the AI-generated content
1980
2078
  // Ensure lesson() is not undefined before saving
1981
- const lessonToSave = this.lesson();
2079
+ const lessonToSave = this.lesson;
1982
2080
  if (lessonToSave) {
1983
- await this.#lessonService.postLesson(lessonToSave);
2081
+ await this.lessonsService.postLesson(lessonToSave);
1984
2082
  this.#toastService.success({ title: 'Contenido generado', subtitle: 'Se generó y guardó el contenido con IA.' });
1985
2083
  }
1986
2084
  else {
@@ -2003,37 +2101,40 @@ class DCLessonMetadataEditorComponent {
2003
2101
  * and updates the lesson signal if successful.
2004
2102
  */
2005
2103
  async triggerGenerateDescriptionAI() {
2006
- const currentLesson = this.lesson();
2104
+ const currentLesson = this.lesson;
2007
2105
  if (!currentLesson) {
2008
2106
  this.#toastService.warn({ title: 'Lección no cargada', subtitle: 'Espera a que la lección se cargue.' });
2009
2107
  return;
2010
2108
  }
2011
2109
  const generatedDescription = await this.#lessonUtilsService.generateDescriptionWithAI(currentLesson);
2012
2110
  if (generatedDescription) {
2013
- // Use the new method for metadata properties
2014
- this.onMetadataPropertyChange('description', generatedDescription);
2111
+ // this.form.controls['description'].setValue(generatedDescription);
2015
2112
  }
2016
2113
  }
2017
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DCLessonMetadataEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2018
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.4", type: DCLessonMetadataEditorComponent, isStandalone: true, selector: "dc-lesson-metadata-editor", inputs: { lesson: "lesson", isLoadingLesson: "isLoadingLesson" }, outputs: { saveRequest: "saveRequest", importNotionRequest: "importNotionRequest", improveNotionRequest: "improveNotionRequest" }, ngImport: i0, template: "@if (lesson(); as currentLesson) {\n<div>\n <div>\n <div style=\"display: flex; gap: 10px; padding: 10px\">\n <p-button label=\"Guardar\" severity=\"primary\" (click)=\"emitSaveRequest()\" />\n <p-button label=\"Importar de Notion\" severity=\"help\" (click)=\"emitImportNotionRequest()\" />\n <p-button label=\"Mejorar Notion con AI\" severity=\"help\" (click)=\"emitImproveNotionRequest()\" />\n </div>\n\n <!-- Use one-way binding and ngModelChange for signals -->\n <div>\n <input\n pInputText\n style=\"width: 100%\"\n [ngModel]=\"currentLesson.metadata?.title\"\n (ngModelChange)=\"onMetadataPropertyChange('title', $event)\"\n type=\"text\"\n placeholder=\"Agrega un t\u00EDtulo\" />\n </div>\n <div style=\"margin-top: 4px\">\n <p-inputgroup>\n <input\n pInputText\n style=\"width: 100%\"\n [ngModel]=\"currentLesson.metadata?.description\"\n (ngModelChange)=\"onMetadataPropertyChange('description', $event)\"\n type=\"text\"\n placeholder=\"Agrega una descripci\u00F3n\" />\n <p-button\n icon=\"pi pi-sparkles\"\n styleClass=\"p-button-secondary p-button-outlined\"\n pTooltip=\"Generar descripci\u00F3n con IA\"\n tooltipPosition=\"top\"\n [disabled]=\"isLoadingLesson()\"\n (click)=\"triggerGenerateDescriptionAI()\" />\n </p-inputgroup>\n </div>\n\n <div style=\"display: flex; align-items: center; margin-top: 10px\">\n <input\n pInputText\n style=\"flex: auto; margin-right: 5px\"\n [ngModel]=\"currentLesson.metadata?.prompt\"\n (ngModelChange)=\"onMetadataPropertyChange('prompt', $event)\"\n type=\"text\"\n placeholder=\"Prompt para IA (opcional)\" />\n <p-button severity=\"primary\" label=\"Generar con IA\" icon=\"pi pi-sparkles\" [disabled]=\"isLoadingLesson()\" (click)=\"generateByAI()\" />\n </div>\n\n <div style=\"margin-top: 10px\">\n <label class=\"checkbox-container\" style=\"margin-right: 15px\">\n <input\n type=\"checkbox\"\n [ngModel]=\"currentLesson.metadata?.isPublished\"\n (ngModelChange)=\"onMetadataPropertyChange('isPublished', $event)\"\n title=\"Cuando termines la edici\u00F3n marca esta casilla\" />\n <span class=\"checkmark\"></span>\n Publicada\n </label>\n </div>\n\n <p-divider />\n\n <div style=\"display: flex; align-items: center; margin-top: 10px; gap: 10px\">\n <input\n pInputText\n [ngModel]=\"currentLesson.appExtension?.['level']\"\n (ngModelChange)=\"onAppExtensionPropChange('level', $event)\"\n type=\"number\"\n placeholder=\"Nivel\"\n style=\"width: 80px\" />\n\n <!-- Access signal values -->\n @if (currentLesson.appExtension) {\n <div>\n {{ currentLesson.appExtension?.['baseLang'] | flagEmoji }} -> {{ currentLesson.appExtension?.['targetLang'] | flagEmoji }} Lecci\u00F3n para hablantes de\n {{ currentLesson.appExtension?.['baseLang'] | langDesc : 'es' }} que aprenden\n {{ currentLesson.appExtension?.['targetLang'] | langDesc : 'es' }}\n </div>\n }\n </div>\n </div>\n</div>\n} @else {\n<!-- Optional: Show a loading state or placeholder if lesson is undefined -->\n<p>Cargando datos de la lecci\u00F3n...</p>\n}\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i3.InputText, selector: "[pInputText]", inputs: ["variant", "fluid", "pSize"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i6.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }, { kind: "pipe", type: // Added TooltipModule
2114
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DCLessonMetadataEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2115
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.6", type: DCLessonMetadataEditorComponent, isStandalone: true, selector: "dc-lesson-metadata-editor", inputs: { form: "form", lesson: "lesson", isLoadingLesson: "isLoadingLesson" }, outputs: { saveRequest: "saveRequest", importNotionRequest: "importNotionRequest", improveNotionRequest: "improveNotionRequest" }, ngImport: i0, template: "<div>\n <!-- <div style=\"display: flex; gap: 10px; padding: 10px\">\n <p-button label=\"Guardar\" severity=\"primary\" (click)=\"emitSaveRequest()\" />\n <p-button label=\"Importar de Notion\" severity=\"help\" (click)=\"emitImportNotionRequest()\" />\n <p-button label=\"Mejorar Notion con AI\" severity=\"help\" (click)=\"emitImproveNotionRequest()\" />\n </div> -->\n\n <div>\n <div>\n <span>Nombre de La lecci\u00F3n</span>\n <input pInputText style=\"width: 100%\" [formControl]=\"form.controls['name']\" type=\"text\" placeholder=\"Agrega un nombre\" />\n </div>\n <div>\n <span>T\u00EDtulo </span>\n <input pInputText style=\"width: 100%\" [formControl]=\"form.controls['title']\" type=\"text\" placeholder=\"Agrega un t\u00EDtulo\" />\n </div>\n\n <div style=\"margin-top: 4px\">\n <span>Descripci\u00F3n </span>\n <p-inputgroup>\n <input pInputText style=\"width: 100%\" [formControl]=\"form.controls['description']\" type=\"text\" placeholder=\"Agrega una descripci\u00F3n\" />\n <p-button\n icon=\"pi pi-sparkles\"\n styleClass=\"p-button-secondary p-button-outlined\"\n pTooltip=\"Generar descripci\u00F3n con IA\"\n tooltipPosition=\"top\"\n [disabled]=\"isLoadingLesson\"\n (click)=\"triggerGenerateDescriptionAI()\" />\n </p-inputgroup>\n </div>\n </div>\n\n <div style=\"display: flex; align-items: center; margin-top: 10px\">\n <input\n pInputText\n style=\"flex: auto; margin-right: 5px\"\n [value]=\"lesson?.auditable?.prompt || ''\"\n (input)=\"handlePromptInputChange($event)\"\n type=\"text\"\n placeholder=\"Prompt para IA (opcional)\" />\n <p-button severity=\"primary\" label=\"Generar con IA\" icon=\"pi pi-sparkles\" [disabled]=\"isLoadingLesson\" (click)=\"generateByAI()\" />\n </div>\n\n <p-divider />\n\n <div style=\"display: flex; align-items: center; margin-top: 10px; gap: 10px\">\n <input pInputText [value]=\"lesson?.extensions?.['level'] || ''\" type=\"number\" placeholder=\"Nivel\" style=\"width: 80px\" />\n\n <!-- Access signal values -->\n @if (lesson?.extensions) {\n <div>\n {{ lesson?.extensions?.['baseLang'] | flagEmoji }} -> {{ lesson?.extensions?.['targetLang'] | flagEmoji }} Lecci\u00F3n para hablantes de\n {{ lesson?.extensions?.['baseLang'] | langDesc : 'es' }} que aprenden\n {{ lesson?.extensions?.['targetLang'] | langDesc : 'es' }}\n </div>\n }\n </div>\n</div>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i3.InputText, selector: "[pInputText]", inputs: ["pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i7.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo"] }, { kind: "ngmodule", type: // Added Pipe
2116
+ InputGroupModule }, { kind: "component", type: i5.InputGroup, selector: "p-inputgroup, p-inputGroup, p-input-group", inputs: ["styleClass"] }, { kind: "ngmodule", type: DividerModule }, { kind: "component", type: i6.Divider, selector: "p-divider", inputs: ["styleClass", "layout", "type", "align"] }, { kind: "pipe", type: // Added TooltipModule
2019
2117
  FlagLanguagePipe, name: "flagEmoji" }, { kind: "pipe", type: // Added Pipe
2020
- LangDescTranslationPipe, name: "langDesc" }, { kind: "ngmodule", type: // Added Pipe
2021
- InputGroupModule }, { kind: "component", type: i5.InputGroup, selector: "p-inputgroup, p-inputGroup, p-input-group", inputs: ["style", "styleClass"] }, { kind: "ngmodule", type: DividerModule }, { kind: "component", type: i6$1.Divider, selector: "p-divider", inputs: ["style", "styleClass", "layout", "type", "align"] }] }); }
2118
+ LangDescTranslation, name: "langDesc" }] }); }
2022
2119
  }
2023
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DCLessonMetadataEditorComponent, decorators: [{
2120
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DCLessonMetadataEditorComponent, decorators: [{
2024
2121
  type: Component,
2025
2122
  args: [{ selector: 'dc-lesson-metadata-editor', standalone: true, imports: [
2026
2123
  CommonModule,
2027
2124
  FormsModule,
2028
2125
  ButtonModule,
2029
2126
  InputTextModule,
2127
+ ReactiveFormsModule,
2030
2128
  TooltipModule, // Added TooltipModule
2031
2129
  FlagLanguagePipe, // Added Pipe
2032
- LangDescTranslationPipe, // Added Pipe
2130
+ LangDescTranslation, // Added Pipe
2033
2131
  InputGroupModule,
2034
2132
  DividerModule,
2035
- ], template: "@if (lesson(); as currentLesson) {\n<div>\n <div>\n <div style=\"display: flex; gap: 10px; padding: 10px\">\n <p-button label=\"Guardar\" severity=\"primary\" (click)=\"emitSaveRequest()\" />\n <p-button label=\"Importar de Notion\" severity=\"help\" (click)=\"emitImportNotionRequest()\" />\n <p-button label=\"Mejorar Notion con AI\" severity=\"help\" (click)=\"emitImproveNotionRequest()\" />\n </div>\n\n <!-- Use one-way binding and ngModelChange for signals -->\n <div>\n <input\n pInputText\n style=\"width: 100%\"\n [ngModel]=\"currentLesson.metadata?.title\"\n (ngModelChange)=\"onMetadataPropertyChange('title', $event)\"\n type=\"text\"\n placeholder=\"Agrega un t\u00EDtulo\" />\n </div>\n <div style=\"margin-top: 4px\">\n <p-inputgroup>\n <input\n pInputText\n style=\"width: 100%\"\n [ngModel]=\"currentLesson.metadata?.description\"\n (ngModelChange)=\"onMetadataPropertyChange('description', $event)\"\n type=\"text\"\n placeholder=\"Agrega una descripci\u00F3n\" />\n <p-button\n icon=\"pi pi-sparkles\"\n styleClass=\"p-button-secondary p-button-outlined\"\n pTooltip=\"Generar descripci\u00F3n con IA\"\n tooltipPosition=\"top\"\n [disabled]=\"isLoadingLesson()\"\n (click)=\"triggerGenerateDescriptionAI()\" />\n </p-inputgroup>\n </div>\n\n <div style=\"display: flex; align-items: center; margin-top: 10px\">\n <input\n pInputText\n style=\"flex: auto; margin-right: 5px\"\n [ngModel]=\"currentLesson.metadata?.prompt\"\n (ngModelChange)=\"onMetadataPropertyChange('prompt', $event)\"\n type=\"text\"\n placeholder=\"Prompt para IA (opcional)\" />\n <p-button severity=\"primary\" label=\"Generar con IA\" icon=\"pi pi-sparkles\" [disabled]=\"isLoadingLesson()\" (click)=\"generateByAI()\" />\n </div>\n\n <div style=\"margin-top: 10px\">\n <label class=\"checkbox-container\" style=\"margin-right: 15px\">\n <input\n type=\"checkbox\"\n [ngModel]=\"currentLesson.metadata?.isPublished\"\n (ngModelChange)=\"onMetadataPropertyChange('isPublished', $event)\"\n title=\"Cuando termines la edici\u00F3n marca esta casilla\" />\n <span class=\"checkmark\"></span>\n Publicada\n </label>\n </div>\n\n <p-divider />\n\n <div style=\"display: flex; align-items: center; margin-top: 10px; gap: 10px\">\n <input\n pInputText\n [ngModel]=\"currentLesson.appExtension?.['level']\"\n (ngModelChange)=\"onAppExtensionPropChange('level', $event)\"\n type=\"number\"\n placeholder=\"Nivel\"\n style=\"width: 80px\" />\n\n <!-- Access signal values -->\n @if (currentLesson.appExtension) {\n <div>\n {{ currentLesson.appExtension?.['baseLang'] | flagEmoji }} -> {{ currentLesson.appExtension?.['targetLang'] | flagEmoji }} Lecci\u00F3n para hablantes de\n {{ currentLesson.appExtension?.['baseLang'] | langDesc : 'es' }} que aprenden\n {{ currentLesson.appExtension?.['targetLang'] | langDesc : 'es' }}\n </div>\n }\n </div>\n </div>\n</div>\n} @else {\n<!-- Optional: Show a loading state or placeholder if lesson is undefined -->\n<p>Cargando datos de la lecci\u00F3n...</p>\n}\n" }]
2036
- }], propDecorators: { lesson: [{
2133
+ ], template: "<div>\n <!-- <div style=\"display: flex; gap: 10px; padding: 10px\">\n <p-button label=\"Guardar\" severity=\"primary\" (click)=\"emitSaveRequest()\" />\n <p-button label=\"Importar de Notion\" severity=\"help\" (click)=\"emitImportNotionRequest()\" />\n <p-button label=\"Mejorar Notion con AI\" severity=\"help\" (click)=\"emitImproveNotionRequest()\" />\n </div> -->\n\n <div>\n <div>\n <span>Nombre de La lecci\u00F3n</span>\n <input pInputText style=\"width: 100%\" [formControl]=\"form.controls['name']\" type=\"text\" placeholder=\"Agrega un nombre\" />\n </div>\n <div>\n <span>T\u00EDtulo </span>\n <input pInputText style=\"width: 100%\" [formControl]=\"form.controls['title']\" type=\"text\" placeholder=\"Agrega un t\u00EDtulo\" />\n </div>\n\n <div style=\"margin-top: 4px\">\n <span>Descripci\u00F3n </span>\n <p-inputgroup>\n <input pInputText style=\"width: 100%\" [formControl]=\"form.controls['description']\" type=\"text\" placeholder=\"Agrega una descripci\u00F3n\" />\n <p-button\n icon=\"pi pi-sparkles\"\n styleClass=\"p-button-secondary p-button-outlined\"\n pTooltip=\"Generar descripci\u00F3n con IA\"\n tooltipPosition=\"top\"\n [disabled]=\"isLoadingLesson\"\n (click)=\"triggerGenerateDescriptionAI()\" />\n </p-inputgroup>\n </div>\n </div>\n\n <div style=\"display: flex; align-items: center; margin-top: 10px\">\n <input\n pInputText\n style=\"flex: auto; margin-right: 5px\"\n [value]=\"lesson?.auditable?.prompt || ''\"\n (input)=\"handlePromptInputChange($event)\"\n type=\"text\"\n placeholder=\"Prompt para IA (opcional)\" />\n <p-button severity=\"primary\" label=\"Generar con IA\" icon=\"pi pi-sparkles\" [disabled]=\"isLoadingLesson\" (click)=\"generateByAI()\" />\n </div>\n\n <p-divider />\n\n <div style=\"display: flex; align-items: center; margin-top: 10px; gap: 10px\">\n <input pInputText [value]=\"lesson?.extensions?.['level'] || ''\" type=\"number\" placeholder=\"Nivel\" style=\"width: 80px\" />\n\n <!-- Access signal values -->\n @if (lesson?.extensions) {\n <div>\n {{ lesson?.extensions?.['baseLang'] | flagEmoji }} -> {{ lesson?.extensions?.['targetLang'] | flagEmoji }} Lecci\u00F3n para hablantes de\n {{ lesson?.extensions?.['baseLang'] | langDesc : 'es' }} que aprenden\n {{ lesson?.extensions?.['targetLang'] | langDesc : 'es' }}\n </div>\n }\n </div>\n</div>\n" }]
2134
+ }], propDecorators: { form: [{
2135
+ type: Input,
2136
+ args: [{ required: true }]
2137
+ }], lesson: [{
2037
2138
  type: Input,
2038
2139
  args: [{ required: true }]
2039
2140
  }], isLoadingLesson: [{
@@ -2047,205 +2148,91 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImpor
2047
2148
  type: Output
2048
2149
  }] } });
2049
2150
 
2050
- // Define placeholder endpoints - these should be configured appropriately
2051
- const LESSONS_BASE_PATH = 'api/lesson'; // Example base path
2052
- class DefaultLessonsService {
2151
+ class LessonFormEditorService {
2053
2152
  constructor() {
2054
- this.httpCoreService = inject(HttpCoreService);
2055
- // --- Endpoint Definitions (Hardcoded as requested) ---
2056
- this.endpoints = {
2057
- queryLessons: `${LESSONS_BASE_PATH}/query`,
2058
- getLesson: (id) => `${LESSONS_BASE_PATH}/${id}`,
2059
- saveLesson: `api/user/saveLesson`,
2060
- updateLesson: (id) => `${LESSONS_BASE_PATH}/${id}`, // Assuming PUT to /lessons/:id
2061
- deleteLesson: (id) => `${LESSONS_BASE_PATH}/${id}`, // Assuming DELETE to /lessons/:id
2062
- generateLesson: `${LESSONS_BASE_PATH}/generate`, // Placeholder
2063
- generateByAI: `${LESSONS_BASE_PATH}/generate-ai`, // Placeholder
2064
- improveMDWithAI: `${LESSONS_BASE_PATH}/improve-markdown-ai`, // Placeholder
2065
- QueryLessons: 'api/lesson/query',
2066
- Lesson: 'api/lesson',
2067
- SaveLesson: 'api/lesson-polilan',
2068
- GetPublicLessons: 'api/lesson/publicLessons',
2069
- GetUnpublishedLessons: 'api/lesson/unpublished',
2070
- TakenLesson: 'api/lesson/taken',
2071
- DeleteLesson: 'api/lesson',
2072
- Base: 'api/lesson',
2073
- GenerateBanner: 'api/lesson/generate-banner',
2074
- };
2075
- }
2076
- saveTakenLesson(lesson) {
2077
- // Not sure how to implement this yet.
2078
- return this.httpCoreService.post(this.endpoints.saveLesson, lesson);
2079
- }
2080
- // --- Method Implementations ---
2081
- async getLessons(paginator) {
2082
- // Assuming paginator is the body for a POST request based on the example
2083
- return this.httpCoreService.post(this.endpoints.queryLessons, paginator || {});
2084
- }
2085
- async getLesson(id) {
2086
- return this.httpCoreService.get(this.endpoints.getLesson(id));
2087
- }
2088
- async postLesson(lesson) {
2089
- return this.httpCoreService.post(this.endpoints.saveLesson, lesson);
2090
- }
2091
- async updateLesson(lesson) {
2092
- if (!lesson._id) {
2093
- throw new Error('Lesson ID is required for update.');
2094
- }
2095
- // Assuming _id is the identifier
2096
- return this.httpCoreService.put(this.endpoints.updateLesson(lesson._id), lesson);
2097
- }
2098
- async deleteLesson(id) {
2099
- return this.httpCoreService.delete(this.endpoints.deleteLesson(id));
2100
- }
2101
- async generateLesson(lesson) {
2102
- // This endpoint might need specific data or structure
2103
- return this.httpCoreService.post(this.endpoints.generateLesson, lesson);
2104
- }
2105
- async postGenerateByAI(id) {
2106
- return this.httpCoreService.post(this.endpoints.generateByAI, { id });
2107
- }
2108
- async postImproveMDWithAI(lessonId, markdownText) {
2109
- return this.httpCoreService.post(this.endpoints.improveMDWithAI, { id: lessonId, markdown: markdownText });
2153
+ this.fb = inject(FormBuilder);
2154
+ this.formUtils = inject(FormUtilsService);
2155
+ this.formatOptions = [
2156
+ { label: 'HTML', value: 'html' },
2157
+ { label: 'Markdown', value: 'markdown' },
2158
+ ];
2110
2159
  }
2111
- extractTextFromHtml(html) {
2112
- // Copied from src/app/core/data-services/lessons.service.ts
2113
- const r1 = new RegExp('~(.+?)~', 'g');
2114
- const lessonHtml = html.replace(r1, (_matching, jsonCoded) => {
2115
- try {
2116
- const data = JSON.parse(jsonCoded);
2117
- return `<span>${data?.settings?.text || ''}</span>`; // Added default empty string
2118
- }
2119
- catch (e) {
2120
- console.error('Error parsing JSON in extractTextFromHtml:', jsonCoded, e);
2121
- return ''; // Return empty string on error
2122
- }
2160
+ createLessonForm() {
2161
+ return this.fb.group({
2162
+ version: ['1.0'],
2163
+ id: [''],
2164
+ name: [''],
2165
+ title: [''],
2166
+ description: [''],
2167
+ format: ['html'],
2168
+ lang: [''],
2169
+ characterCard: [],
2170
+ conversationSettings: [],
2171
+ metaApp: [],
2172
+ conversationFlow: [],
2173
+ textCoded: [''],
2174
+ manageable: this.formUtils.createManageableFormGroup(),
2175
+ learnable: this.formUtils.createLearnableFormGroup(),
2123
2176
  });
2124
- // Remove HTML tags
2125
- let text = lessonHtml.replace(/<[^>]*>/g, ' ');
2126
- // Remove style and script content
2127
- text = text.replace(/<style[^>]*>[\s\S]*?<\/style>/gi, ' ');
2128
- text = text.replace(/<script[^>]*>[\s\S]*?<\/script>/gi, ' ');
2129
- // Decode HTML entities
2130
- text = text.replace(/&nbsp;/g, ' ');
2131
- text = text.replace(/&/g, '&');
2132
- text = text.replace(/</g, '<');
2133
- text = text.replace(/>/g, '>');
2134
- // Remove extra whitespace
2135
- text = text.replace(/\s+/g, ' ').trim();
2136
- return text;
2137
- }
2138
- generateBanner(prompt, lessonId) {
2139
- return this.httpCoreService.post(this.endpoints.GenerateBanner, { prompt, lessonId });
2140
- }
2141
- getPrompts() {
2142
- return null;
2143
2177
  }
2144
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DefaultLessonsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2145
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DefaultLessonsService, providedIn: 'root' }); }
2178
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: LessonFormEditorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2179
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: LessonFormEditorService, providedIn: 'root' }); }
2146
2180
  }
2147
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DefaultLessonsService, decorators: [{
2181
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: LessonFormEditorService, decorators: [{
2148
2182
  type: Injectable,
2149
2183
  args: [{
2150
2184
  providedIn: 'root',
2151
2185
  }]
2152
2186
  }] });
2153
2187
 
2154
- class DCLessonEditorComponent {
2155
- // Services
2156
- #activatedRoute; // Re-inject as it's needed for navigation
2157
- #lessonNotionService;
2158
- #lessonUtilsService;
2159
- #router;
2160
- #lessonService;
2161
- #toastService;
2162
- #loadingBarService;
2188
+ class DCLessonEditorComponent extends EntityBaseFormComponent {
2163
2189
  constructor() {
2190
+ super(...arguments);
2191
+ this.lessonFormEditorService = inject(LessonFormEditorService);
2192
+ this.markdownService = inject(MarkdownService);
2193
+ this.form = this.lessonFormEditorService.createLessonForm();
2194
+ this.formatOptions = this.lessonFormEditorService.formatOptions;
2195
+ this.entityCommunicationService = inject(LESSONS_TOKEN);
2196
+ this.htmlTemporal = '';
2164
2197
  // Services
2165
- this.#activatedRoute = inject(ActivatedRoute); // Re-inject as it's needed for navigation
2166
- this.#lessonNotionService = inject(LessonNotionService);
2167
- this.#lessonUtilsService = inject(LessonUtilsService);
2168
- this.#router = inject(Router);
2169
- this.#lessonService = inject(LESSONS_TOKEN);
2170
- this.#toastService = inject(TOAST_ALERTS_TOKEN);
2171
- this.#loadingBarService = inject(LoadingBarService);
2198
+ this.activatedRoute = inject(ActivatedRoute); // Re-inject as it's needed for navigation
2199
+ this.lessonNotionService = inject(LessonNotionService);
2200
+ this.lessonUtilsService = inject(LessonUtilsService);
2201
+ this.lessonsService = inject(LESSONS_TOKEN, { optional: true }) ?? inject(DefaultLessonsService);
2202
+ this.loadingBarService = inject(LoadingBarService);
2172
2203
  this.defaultLessonsService = inject(DefaultLessonsService);
2173
2204
  this.promptService = inject(PromptService);
2174
2205
  this.ngxVertexService = inject(NgxVertexService);
2175
- this.cdr = inject(ChangeDetectorRef);
2176
2206
  this.dynamicComponentsBuilderService = inject(DynamicComponentsBuilderService);
2177
- // Signals States
2178
- this.lessonId = toSignal(inject(ActivatedRoute).paramMap.pipe(map((params) => params.get('id'))));
2179
- this.lesson = signal(undefined); // Initialize as undefined
2180
- this.isLoadingLesson = signal(false);
2181
- // Computed Signals
2182
- this.coverImageUrl = computed(() => {
2183
- // Priority Order 1 Metadata Banner, 2 Banner, 3 Media First Images, 4 Default Banner TODO: reveme banner after migration to Content
2184
- const currentLesson = this.lesson();
2185
- if (currentLesson?.metadata?.banner?.url) {
2186
- return currentLesson.metadata.banner.url;
2187
- }
2188
- else if (currentLesson?.banner?.url) {
2189
- return currentLesson.banner.url;
2190
- }
2191
- else if (currentLesson?.media?.images?.find((img) => img.type === 'cover')) {
2192
- // 3 Media First Images
2193
- return currentLesson.media.images.find((img) => img.type === 'cover')?.url;
2194
- }
2195
- return '/assets/images/default_banner.webp';
2196
- });
2207
+ this.isLoadingLesson = signal(false, ...(ngDevMode ? [{ debugName: "isLoadingLesson" }] : []));
2197
2208
  // Computed signal to get dynamic components as an array for easier iteration in the template
2198
2209
  this.dynamicComponentsArray = computed(() => {
2199
- const currentLesson = this.lesson();
2200
- if (currentLesson?.dynamicComponents) {
2201
- return Object.values(currentLesson.dynamicComponents);
2202
- }
2210
+ // const currentLesson = this.lesson();
2211
+ // if (currentLesson?.dynamicComponents) {
2212
+ // return Object.values(currentLesson.dynamicComponents);
2213
+ // }
2203
2214
  return []; // Return empty array if no lesson or no dynamic components
2204
- });
2215
+ }, ...(ngDevMode ? [{ debugName: "dynamicComponentsArray" }] : []));
2205
2216
  // States
2206
2217
  this.components = {}; // Current Dynamic components
2207
2218
  this.editor = BalloonEditor;
2208
2219
  this.lessonComponentEnum = LessonComponentEnum;
2209
2220
  this.coverStorageSettings = {
2210
- path: `lessons/${this.lessonId()}/covers`,
2221
+ path: `lessons/${this.entityId()}/covers`,
2211
2222
  fileName: 'cover',
2212
2223
  cropSettings: { resizeToWidth: 850, aspectRatio: AspectType.RectangleLarge, resolutions: [ResolutionType.Medium] },
2213
2224
  };
2214
- this.promptsVisible = false;
2215
- // Effect to fetch lesson data when ID changes
2216
- effect(async () => {
2217
- const id = this.lessonId();
2218
- console.log('Lesson ID Signal:', id);
2219
- if (id) {
2220
- this.isLoadingLesson.set(true); // Start loading
2221
- try {
2222
- const fetchedLesson = await this.#lessonService.getLesson(id);
2223
- if (fetchedLesson) {
2224
- this.lesson.set(fetchedLesson);
2225
- }
2226
- else {
2227
- this.lesson.set(undefined); // Reset if not found
2228
- this.#toastService.warn({ title: 'No se encontró la lección', subtitle: 'Quizá el id es incorrecto' });
2229
- // Optional: Navigate away or show a specific "not found" state
2230
- // this.#router.navigate(['/path/to/lessons']);
2231
- }
2232
- }
2233
- catch (error) {
2234
- console.error('Error fetching lesson:', error);
2235
- this.lesson.set(undefined); // Reset on error
2236
- this.#toastService.error({ title: 'Error al cargar la lección', subtitle: 'Intenta de nuevo más tarde' });
2237
- }
2238
- finally {
2239
- this.isLoadingLesson.set(false); // Stop loading
2240
- }
2241
- }
2242
- else {
2243
- // Handle case for new lesson (ID is null/undefined)
2244
- this.lesson.set({ textCoded: `<h1>Nueva lección </h1> <p> Texto aquí</p>`, tags: [] }); // Set default new lesson structure
2245
- this.saveLesson();
2246
- this.isLoadingLesson.set(false); // Ensure loading is off
2247
- }
2248
- });
2225
+ }
2226
+ patchForm(entity) {
2227
+ console.log(this.form);
2228
+ if (this.entity().format === 'markdown') {
2229
+ this.htmlTemporal = this.markdownService.parse(entity.markdown);
2230
+ }
2231
+ else {
2232
+ this.htmlTemporal = entity.textCoded;
2233
+ }
2234
+ // console.log(this.htmlTemporal);
2235
+ this.form.patchValue(entity);
2249
2236
  }
2250
2237
  /**
2251
2238
  * Updates a specific property on the lesson signal.
@@ -2255,77 +2242,71 @@ class DCLessonEditorComponent {
2255
2242
  */
2256
2243
  updateLessonProperty(property, value) {
2257
2244
  console.log('Updating property:', property, value);
2258
- this.lesson.update((currentLesson) => {
2245
+ this.entity.update((currentLesson) => {
2259
2246
  if (!currentLesson)
2260
2247
  return undefined;
2261
2248
  return { ...currentLesson, [property]: value };
2262
2249
  });
2263
2250
  }
2264
- onTagRemove(tag) {
2265
- this.lesson.update((currentLesson) => {
2251
+ updateHtmlTextCoded(_, value) {
2252
+ this.entity.update((currentLesson) => {
2266
2253
  if (!currentLesson)
2267
2254
  return undefined;
2268
- const updatedTags = currentLesson.tags.filter((text) => text !== tag.text);
2269
- return { ...currentLesson, tags: updatedTags };
2255
+ return { ...currentLesson, textCoded: value };
2270
2256
  });
2257
+ this.form.controls.textCoded.setValue(value);
2271
2258
  }
2272
- onTagAdd(tag) {
2273
- if (tag.value) {
2274
- this.lesson.update((currentLesson) => {
2275
- if (!currentLesson)
2276
- return undefined;
2277
- // Avoid duplicate tags if necessary
2278
- if (currentLesson.tags.includes(tag.value)) {
2279
- return currentLesson;
2280
- }
2281
- const updatedTags = [...currentLesson.tags, tag.value];
2282
- return { ...currentLesson, tags: updatedTags };
2283
- });
2284
- }
2285
- tag.input.nativeElement.value = ''; // Clear input
2259
+ onAssetsChange(updatedAssets) {
2260
+ console.log(updatedAssets);
2261
+ this.entity.update((currentLesson) => {
2262
+ if (!currentLesson)
2263
+ return undefined;
2264
+ return { ...currentLesson, assets: updatedAssets };
2265
+ });
2286
2266
  }
2287
2267
  async saveLesson(event) {
2268
+ // TODO: Revisar por ahora uso el método del padre para guardar. pero creo que este era para guardar la lección.
2288
2269
  event?.preventDefault();
2289
- const currentLesson = this.lesson();
2270
+ const currentLesson = this.entity();
2290
2271
  if (!currentLesson) {
2291
- this.#toastService.error({ title: 'Error', subtitle: 'No hay datos de lección para guardar' });
2272
+ this.toastService.error({ title: 'Error', subtitle: 'No hay datos de lección para guardar' });
2292
2273
  return undefined;
2293
2274
  }
2294
2275
  // Clean orphaned components before saving
2295
- const lessonToSave = this.#lessonUtilsService.cleanOrphanedComponents(currentLesson);
2276
+ const lessonToSave = this.lessonUtilsService.cleanOrphanedComponents(currentLesson);
2296
2277
  // TODO: Implement optimization for saving only changed data.
2297
2278
  // This requires comparing lessonToSave with the initially fetched state.
2298
2279
  this.isLoadingLesson.set(true); // Indicate saving
2299
2280
  try {
2300
2281
  // Use the cleaned lesson object for saving
2301
- const savedLesson = await this.#lessonService.postLesson(lessonToSave);
2302
- const currentId = this.lessonId();
2282
+ const savedLesson = await this.lessonsService.postLesson(lessonToSave);
2283
+ const currentId = this.entityId();
2303
2284
  if (!currentId) {
2304
2285
  // No se como guardar los extras aunt
2305
2286
  // It was a new lesson, now it has an ID. Navigate.
2306
- this.#toastService.success({ title: 'Se creó la lección', subtitle: 'Éxito' });
2287
+ this.toastService.success({ title: 'Se creó la lección', subtitle: 'Éxito' });
2307
2288
  // The effect should automatically fetch the lesson again after navigation due to paramMap change.
2308
- this.#router.navigate(['./', savedLesson.id], { relativeTo: this.#activatedRoute });
2289
+ this.router.navigate(['./', savedLesson.id], { relativeTo: this.activatedRoute });
2309
2290
  }
2310
2291
  else {
2311
2292
  // It was an existing lesson, update the signal with the potentially updated data from the backend.
2312
- this.lesson.set(savedLesson);
2313
- this.#toastService.info({ title: 'Se guardaron los cambios en la lección', subtitle: 'Guardado' });
2293
+ this.entity.set(savedLesson);
2294
+ this.toastService.info({ title: 'Se guardaron los cambios en la lección', subtitle: 'Guardado' });
2314
2295
  // Call the service method for validation
2315
- this.#lessonUtilsService.validateAudios(this.lesson());
2296
+ this.lessonUtilsService.validateAudios(this.entity());
2316
2297
  }
2317
2298
  return savedLesson;
2318
2299
  }
2319
2300
  catch (error) {
2320
2301
  // Type error
2321
2302
  console.error('Error saving lesson:', error);
2322
- this.#toastService.error({ title: 'Error al guardar', subtitle: 'No se pudieron guardar los cambios' });
2303
+ this.toastService.error({ title: 'Error al guardar', subtitle: 'No se pudieron guardar los cambios' });
2323
2304
  return undefined;
2324
2305
  }
2325
2306
  finally {
2326
2307
  this.isLoadingLesson.set(false); // Finish saving indication
2327
2308
  }
2328
- } // Add missing closing brace for saveLesson
2309
+ }
2329
2310
  // Removed openComponentBuilder method
2330
2311
  /**
2331
2312
  * Handles the event emitted when a component is added via the adder component.
@@ -2337,7 +2318,7 @@ class DCLessonEditorComponent {
2337
2318
  if (newComponent?.id) {
2338
2319
  console.log('Component builder closed, result received in editor:', newComponent);
2339
2320
  // Update the lesson signal, adding the transformed component to the dynamicComponents object
2340
- this.lesson.update((currentLesson) => {
2321
+ this.entity.update((currentLesson) => {
2341
2322
  if (!currentLesson)
2342
2323
  return undefined;
2343
2324
  // Ensure dynamicComponents object exists, initialize if not
@@ -2350,54 +2331,17 @@ class DCLessonEditorComponent {
2350
2331
  // Return the updated lesson state
2351
2332
  return { ...currentLesson, dynamicComponents: updatedDynamicComponents };
2352
2333
  });
2353
- // Optionally save the lesson after adding the component
2354
- // this.saveLesson();
2355
2334
  }
2356
2335
  }
2357
- // isLoadingLesson signal is used directly
2358
- // Removed generateByAI and _extractTextFromEncodedJson methods.
2359
- // This logic is now handled within DCLessonMetadataEditorComponent.
2360
- /**
2361
- * Handles the image upload event, updates the lesson signal via the service, and saves.
2362
- * @param event The image upload event data.
2363
- */
2364
- async onImageUploaded(event) {
2365
- this.#lessonUtilsService.uploadCover(this.lesson, event);
2366
- await this.saveLesson();
2367
- }
2368
- /**
2369
- * Imports lesson content from Notion using the LessonNotionService.
2370
- */
2371
- async importFromNotion() {
2372
- // Use the service's loading state or manage locally
2373
- this.isLoadingLesson.set(true);
2374
- try {
2375
- const newContent = await this.#lessonNotionService.importAndLinkLessonFromNotion(this.lesson(), this.lessonId());
2376
- if (newContent !== null) {
2377
- // Update the lesson signal's textCoded property
2378
- this.updateLessonProperty('textCoded', newContent);
2379
- // Toast success is handled within the service now
2380
- }
2381
- // If newContent is null, the service handled errors/toasts
2382
- }
2383
- finally {
2384
- // Ensure loading state is reset regardless of service outcome
2385
- // If observing service state: this.isLoadingLesson.set(this.#lessonNotionService.isLoading());
2386
- this.isLoadingLesson.set(false); // Keep local loading for now
2387
- }
2388
- }
2389
- /**
2390
- * Calls the LessonNotionService to improve the lesson using AI based on Notion content.
2391
- */
2392
2336
  async improveNotionWithAI() {
2393
- await this.#lessonNotionService.improveLessonWithNotionAI(this.lesson());
2337
+ await this.lessonNotionService.improveLessonWithNotionAI(this.entity());
2394
2338
  }
2395
2339
  showComponentDetails(data) {
2396
2340
  alert('showComponentDetails' + JSON.stringify(data));
2397
2341
  }
2398
2342
  async generateBanner() {
2399
- this.#toastService.info({ title: 'Generando prompt de sugerencia', subtitle: 'Por favor, espera' });
2400
- const prompt = this.#lessonService.getPrompts().banner(this.lesson());
2343
+ this.toastService.info({ title: 'Generando prompt de sugerencia', subtitle: 'Por favor, espera' });
2344
+ const prompt = this.lessonsService.getPrompts().banner(this.entity());
2401
2345
  const geminiRes = await this.ngxVertexService.generateText([{ role: ChatRoleVertex.User, content: prompt }]);
2402
2346
  this.promptService
2403
2347
  .openPrompt({
@@ -2409,31 +2353,16 @@ class DCLessonEditorComponent {
2409
2353
  })
2410
2354
  .then((promptResult) => {
2411
2355
  if (promptResult) {
2412
- this.#loadingBarService.showIndeterminate();
2413
- this.defaultLessonsService.generateBanner(promptResult, this.lessonId()).then((result) => {
2356
+ this.loadingBarService.showIndeterminate();
2357
+ this.defaultLessonsService.generateBanner(promptResult, this.entityId()).then((result) => {
2414
2358
  if (result) {
2415
- this.updateLessonProperty('banner', result.banner);
2359
+ alert('Revisar como actualizar el banner');
2360
+ // this.updateLessonProperty('banner', (result as any).banner);
2416
2361
  }
2417
- this.#loadingBarService.successAndHide();
2362
+ this.loadingBarService.successAndHide();
2418
2363
  });
2419
2364
  }
2420
2365
  });
2421
- // const imagePrompt = prompt('alguna idea de lo que quieres ver?');
2422
- // this.#loadingBarService.showIndeterminate();
2423
- // const result = await this.defaultLessonsService.generateBanner(imagePrompt, this.lessonId());
2424
- // if (result) {
2425
- // this.updateLessonProperty('banner', result.banner);
2426
- // }
2427
- // console.log('Generated banner:', result);
2428
- //
2429
- // this.#loadingBarService.successAndHide();
2430
- }
2431
- showPrompts() {
2432
- this.promptsVisible = true;
2433
- const promptsFn = this.#lessonService.getPrompts();
2434
- this.prompts = { banner: promptsFn.banner(this.lesson()), content: promptsFn.content(this.lesson()), description: promptsFn.description(this.lesson()) };
2435
- console.log(this.prompts);
2436
- this.cdr.markForCheck();
2437
2366
  }
2438
2367
  editComponent(comp) {
2439
2368
  console.log('Edit component:', comp);
@@ -2441,43 +2370,61 @@ class DCLessonEditorComponent {
2441
2370
  this.onComponentAdded(result);
2442
2371
  });
2443
2372
  }
2444
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DCLessonEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2445
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.4", type: DCLessonEditorComponent, isStandalone: true, selector: "dc-lesson-editor", providers: [LessonNotionService], viewQueries: [{ propertyName: "target", first: true, predicate: ["target"], descendants: true, read: ViewContainerRef }, { propertyName: "dhtml", first: true, predicate: ["dhtml"], descendants: true, static: true }], ngImport: i0, template: "<div style=\"position: relative; margin-bottom: 20px\">\n <img class=\"header-cover\" [src]=\"coverImageUrl()\" alt=\"Lesson Cover Image\" />\n\n <dc-cropper-modal\n style=\"position: absolute; top: 10px; left: 20px\"\n [buttonLabel]=\"'Carga una portada'\"\n [imgStorageSettings]=\"coverStorageSettings\"\n (imageUploaded)=\"onImageUploaded($event)\"></dc-cropper-modal>\n\n <p-button\n (click)=\"generateBanner()\"\n class=\"generate-banner-btn\"\n icon=\"pi pi-sparkles\"\n severity=\"primary\"\n [rounded]=\"true\"\n [raised]=\"true\"\n pTooltip=\"Generar Banner AI\"\n tooltipPosition=\"left\"></p-button>\n\n <p-button class=\"prompt-visual\" icon=\"pi pi-info\" label=\"Ver Prompts\" [link]=\"true\" (click)=\"showPrompts()\" />\n</div>\n\n<br />\n\n<!-- Lesson Metadata Editor -->\n<dc-lesson-metadata-editor\n [lesson]=\"lesson\"\n [isLoadingLesson]=\"isLoadingLesson\"\n (saveRequest)=\"saveLesson()\"\n (importNotionRequest)=\"importFromNotion()\"\n (improveNotionRequest)=\"improveNotionWithAI()\">\n</dc-lesson-metadata-editor>\n\n<div style=\"margin-top: 30px\"></div>\n\n<!-- Component Adder -->\n<dc-lesson-component-adder (componentAdded)=\"onComponentAdded($event)\"></dc-lesson-component-adder>\n\n<!-- Display Added Components -->\n<div class=\"added-components-list\" style=\"margin-top: 15px; margin-bottom: 15px\">\n <h4>Componentes Agregados:</h4>\n @if (dynamicComponentsArray().length > 0) {\n <ul>\n @for (comp of dynamicComponentsArray(); track comp.id) {\n <li\n >ID: {{ comp.id }} - Tipo: {{ comp.component }}\n\n <button pButton icon=\"pi pi-info\" (click)=\"showComponentDetails(comp)\"></button>\n <p-button icon=\"pi pi-pencil\" [rounded]=\"true\" severity=\"warn\" (click)=\"editComponent(comp)\"></p-button>\n </li>\n }\n </ul>\n } @else {\n <p>A\u00FAn no se han agregado componentes.</p>\n }\n</div>\n\n<hr />\n\n<!-- Text Editor and Renderer -->\n<p-splitter [style]=\"{ height: '80vh' }\">\n <ng-template pTemplate>\n <ckeditor\n (keydown.control.s)=\"saveLesson($event)\"\n class=\"text-editor\"\n [editor]=\"editor\"\n [ngModel]=\"lesson()?.textCoded\"\n (ngModelChange)=\"updateLessonProperty('textCoded', $event)\">\n </ckeditor>\n </ng-template>\n\n <ng-template pTemplate>\n <dc-lesson-renderer class=\"text-editor\" [lessonInput]=\"lesson()\"></dc-lesson-renderer>\n </ng-template>\n</p-splitter>\n\n<div class=\"float-button\">\n <!-- Removed p-speeddial -->\n <p-button icon=\"pi pi-save\" (click)=\"saveLesson()\" severity=\"primary\" [rounded]=\"true\" [raised]=\"true\" pTooltip=\"Guardar (Ctrl + S)\"> </p-button>\n</div>\n\n<hr />\n\n<p-dialog header=\"Prompts\" [modal]=\"true\" [(visible)]=\"promptsVisible\" [style]=\"{ width: '70%' }\">\n <div>\n <h1>Banner</h1>\n <p>{{ prompts?.banner }}</p>\n <h1>Contenido</h1>\n <p>{{ prompts?.content }}</p>\n <h1>Descripci\u00F3n</h1>\n <p>{{ prompts?.description }}</p>\n </div>\n</p-dialog>\n", styles: [".btn{padding:.5rem 1rem;border-radius:4px;border:1px solid transparent;cursor:pointer}.generate-banner-btn{position:absolute;right:10px;top:10px}.prompt-visual{position:absolute;left:10px;bottom:10px}.btn-primary{background-color:#007bff;color:#fff}.btn-outline-primary{border-color:#007bff;color:#007bff}.btn-secondary{background-color:#6c757d;color:#fff}.btn-outline-secondary{border-color:#6c757d;color:#6c757d}.btn-rounded{border-radius:50%}.form-control{padding:.375rem .75rem;border:1px solid #ced4da;border-radius:.25rem}.splitter{display:flex;gap:1rem}.splitter-panel{flex:1}.checkbox-container{display:inline-flex;align-items:center;gap:.5rem;cursor:pointer}.mr-2{margin-right:.5rem}.header-cover{width:100%;height:250px;object-fit:cover;position:relative;border-radius:8px}.float-button{position:fixed;bottom:3.5rem;right:2rem;z-index:1000;display:flex;gap:1px}.float-button :host ::ng-deep .p-button{width:4rem;height:4rem;border-radius:50%}.text-editor{width:-webkit-fill-available;overflow-y:auto}:host ::ng-deep .p-inputtext{background:#fff3}\n"], dependencies: [{ kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i1$1.ButtonDirective, selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "fluid", "label", "icon", "buttonProps"] }, { kind: "component", type: i1$1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i2$3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: CKEditorModule }, { kind: "component", type: i3$2.CKEditorComponent, selector: "ckeditor", inputs: ["editor", "config", "data", "tagName", "watchdog", "editorWatchdogConfig", "disableTwoWayDataBinding", "disabled"], outputs: ["ready", "change", "blur", "focus", "error"] }, { kind: "component", type: CropperComponentModal, selector: "dc-cropper-modal", inputs: ["imgStorageSettings", "buttonLabel", "currentStorage"], outputs: ["imageUploaded", "onImageCropped", "onFileSelected"] }, { kind: "component", type: DCLessonRendererComponent, selector: "dc-lesson-renderer", inputs: ["lessonInput", "lessonIdInput", "settings"], outputs: ["wordClicked"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "ngmodule", type: SplitterModule }, { kind: "component", type: i5$1.Splitter, selector: "p-splitter", inputs: ["styleClass", "panelStyleClass", "style", "panelStyle", "stateStorage", "stateKey", "layout", "gutterSize", "step", "minSizes", "panelSizes"], outputs: ["onResizeEnd", "onResizeStart"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i6.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }, { kind: "component", type: DCLessonComponentAdderComponent, selector: "dc-lesson-component-adder", outputs: ["componentAdded"] }, { kind: "component", type: // Add the component adder here
2446
- DCLessonMetadataEditorComponent, selector: "dc-lesson-metadata-editor", inputs: ["lesson", "isLoadingLesson"], outputs: ["saveRequest", "importNotionRequest", "improveNotionRequest"] }, { kind: "ngmodule", type: // Add the metadata editor here
2447
- DialogModule }, { kind: "component", type: i7.Dialog, selector: "p-dialog", inputs: ["header", "draggable", "resizable", "positionLeft", "positionTop", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "responsive", "appendTo", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "breakpoint", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }] }); }
2373
+ onAssetUpdate(event) {
2374
+ this.entityCommunicationService.partialUpdate(this.entityId(), { assets: event.assets });
2375
+ }
2376
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DCLessonEditorComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
2377
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.6", type: DCLessonEditorComponent, isStandalone: true, selector: "dc-lesson-editor", providers: [LessonNotionService], usesInheritance: true, ngImport: i0, template: "<div class=\"p-grid\">\n <div class=\"p-col-4\">\n <assets-loader\n [assets]=\"entity()?.assets\"\n storagePath=\"lessons/{{ entityId() }}\"\n (assetsChange)=\"onAssetsChange($event)\"\n (assetUpdate)=\"onAssetUpdate($event)\"></assets-loader>\n </div>\n\n <div class=\"p-col-4\">\n <h3>Learnable</h3>\n <dc-learnable-viewer [data]=\"entity()?.learnable\"></dc-learnable-viewer>\n </div>\n <div class=\"p-col-4\">\n <h3>Auditable</h3>\n <dc-auditable-viewer [data]=\"entity()?.auditable\"></dc-auditable-viewer>\n </div>\n <div class=\"p-col-4\">\n <h3>Manageable</h3>\n <dc-manageable-form [form]=\"form.controls.manageable\"></dc-manageable-form>\n </div>\n <div class=\"p-col-4\">\n <h3>Learnable</h3>\n <dc-learnable-form [form]=\"form.controls.learnable\"></dc-learnable-form>\n </div>\n <div class=\"p-col-4\">\n <h3>Reactions</h3>\n <dc-reactions-viewer [data]=\"entity()?.reactions\"></dc-reactions-viewer>\n </div>\n\n <div class=\"p-col-4\">\n <h3>Extensions</h3>\n <dc-extensions-viewer [data]=\"entity()?.extensions\"></dc-extensions-viewer>\n </div>\n</div>\n\n<!-- Lesson Metadata Editor -->\n<div [formGroup]=\"form\">\n <p-selectButton [options]=\"formatOptions\" formControlName=\"format\" optionLabel=\"label\" optionValue=\"value\" />\n</div>\n<dc-lesson-metadata-editor [lesson]=\"entity()\" [form]=\"form\" [isLoadingLesson]=\"isLoadingLesson()\"></dc-lesson-metadata-editor>\n\n<div style=\"margin-top: 30px\"></div>\n\n<!-- Component Adder -->\n<dc-lesson-component-adder (componentAdded)=\"onComponentAdded($event)\"></dc-lesson-component-adder>\n\n<!-- Display Added Components -->\n<div class=\"added-components-list\" style=\"margin-top: 15px; margin-bottom: 15px\">\n <h4>Componentes Agregados:</h4>\n @if (dynamicComponentsArray().length > 0) {\n <ul>\n @for (comp of dynamicComponentsArray(); track comp.id) {\n <li\n >ID: {{ comp.id }} - Tipo: {{ comp.component }}\n\n <button pButton icon=\"pi pi-info\" (click)=\"showComponentDetails(comp)\"></button>\n <p-button icon=\"pi pi-pencil\" [rounded]=\"true\" severity=\"warn\" (click)=\"editComponent(comp)\"></p-button>\n </li>\n }\n </ul>\n } @else {\n <p>A\u00FAn no se han agregado componentes.</p>\n }\n</div>\n\n<hr />\n\n<!-- Text Editor and Renderer -->\n<p-splitter [style]=\"{ height: '80vh' }\">\n <ng-template pTemplate>\n <ckeditor\n (keydown.control.s)=\"saveLesson($event)\"\n class=\"text-editor\"\n [editor]=\"editor\"\n [ngModel]=\"htmlTemporal\"\n (ngModelChange)=\"updateHtmlTextCoded('textCoded', $event)\">\n </ckeditor>\n </ng-template>\n\n <ng-template pTemplate>\n <dc-lesson-renderer class=\"text-editor\" [lessonInput]=\"entity()\"></dc-lesson-renderer>\n </ng-template>\n</p-splitter>\n\n<div class=\"float-button\">\n <p-button icon=\"pi pi-save\" (click)=\"save()\" severity=\"primary\" [rounded]=\"true\" [raised]=\"true\" pTooltip=\"Guardar (Ctrl + S)\"> </p-button>\n</div>\n\n<hr />\n\n<!-- <p-dialog header=\"Prompts\" [modal]=\"true\" [(visible)]=\"promptsVisible\" [style]=\"{ width: '70%' }\">\n <div>\n <h1>Banner</h1>\n <p>{{ prompts?.banner }}</p>\n <h1>Contenido</h1>\n <p>{{ prompts?.content }}</p>\n <h1>Descripci\u00F3n</h1>\n <p>{{ prompts?.description }}</p>\n </div>\n</p-dialog> -->\n", styles: [".btn{padding:.5rem 1rem;border-radius:4px;border:1px solid transparent;cursor:pointer}.generate-banner-btn{position:absolute;right:10px;top:10px}.prompt-visual{position:absolute;left:10px;bottom:10px}.btn-primary{background-color:#007bff;color:#fff}.btn-outline-primary{border-color:#007bff;color:#007bff}.btn-secondary{background-color:#6c757d;color:#fff}.btn-outline-secondary{border-color:#6c757d;color:#6c757d}.btn-rounded{border-radius:50%}.form-control{padding:.375rem .75rem;border:1px solid #ced4da;border-radius:.25rem}.splitter{display:flex;gap:1rem}.splitter-panel{flex:1}.checkbox-container{display:inline-flex;align-items:center;gap:.5rem;cursor:pointer}.mr-2{margin-right:.5rem}.header-cover{width:100%;height:250px;object-fit:cover;position:relative;border-radius:8px}.float-button{position:fixed;bottom:3.5rem;right:2rem;z-index:1000;display:flex;gap:1px}.float-button :host ::ng-deep .p-button{width:4rem;height:4rem;border-radius:50%}.text-editor{width:-webkit-fill-available;overflow-y:auto}:host ::ng-deep .p-inputtext{background:#fff3}::ng-deep .p-splitter .p-splitterpanel{overflow:auto!important}\n"], dependencies: [{ kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i1$1.ButtonDirective, selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "fluid", "label", "icon", "buttonProps"] }, { kind: "component", type: i1$1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i2$3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: CKEditorModule }, { kind: "component", type: i3$1.CKEditorComponent, selector: "ckeditor", inputs: ["editor", "config", "data", "tagName", "watchdog", "editorWatchdogConfig", "disableTwoWayDataBinding", "disabled"], outputs: ["ready", "change", "blur", "focus", "error"] }, { kind: "component", type: DCLessonRendererComponent, selector: "dc-lesson-renderer", inputs: ["lessonInput", "lessonIdInput", "settings"], outputs: ["wordClicked"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: SelectButtonModule }, { kind: "component", type: i5$1.SelectButton, selector: "p-selectButton, p-selectbutton, p-select-button", inputs: ["options", "optionLabel", "optionValue", "optionDisabled", "unselectable", "tabindex", "multiple", "allowEmpty", "styleClass", "ariaLabelledBy", "dataKey", "autofocus", "size", "fluid"], outputs: ["onOptionClick", "onChange"] }, { kind: "ngmodule", type: SplitterModule }, { kind: "component", type: i6$1.Splitter, selector: "p-splitter", inputs: ["styleClass", "panelStyleClass", "panelStyle", "stateStorage", "stateKey", "layout", "gutterSize", "step", "minSizes", "panelSizes"], outputs: ["onResizeEnd", "onResizeStart"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i7.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo"] }, { kind: "component", type: DCLessonComponentAdderComponent, selector: "dc-lesson-component-adder", outputs: ["componentAdded"] }, { kind: "ngmodule", type: // Add the component adder here
2378
+ DialogModule }, { kind: "component", type: DcExtensionsViewerComponent, selector: "dc-extensions-viewer", inputs: ["data"] }, { kind: "component", type: DcLearnableViewerComponent, selector: "dc-learnable-viewer", inputs: ["data"] }, { kind: "component", type: DcAuditableViewerComponent, selector: "dc-auditable-viewer", inputs: ["data"] }, { kind: "component", type: DcReactionsViewerComponent, selector: "dc-reactions-viewer", inputs: ["data"] }, { kind: "component", type: AssetsLoaderComponent, selector: "assets-loader", inputs: ["assets", "storagePath"], outputs: ["assetsChange", "assetUpdate", "onFileSelected"] }, { kind: "component", type: DCLessonMetadataEditorComponent, selector: "dc-lesson-metadata-editor", inputs: ["form", "lesson", "isLoadingLesson"], outputs: ["saveRequest", "importNotionRequest", "improveNotionRequest"] }, { kind: "component", type: DcManageableFormComponent, selector: "dc-manageable-form", inputs: ["form"] }, { kind: "component", type: DcLearnableFormComponent, selector: "dc-learnable-form", inputs: ["form"] }] }); }
2448
2379
  }
2449
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DCLessonEditorComponent, decorators: [{
2380
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DCLessonEditorComponent, decorators: [{
2450
2381
  type: Component,
2451
2382
  args: [{ selector: 'dc-lesson-editor', standalone: true, imports: [
2452
2383
  ButtonModule,
2453
2384
  CKEditorModule,
2454
- CropperComponentModal,
2455
2385
  DCLessonRendererComponent,
2456
2386
  FormsModule,
2457
2387
  InputTextModule,
2388
+ ReactiveFormsModule,
2389
+ SelectButtonModule,
2458
2390
  SplitterModule,
2459
2391
  TooltipModule,
2460
2392
  DCLessonComponentAdderComponent, // Add the component adder here
2461
- DCLessonMetadataEditorComponent, // Add the metadata editor here
2462
2393
  DialogModule,
2463
- ], providers: [LessonNotionService], template: "<div style=\"position: relative; margin-bottom: 20px\">\n <img class=\"header-cover\" [src]=\"coverImageUrl()\" alt=\"Lesson Cover Image\" />\n\n <dc-cropper-modal\n style=\"position: absolute; top: 10px; left: 20px\"\n [buttonLabel]=\"'Carga una portada'\"\n [imgStorageSettings]=\"coverStorageSettings\"\n (imageUploaded)=\"onImageUploaded($event)\"></dc-cropper-modal>\n\n <p-button\n (click)=\"generateBanner()\"\n class=\"generate-banner-btn\"\n icon=\"pi pi-sparkles\"\n severity=\"primary\"\n [rounded]=\"true\"\n [raised]=\"true\"\n pTooltip=\"Generar Banner AI\"\n tooltipPosition=\"left\"></p-button>\n\n <p-button class=\"prompt-visual\" icon=\"pi pi-info\" label=\"Ver Prompts\" [link]=\"true\" (click)=\"showPrompts()\" />\n</div>\n\n<br />\n\n<!-- Lesson Metadata Editor -->\n<dc-lesson-metadata-editor\n [lesson]=\"lesson\"\n [isLoadingLesson]=\"isLoadingLesson\"\n (saveRequest)=\"saveLesson()\"\n (importNotionRequest)=\"importFromNotion()\"\n (improveNotionRequest)=\"improveNotionWithAI()\">\n</dc-lesson-metadata-editor>\n\n<div style=\"margin-top: 30px\"></div>\n\n<!-- Component Adder -->\n<dc-lesson-component-adder (componentAdded)=\"onComponentAdded($event)\"></dc-lesson-component-adder>\n\n<!-- Display Added Components -->\n<div class=\"added-components-list\" style=\"margin-top: 15px; margin-bottom: 15px\">\n <h4>Componentes Agregados:</h4>\n @if (dynamicComponentsArray().length > 0) {\n <ul>\n @for (comp of dynamicComponentsArray(); track comp.id) {\n <li\n >ID: {{ comp.id }} - Tipo: {{ comp.component }}\n\n <button pButton icon=\"pi pi-info\" (click)=\"showComponentDetails(comp)\"></button>\n <p-button icon=\"pi pi-pencil\" [rounded]=\"true\" severity=\"warn\" (click)=\"editComponent(comp)\"></p-button>\n </li>\n }\n </ul>\n } @else {\n <p>A\u00FAn no se han agregado componentes.</p>\n }\n</div>\n\n<hr />\n\n<!-- Text Editor and Renderer -->\n<p-splitter [style]=\"{ height: '80vh' }\">\n <ng-template pTemplate>\n <ckeditor\n (keydown.control.s)=\"saveLesson($event)\"\n class=\"text-editor\"\n [editor]=\"editor\"\n [ngModel]=\"lesson()?.textCoded\"\n (ngModelChange)=\"updateLessonProperty('textCoded', $event)\">\n </ckeditor>\n </ng-template>\n\n <ng-template pTemplate>\n <dc-lesson-renderer class=\"text-editor\" [lessonInput]=\"lesson()\"></dc-lesson-renderer>\n </ng-template>\n</p-splitter>\n\n<div class=\"float-button\">\n <!-- Removed p-speeddial -->\n <p-button icon=\"pi pi-save\" (click)=\"saveLesson()\" severity=\"primary\" [rounded]=\"true\" [raised]=\"true\" pTooltip=\"Guardar (Ctrl + S)\"> </p-button>\n</div>\n\n<hr />\n\n<p-dialog header=\"Prompts\" [modal]=\"true\" [(visible)]=\"promptsVisible\" [style]=\"{ width: '70%' }\">\n <div>\n <h1>Banner</h1>\n <p>{{ prompts?.banner }}</p>\n <h1>Contenido</h1>\n <p>{{ prompts?.content }}</p>\n <h1>Descripci\u00F3n</h1>\n <p>{{ prompts?.description }}</p>\n </div>\n</p-dialog>\n", styles: [".btn{padding:.5rem 1rem;border-radius:4px;border:1px solid transparent;cursor:pointer}.generate-banner-btn{position:absolute;right:10px;top:10px}.prompt-visual{position:absolute;left:10px;bottom:10px}.btn-primary{background-color:#007bff;color:#fff}.btn-outline-primary{border-color:#007bff;color:#007bff}.btn-secondary{background-color:#6c757d;color:#fff}.btn-outline-secondary{border-color:#6c757d;color:#6c757d}.btn-rounded{border-radius:50%}.form-control{padding:.375rem .75rem;border:1px solid #ced4da;border-radius:.25rem}.splitter{display:flex;gap:1rem}.splitter-panel{flex:1}.checkbox-container{display:inline-flex;align-items:center;gap:.5rem;cursor:pointer}.mr-2{margin-right:.5rem}.header-cover{width:100%;height:250px;object-fit:cover;position:relative;border-radius:8px}.float-button{position:fixed;bottom:3.5rem;right:2rem;z-index:1000;display:flex;gap:1px}.float-button :host ::ng-deep .p-button{width:4rem;height:4rem;border-radius:50%}.text-editor{width:-webkit-fill-available;overflow-y:auto}:host ::ng-deep .p-inputtext{background:#fff3}\n"] }]
2464
- }], ctorParameters: () => [], propDecorators: { target: [{
2465
- type: ViewChild,
2466
- args: ['target', { read: ViewContainerRef }]
2467
- }], dhtml: [{
2468
- type: ViewChild,
2469
- args: ['dhtml', { static: true }]
2470
- }] } });
2394
+ DcExtensionsViewerComponent,
2395
+ DcLearnableViewerComponent,
2396
+ DcAuditableViewerComponent,
2397
+ DcReactionsViewerComponent,
2398
+ AssetsLoaderComponent,
2399
+ DCLessonMetadataEditorComponent,
2400
+ DcManageableFormComponent,
2401
+ DcLearnableFormComponent,
2402
+ ], providers: [LessonNotionService], template: "<div class=\"p-grid\">\n <div class=\"p-col-4\">\n <assets-loader\n [assets]=\"entity()?.assets\"\n storagePath=\"lessons/{{ entityId() }}\"\n (assetsChange)=\"onAssetsChange($event)\"\n (assetUpdate)=\"onAssetUpdate($event)\"></assets-loader>\n </div>\n\n <div class=\"p-col-4\">\n <h3>Learnable</h3>\n <dc-learnable-viewer [data]=\"entity()?.learnable\"></dc-learnable-viewer>\n </div>\n <div class=\"p-col-4\">\n <h3>Auditable</h3>\n <dc-auditable-viewer [data]=\"entity()?.auditable\"></dc-auditable-viewer>\n </div>\n <div class=\"p-col-4\">\n <h3>Manageable</h3>\n <dc-manageable-form [form]=\"form.controls.manageable\"></dc-manageable-form>\n </div>\n <div class=\"p-col-4\">\n <h3>Learnable</h3>\n <dc-learnable-form [form]=\"form.controls.learnable\"></dc-learnable-form>\n </div>\n <div class=\"p-col-4\">\n <h3>Reactions</h3>\n <dc-reactions-viewer [data]=\"entity()?.reactions\"></dc-reactions-viewer>\n </div>\n\n <div class=\"p-col-4\">\n <h3>Extensions</h3>\n <dc-extensions-viewer [data]=\"entity()?.extensions\"></dc-extensions-viewer>\n </div>\n</div>\n\n<!-- Lesson Metadata Editor -->\n<div [formGroup]=\"form\">\n <p-selectButton [options]=\"formatOptions\" formControlName=\"format\" optionLabel=\"label\" optionValue=\"value\" />\n</div>\n<dc-lesson-metadata-editor [lesson]=\"entity()\" [form]=\"form\" [isLoadingLesson]=\"isLoadingLesson()\"></dc-lesson-metadata-editor>\n\n<div style=\"margin-top: 30px\"></div>\n\n<!-- Component Adder -->\n<dc-lesson-component-adder (componentAdded)=\"onComponentAdded($event)\"></dc-lesson-component-adder>\n\n<!-- Display Added Components -->\n<div class=\"added-components-list\" style=\"margin-top: 15px; margin-bottom: 15px\">\n <h4>Componentes Agregados:</h4>\n @if (dynamicComponentsArray().length > 0) {\n <ul>\n @for (comp of dynamicComponentsArray(); track comp.id) {\n <li\n >ID: {{ comp.id }} - Tipo: {{ comp.component }}\n\n <button pButton icon=\"pi pi-info\" (click)=\"showComponentDetails(comp)\"></button>\n <p-button icon=\"pi pi-pencil\" [rounded]=\"true\" severity=\"warn\" (click)=\"editComponent(comp)\"></p-button>\n </li>\n }\n </ul>\n } @else {\n <p>A\u00FAn no se han agregado componentes.</p>\n }\n</div>\n\n<hr />\n\n<!-- Text Editor and Renderer -->\n<p-splitter [style]=\"{ height: '80vh' }\">\n <ng-template pTemplate>\n <ckeditor\n (keydown.control.s)=\"saveLesson($event)\"\n class=\"text-editor\"\n [editor]=\"editor\"\n [ngModel]=\"htmlTemporal\"\n (ngModelChange)=\"updateHtmlTextCoded('textCoded', $event)\">\n </ckeditor>\n </ng-template>\n\n <ng-template pTemplate>\n <dc-lesson-renderer class=\"text-editor\" [lessonInput]=\"entity()\"></dc-lesson-renderer>\n </ng-template>\n</p-splitter>\n\n<div class=\"float-button\">\n <p-button icon=\"pi pi-save\" (click)=\"save()\" severity=\"primary\" [rounded]=\"true\" [raised]=\"true\" pTooltip=\"Guardar (Ctrl + S)\"> </p-button>\n</div>\n\n<hr />\n\n<!-- <p-dialog header=\"Prompts\" [modal]=\"true\" [(visible)]=\"promptsVisible\" [style]=\"{ width: '70%' }\">\n <div>\n <h1>Banner</h1>\n <p>{{ prompts?.banner }}</p>\n <h1>Contenido</h1>\n <p>{{ prompts?.content }}</p>\n <h1>Descripci\u00F3n</h1>\n <p>{{ prompts?.description }}</p>\n </div>\n</p-dialog> -->\n", styles: [".btn{padding:.5rem 1rem;border-radius:4px;border:1px solid transparent;cursor:pointer}.generate-banner-btn{position:absolute;right:10px;top:10px}.prompt-visual{position:absolute;left:10px;bottom:10px}.btn-primary{background-color:#007bff;color:#fff}.btn-outline-primary{border-color:#007bff;color:#007bff}.btn-secondary{background-color:#6c757d;color:#fff}.btn-outline-secondary{border-color:#6c757d;color:#6c757d}.btn-rounded{border-radius:50%}.form-control{padding:.375rem .75rem;border:1px solid #ced4da;border-radius:.25rem}.splitter{display:flex;gap:1rem}.splitter-panel{flex:1}.checkbox-container{display:inline-flex;align-items:center;gap:.5rem;cursor:pointer}.mr-2{margin-right:.5rem}.header-cover{width:100%;height:250px;object-fit:cover;position:relative;border-radius:8px}.float-button{position:fixed;bottom:3.5rem;right:2rem;z-index:1000;display:flex;gap:1px}.float-button :host ::ng-deep .p-button{width:4rem;height:4rem;border-radius:50%}.text-editor{width:-webkit-fill-available;overflow-y:auto}:host ::ng-deep .p-inputtext{background:#fff3}::ng-deep .p-splitter .p-splitterpanel{overflow:auto!important}\n"] }]
2403
+ }] });
2404
+
2405
+ class LessonsV2Component {
2406
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: LessonsV2Component, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2407
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.6", type: LessonsV2Component, isStandalone: true, selector: "app-lessonsv2", ngImport: i0, template: '<router-outlet></router-outlet>', isInline: true, dependencies: [{ kind: "directive", type: RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }] }); }
2408
+ }
2409
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: LessonsV2Component, decorators: [{
2410
+ type: Component,
2411
+ args: [{
2412
+ selector: 'app-lessonsv2',
2413
+ template: '<router-outlet></router-outlet>',
2414
+ standalone: true,
2415
+ imports: [RouterOutlet],
2416
+ }]
2417
+ }] });
2471
2418
 
2472
2419
  // This is the base class for all the components that are going to be used in the lessons.
2473
2420
  class LessonDynamicComponent {
2474
2421
  constructor() {
2475
2422
  this.settings = {};
2476
2423
  }
2477
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: LessonDynamicComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2478
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.4", type: LessonDynamicComponent, isStandalone: true, selector: "app-lesson-component", inputs: { settings: "settings" }, ngImport: i0, template: '<div>no template</div>', isInline: true }); }
2424
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: LessonDynamicComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2425
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.6", type: LessonDynamicComponent, isStandalone: true, selector: "app-lesson-component", inputs: { settings: "settings" }, ngImport: i0, template: '<div>no template</div>', isInline: true }); }
2479
2426
  }
2480
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: LessonDynamicComponent, decorators: [{
2427
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: LessonDynamicComponent, decorators: [{
2481
2428
  type: Component,
2482
2429
  args: [{
2483
2430
  selector: 'app-lesson-component',
@@ -2488,7 +2435,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImpor
2488
2435
  type: Input
2489
2436
  }] } });
2490
2437
 
2491
- const Endpoints$1 = {
2438
+ const Endpoints = {
2492
2439
  courses: 'api/courses',
2493
2440
  };
2494
2441
  class CoursesService {
@@ -2497,12 +2444,12 @@ class CoursesService {
2497
2444
  }
2498
2445
  // Not sure how to implement this yet.
2499
2446
  getCourses() {
2500
- return this.httpCoreService.get(Endpoints$1.courses);
2447
+ return this.httpCoreService.get(Endpoints.courses);
2501
2448
  }
2502
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: CoursesService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2503
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: CoursesService, providedIn: 'root' }); }
2449
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: CoursesService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2450
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: CoursesService, providedIn: 'root' }); }
2504
2451
  }
2505
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: CoursesService, decorators: [{
2452
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: CoursesService, decorators: [{
2506
2453
  type: Injectable,
2507
2454
  args: [{
2508
2455
  providedIn: 'root',
@@ -2517,92 +2464,48 @@ class CoursesAdminComponent {
2517
2464
  const courses = await this.httpCoreService.get('courses');
2518
2465
  console.log(courses);
2519
2466
  }
2520
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: CoursesAdminComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2521
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.4", type: CoursesAdminComponent, isStandalone: true, selector: "ngx-courses-admin", ngImport: i0, template: "<p>welcome to courses creation</p>\n", styles: [""] }); }
2467
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: CoursesAdminComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2468
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.6", type: CoursesAdminComponent, isStandalone: true, selector: "ngx-courses-admin", ngImport: i0, template: "<p>welcome to courses creation</p>\n", styles: [""] }); }
2522
2469
  }
2523
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: CoursesAdminComponent, decorators: [{
2470
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: CoursesAdminComponent, decorators: [{
2524
2471
  type: Component,
2525
2472
  args: [{ selector: 'ngx-courses-admin', standalone: true, template: "<p>welcome to courses creation</p>\n" }]
2526
2473
  }] });
2527
2474
 
2528
- class CoursesComponent {
2529
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: CoursesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2530
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.4", type: CoursesComponent, isStandalone: true, selector: "app-courses", ngImport: i0, template: "<router-outlet />\n", styles: [":host{display:block;height:100%}\n"], dependencies: [{ kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1$3.RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2531
- }
2532
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: CoursesComponent, decorators: [{
2533
- type: Component,
2534
- args: [{ selector: 'app-courses', imports: [RouterModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<router-outlet />\n", styles: [":host{display:block;height:100%}\n"] }]
2535
- }] });
2536
-
2537
- class CourseDetailComponent {
2538
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: CourseDetailComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2539
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.4", type: CourseDetailComponent, isStandalone: true, selector: "app-course-detail", ngImport: i0, template: `<p>course-detail works!</p>`, isInline: true, styles: [":host{display:block}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2540
- }
2541
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: CourseDetailComponent, decorators: [{
2542
- type: Component,
2543
- args: [{ selector: 'app-course-detail', imports: [], template: `<p>course-detail works!</p>`, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block}\n"] }]
2544
- }] });
2545
-
2546
- const server = 'primary';
2547
- // TODO add your own end points
2548
- const Endpoints = {
2549
- Courses: {
2550
- Courses: 'api/courses',
2551
- CoursesFiltered: 'api/courses/query',
2552
- },
2553
- };
2554
- class CourseService {
2475
+ class CourseService extends EntityCommunicationService {
2555
2476
  constructor() {
2556
- this.httpService = inject(HttpCoreService);
2557
- this.toastService = inject(TOAST_ALERTS_TOKEN);
2558
- }
2559
- async getCourses() {
2560
- try {
2561
- const response = await this.httpService.get(Endpoints.Courses.Courses, server);
2562
- this.toastService.success({ title: 'Se han encontrado generics', subtitle: 'Mostrando información' });
2563
- return response;
2564
- }
2565
- catch (error) {
2566
- this.toastService.warn({ title: 'Error fetching generics', subtitle: 'Showing Default Data' });
2567
- // return RemoveSimpleDataExample;
2568
- return [];
2569
- }
2570
- }
2571
- async getFilteredCourses(filter) {
2572
- return this.httpService.post(Endpoints.Courses.CoursesFiltered, filter, server);
2573
- }
2574
- async getCourse(id) {
2575
- return this.httpService.get(`${Endpoints.Courses.Courses}/${id}`);
2477
+ super('courses');
2576
2478
  }
2577
- async saveCourse(course) {
2578
- return this.httpService.post(Endpoints.Courses.Courses, course);
2479
+ generateLanguageCourse(base, target, id = '') {
2480
+ return this.httpService.post(`api/courses/generate-language`, { base, target, id });
2579
2481
  }
2580
- async deleteCourse(id) {
2581
- return this.httpService.delete(`${Endpoints.Courses.Courses}/${id}`);
2482
+ autogenerateLessons(id) {
2483
+ return this.httpService.post(`api/courses/autogenerate-lessons`, { id });
2582
2484
  }
2583
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: CourseService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2584
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: CourseService, providedIn: 'root' }); }
2485
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: CourseService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2486
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: CourseService, providedIn: 'root' }); }
2585
2487
  }
2586
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: CourseService, decorators: [{
2488
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: CourseService, decorators: [{
2587
2489
  type: Injectable,
2588
2490
  args: [{
2589
2491
  providedIn: 'root',
2590
2492
  }]
2591
- }] });
2493
+ }], ctorParameters: () => [] });
2592
2494
 
2593
2495
  class CourseListComponent extends PaginationBase {
2594
2496
  constructor() {
2595
2497
  super(...arguments);
2596
2498
  // Services
2597
2499
  this.toastService = inject(TOAST_ALERTS_TOKEN);
2598
- this.sourceService = inject(CourseService);
2500
+ this.courseService = inject(CourseService);
2501
+ this.userService = inject(UserService);
2599
2502
  this.cdr = inject(ChangeDetectorRef);
2600
2503
  // Inputs
2601
2504
  this.viewType = 'card';
2602
- this.onlyView = input(true);
2505
+ this.onlyView = input(true, ...(ngDevMode ? [{ debugName: "onlyView" }] : []));
2603
2506
  this.onSelect = output();
2604
2507
  // States
2605
- this.courses = signal([]);
2508
+ this.courses = signal([], ...(ngDevMode ? [{ debugName: "courses" }] : []));
2606
2509
  this.columns = ['name', 'description', 'updatedAt', 'image'];
2607
2510
  this.filterBarOptions = { showActions: true, showCreateButton: true, showViewButton: true };
2608
2511
  }
@@ -2626,8 +2529,14 @@ class CourseListComponent extends PaginationBase {
2626
2529
  ];
2627
2530
  }
2628
2531
  async ngOnInit() {
2629
- this.filterConfig.returnProps = { _id: 1, id: 1, name: 1, description: 1, updatedAt: 1, image: 1 };
2630
- const response = await this.sourceService.getFilteredCourses(this.filterConfig);
2532
+ const user = this.userService.user();
2533
+ const targetLang = user?.settings?.['targetLanguage'];
2534
+ const baseLang = user?.settings?.['baseLanguage'];
2535
+ // console.log(user?.settings?.['targetLanguage']);
2536
+ this.filterConfig.filters = { baseLang: baseLang, targetLang: targetLang };
2537
+ this.filterConfig.returnProps = { _id: 1, id: 1, name: 1, description: 1, updatedAt: 1, image: 1, baseLang: 1, targetLang: 1, auditable: 1 };
2538
+ // this.filterConfig.filters = { targetLang: 'de', baseLang: 'es' };
2539
+ const response = await this.courseService.query(this.filterConfig);
2631
2540
  this.courses.set(response.rows);
2632
2541
  this.cdr.detectChanges();
2633
2542
  console.log(this.courses(), this.viewType);
@@ -2654,15 +2563,15 @@ class CourseListComponent extends PaginationBase {
2654
2563
  if (action == 'changeView') {
2655
2564
  this.toggleView();
2656
2565
  }
2566
+ const id = item.id || item._id;
2657
2567
  switch (action) {
2658
2568
  case 'view':
2659
- this.router.navigate(['./details', item.id], { relativeTo: this.route });
2569
+ this.router.navigate(['./details', id], { relativeTo: this.route });
2660
2570
  break;
2661
2571
  case 'delete':
2662
2572
  const areYouSure = confirm('¿Estás seguro de querer eliminar este origen?');
2663
2573
  if (areYouSure) {
2664
- const id = item.id || item._id;
2665
- await this.sourceService.deleteCourse(id);
2574
+ await this.courseService.remove(id);
2666
2575
  this.courses.set(this.courses().filter((course) => course._id !== id));
2667
2576
  this.toastService.success({
2668
2577
  title: 'Origen eliminado',
@@ -2672,14 +2581,14 @@ class CourseListComponent extends PaginationBase {
2672
2581
  }
2673
2582
  break;
2674
2583
  case 'edit':
2675
- this.router.navigate(['./edit', item.id], { relativeTo: this.route });
2584
+ this.router.navigate(['./edit', id], { relativeTo: this.route });
2676
2585
  break;
2677
2586
  }
2678
2587
  }
2679
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: CourseListComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
2680
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.4", type: CourseListComponent, isStandalone: true, selector: "app-course-list", inputs: { viewType: { classPropertyName: "viewType", publicName: "viewType", isSignal: false, isRequired: false, transformFunction: null }, onlyView: { classPropertyName: "onlyView", publicName: "onlyView", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onSelect: "onSelect" }, usesInheritance: true, ngImport: i0, template: "@if (!onlyView()) {\n<p-button [icon]=\"viewType === 'card' ? 'pi pi-table' : 'pi pi-list'\" label=\"Change View\" [link]=\"true\" (click)=\"toggleView()\" />\n}\n<div class=\"course-list-container\">\n <dc-filter-bar [options]=\"filterBarOptions\" (onNew)=\"onNew()\" (onFilterAction)=\"doAction($event)\"></dc-filter-bar>\n\n @if (viewType === 'card') {\n <div class=\"course-list-content\">\n @for (course of courses(); track course.id) {\n <div class=\"card-source\">\n <div style=\"position: absolute; top: 4px; right: 4px; z-index: 1000\">\n <p-speeddial\n [model]=\"getCustomButtons(course)\"\n [radius]=\"70\"\n type=\"quarter-circle\"\n direction=\"down-left\"\n [buttonProps]=\"{ severity: 'primary', rounded: true, outlined: true }\" />\n </div>\n <p-card [header]=\"course.name\">\n <p class=\"m-0\">{{ course.description | slice : 0 : 250 }}...</p>\n <span>{{ course.updatedAt | date : 'dd/MM/yyyy HH:mm' }}</span>\n </p-card>\n </div>\n } @if (courses().length === 0) {\n <p-card>\n <p>No courses found</p>\n </p-card>\n }\n </div>\n } @else if ( viewType == 'table'){\n\n <app-quick-table [tableData]=\"courses()\"></app-quick-table>\n\n }\n\n <div class=\"paginator-container\">\n <p-paginator\n currentPageReportTemplate=\"{{ totalRecords }} conversations\"\n [showCurrentPageReport]=\"true\"\n (onPageChange)=\"onPageChange($event)\"\n [first]=\"paginatorFirst\"\n [rows]=\"paginatorRows\"\n [totalRecords]=\"totalRecords\"\n [rowsPerPageOptions]=\"[10, 20, 30]\">\n </p-paginator>\n </div>\n</div>\n", styles: [":host{display:block;height:100%}.course-list-container{display:flex;flex-direction:column;height:100%}.course-list-content{margin-top:10px;flex:1;overflow-y:auto;padding-bottom:10px}.card-source{margin-bottom:10px;position:relative}.paginator-container{margin-top:auto;padding-top:10px}\n"], dependencies: [{ kind: "ngmodule", type: CardModule }, { kind: "component", type: i3$1.Card, selector: "p-card", inputs: ["header", "subheader", "style", "styleClass"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: DCFilterBarComponent, selector: "dc-filter-bar", inputs: ["items", "options", "customFilters"], outputs: ["onFilterAction", "onChangeSort", "onNew"] }, { kind: "ngmodule", type: SpeedDialModule }, { kind: "component", type: i2$1.SpeedDial, selector: "p-speeddial, p-speedDial, p-speed-dial", inputs: ["id", "model", "visible", "style", "className", "direction", "transitionDelay", "type", "radius", "mask", "disabled", "hideOnClickOutside", "buttonStyle", "buttonClassName", "maskStyle", "maskClassName", "showIcon", "hideIcon", "rotateAnimation", "ariaLabel", "ariaLabelledBy", "tooltipOptions", "buttonProps"], outputs: ["onVisibleChange", "visibleChange", "onClick", "onShow", "onHide"] }, { kind: "pipe", type: DatePipe, name: "date" }, { kind: "pipe", type: SlicePipe, name: "slice" }, { kind: "ngmodule", type: PaginatorModule }, { kind: "component", type: i1$2.Paginator, selector: "p-paginator", inputs: ["pageLinkSize", "style", "styleClass", "alwaysShow", "dropdownAppendTo", "templateLeft", "templateRight", "appendTo", "dropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showFirstLastIcon", "totalRecords", "rows", "rowsPerPageOptions", "showJumpToPageDropdown", "showJumpToPageInput", "jumpToPageItemTemplate", "showPageLinks", "locale", "dropdownItemTemplate", "first"], outputs: ["onPageChange"] }, { kind: "ngmodule", type: RouterModule }, { kind: "ngmodule", type: TableModule }, { kind: "component", type: QuickTableComponent, selector: "app-quick-table", inputs: ["columns", "tableData", "actions"], outputs: ["onAction"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2588
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: CourseListComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
2589
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.6", type: CourseListComponent, isStandalone: true, selector: "app-course-list", inputs: { viewType: { classPropertyName: "viewType", publicName: "viewType", isSignal: false, isRequired: false, transformFunction: null }, onlyView: { classPropertyName: "onlyView", publicName: "onlyView", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onSelect: "onSelect" }, usesInheritance: true, ngImport: i0, template: "@if (!onlyView()) {\n<p-button [icon]=\"viewType === 'card' ? 'pi pi-table' : 'pi pi-list'\" label=\"Change View\" [link]=\"true\" (click)=\"toggleView()\" />\n}\n<div class=\"course-list-container\">\n <dc-filter-bar [options]=\"filterBarOptions\" (onNew)=\"onNew()\" (onFilterAction)=\"doAction($event)\"></dc-filter-bar>\n\n @if (viewType === 'card') {\n <div class=\"course-list-content\">\n @for (course of courses(); track course.id) {\n <div class=\"card-source\">\n <div style=\"position: absolute; top: 4px; right: 4px; z-index: 1000\">\n <p-speeddial\n [model]=\"getCustomButtons(course)\"\n [radius]=\"70\"\n type=\"quarter-circle\"\n direction=\"down-left\"\n [buttonProps]=\"{ severity: 'primary', rounded: true, outlined: true }\"\n [tooltipOptions]=\"{ tooltipPosition: 'top' }\" />\n </div>\n <p-card [header]=\"course.name\">\n <p class=\"m-0\">{{ course.description | slice : 0 : 250 }}...</p>\n <span>{{ course?.auditable?.createdAt | date : 'dd/MM/yyyy HH:mm' }}</span>\n\n <p-tag severity=\"success\" [value]=\"course.baseLang | langDesc : 'es'\" [rounded]=\"true\" />\n ->\n <p-tag severity=\"info\" [value]=\"course.targetLang | langDesc : 'es'\" [rounded]=\"true\" />\n </p-card>\n </div>\n } @if (courses().length === 0) {\n <p-card>\n <p>No courses found</p>\n </p-card>\n }\n </div>\n } @else if ( viewType == 'table'){\n\n <app-quick-table [tableData]=\"courses()\"></app-quick-table>\n\n }\n\n <div class=\"paginator-container\">\n <p-paginator\n currentPageReportTemplate=\"{{ totalRecords }} conversations\"\n [showCurrentPageReport]=\"true\"\n (onPageChange)=\"onPageChange($event)\"\n [totalRecords]=\"totalRecords\"\n [rowsPerPageOptions]=\"[10, 20, 30]\">\n </p-paginator>\n </div>\n</div>\n", styles: [":host{display:block;height:100%}.course-list-container{display:flex;flex-direction:column;height:100%}.course-list-content{margin:20px;flex:1;overflow-y:auto;padding-bottom:10px}.card-source{margin:20px;position:relative}.paginator-container{margin-top:auto;padding-top:10px}\n"], dependencies: [{ kind: "ngmodule", type: CardModule }, { kind: "component", type: i1$2.Card, selector: "p-card", inputs: ["header", "subheader", "style", "styleClass"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: DCFilterBarComponent, selector: "dc-filter-bar", inputs: ["items", "options", "customFilters"], outputs: ["onFilterAction", "onChangeSort", "onNew"] }, { kind: "ngmodule", type: SpeedDialModule }, { kind: "component", type: i2$1.SpeedDial, selector: "p-speeddial, p-speedDial, p-speed-dial", inputs: ["id", "model", "visible", "style", "className", "direction", "transitionDelay", "type", "radius", "mask", "disabled", "hideOnClickOutside", "buttonStyle", "buttonClassName", "maskStyle", "maskClassName", "showIcon", "hideIcon", "rotateAnimation", "ariaLabel", "ariaLabelledBy", "tooltipOptions", "buttonProps"], outputs: ["onVisibleChange", "visibleChange", "onClick", "onShow", "onHide"] }, { kind: "ngmodule", type: PaginatorModule }, { kind: "component", type: i1$3.Paginator, selector: "p-paginator", inputs: ["pageLinkSize", "styleClass", "alwaysShow", "dropdownAppendTo", "templateLeft", "templateRight", "dropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showFirstLastIcon", "totalRecords", "rows", "rowsPerPageOptions", "showJumpToPageDropdown", "showJumpToPageInput", "jumpToPageItemTemplate", "showPageLinks", "locale", "dropdownItemTemplate", "first", "appendTo"], outputs: ["onPageChange"] }, { kind: "ngmodule", type: RouterModule }, { kind: "ngmodule", type: TableModule }, { kind: "component", type: QuickTableComponent, selector: "app-quick-table", inputs: ["columns", "tableData", "actions"], outputs: ["onAction"] }, { kind: "ngmodule", type: TagModule }, { kind: "component", type: i4$1.Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }, { kind: "pipe", type: DatePipe, name: "date" }, { kind: "pipe", type: SlicePipe, name: "slice" }, { kind: "pipe", type: LangDescTranslation, name: "langDesc" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2681
2590
  }
2682
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: CourseListComponent, decorators: [{
2591
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: CourseListComponent, decorators: [{
2683
2592
  type: Component,
2684
2593
  args: [{ selector: 'app-course-list', imports: [
2685
2594
  CardModule,
@@ -2692,19 +2601,82 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImpor
2692
2601
  RouterModule,
2693
2602
  TableModule,
2694
2603
  QuickTableComponent,
2695
- ], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (!onlyView()) {\n<p-button [icon]=\"viewType === 'card' ? 'pi pi-table' : 'pi pi-list'\" label=\"Change View\" [link]=\"true\" (click)=\"toggleView()\" />\n}\n<div class=\"course-list-container\">\n <dc-filter-bar [options]=\"filterBarOptions\" (onNew)=\"onNew()\" (onFilterAction)=\"doAction($event)\"></dc-filter-bar>\n\n @if (viewType === 'card') {\n <div class=\"course-list-content\">\n @for (course of courses(); track course.id) {\n <div class=\"card-source\">\n <div style=\"position: absolute; top: 4px; right: 4px; z-index: 1000\">\n <p-speeddial\n [model]=\"getCustomButtons(course)\"\n [radius]=\"70\"\n type=\"quarter-circle\"\n direction=\"down-left\"\n [buttonProps]=\"{ severity: 'primary', rounded: true, outlined: true }\" />\n </div>\n <p-card [header]=\"course.name\">\n <p class=\"m-0\">{{ course.description | slice : 0 : 250 }}...</p>\n <span>{{ course.updatedAt | date : 'dd/MM/yyyy HH:mm' }}</span>\n </p-card>\n </div>\n } @if (courses().length === 0) {\n <p-card>\n <p>No courses found</p>\n </p-card>\n }\n </div>\n } @else if ( viewType == 'table'){\n\n <app-quick-table [tableData]=\"courses()\"></app-quick-table>\n\n }\n\n <div class=\"paginator-container\">\n <p-paginator\n currentPageReportTemplate=\"{{ totalRecords }} conversations\"\n [showCurrentPageReport]=\"true\"\n (onPageChange)=\"onPageChange($event)\"\n [first]=\"paginatorFirst\"\n [rows]=\"paginatorRows\"\n [totalRecords]=\"totalRecords\"\n [rowsPerPageOptions]=\"[10, 20, 30]\">\n </p-paginator>\n </div>\n</div>\n", styles: [":host{display:block;height:100%}.course-list-container{display:flex;flex-direction:column;height:100%}.course-list-content{margin-top:10px;flex:1;overflow-y:auto;padding-bottom:10px}.card-source{margin-bottom:10px;position:relative}.paginator-container{margin-top:auto;padding-top:10px}\n"] }]
2604
+ TagModule,
2605
+ LangDescTranslation,
2606
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (!onlyView()) {\n<p-button [icon]=\"viewType === 'card' ? 'pi pi-table' : 'pi pi-list'\" label=\"Change View\" [link]=\"true\" (click)=\"toggleView()\" />\n}\n<div class=\"course-list-container\">\n <dc-filter-bar [options]=\"filterBarOptions\" (onNew)=\"onNew()\" (onFilterAction)=\"doAction($event)\"></dc-filter-bar>\n\n @if (viewType === 'card') {\n <div class=\"course-list-content\">\n @for (course of courses(); track course.id) {\n <div class=\"card-source\">\n <div style=\"position: absolute; top: 4px; right: 4px; z-index: 1000\">\n <p-speeddial\n [model]=\"getCustomButtons(course)\"\n [radius]=\"70\"\n type=\"quarter-circle\"\n direction=\"down-left\"\n [buttonProps]=\"{ severity: 'primary', rounded: true, outlined: true }\"\n [tooltipOptions]=\"{ tooltipPosition: 'top' }\" />\n </div>\n <p-card [header]=\"course.name\">\n <p class=\"m-0\">{{ course.description | slice : 0 : 250 }}...</p>\n <span>{{ course?.auditable?.createdAt | date : 'dd/MM/yyyy HH:mm' }}</span>\n\n <p-tag severity=\"success\" [value]=\"course.baseLang | langDesc : 'es'\" [rounded]=\"true\" />\n ->\n <p-tag severity=\"info\" [value]=\"course.targetLang | langDesc : 'es'\" [rounded]=\"true\" />\n </p-card>\n </div>\n } @if (courses().length === 0) {\n <p-card>\n <p>No courses found</p>\n </p-card>\n }\n </div>\n } @else if ( viewType == 'table'){\n\n <app-quick-table [tableData]=\"courses()\"></app-quick-table>\n\n }\n\n <div class=\"paginator-container\">\n <p-paginator\n currentPageReportTemplate=\"{{ totalRecords }} conversations\"\n [showCurrentPageReport]=\"true\"\n (onPageChange)=\"onPageChange($event)\"\n [totalRecords]=\"totalRecords\"\n [rowsPerPageOptions]=\"[10, 20, 30]\">\n </p-paginator>\n </div>\n</div>\n", styles: [":host{display:block;height:100%}.course-list-container{display:flex;flex-direction:column;height:100%}.course-list-content{margin:20px;flex:1;overflow-y:auto;padding-bottom:10px}.card-source{margin:20px;position:relative}.paginator-container{margin-top:auto;padding-top:10px}\n"] }]
2696
2607
  }], propDecorators: { viewType: [{
2697
2608
  type: Input
2698
2609
  }] } });
2699
2610
 
2700
- class CourseFormComponent {
2611
+ class CourseDetailComponent {
2701
2612
  constructor() {
2702
- this.route = inject(ActivatedRoute);
2703
- this.courseService = inject(CourseService);
2613
+ this.entityCommunicationService = inject(CourseService);
2614
+ this.activatedRoute = inject(ActivatedRoute);
2615
+ this.messageService = inject(MessageService);
2616
+ this.courseId = this.activatedRoute.snapshot.paramMap.get('id');
2617
+ this.course = signal(null, ...(ngDevMode ? [{ debugName: "course" }] : []));
2618
+ this.generatingLessons = signal(false, ...(ngDevMode ? [{ debugName: "generatingLessons" }] : []));
2619
+ this.generatingLesson = signal('', ...(ngDevMode ? [{ debugName: "generatingLesson" }] : []));
2620
+ }
2621
+ ngOnInit() {
2622
+ this.loadCourse();
2623
+ }
2624
+ async generatePendingLessons() {
2625
+ this.generatingLessons.set(true);
2626
+ try {
2627
+ await this.entityCommunicationService.autogenerateLessons(this.courseId);
2628
+ this.messageService.add({ severity: 'success', summary: 'Success', detail: 'Lessons generated successfully' });
2629
+ this.loadCourse();
2630
+ }
2631
+ catch (error) {
2632
+ this.messageService.add({ severity: 'error', summary: 'Error', detail: 'Error generating lessons' });
2633
+ }
2634
+ finally {
2635
+ this.generatingLessons.set(false);
2636
+ }
2637
+ }
2638
+ async generateLesson(lessonId) {
2639
+ this.generatingLesson.set(lessonId);
2640
+ try {
2641
+ // TODO: Implement the generateLesson method
2642
+ // await this.entityCommunicationService.autogenerateLesson(this.courseId, lessonId);
2643
+ this.messageService.add({ severity: 'success', summary: 'Success', detail: 'Lesson generated successfully' });
2644
+ this.loadCourse();
2645
+ }
2646
+ catch (error) {
2647
+ this.messageService.add({ severity: 'error', summary: 'Error', detail: 'Error generating lesson' });
2648
+ }
2649
+ finally {
2650
+ this.generatingLesson.set('');
2651
+ }
2652
+ }
2653
+ async loadCourse() {
2654
+ const course = await this.entityCommunicationService.findOne(this.courseId);
2655
+ this.course.set(course);
2656
+ }
2657
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: CourseDetailComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2658
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.6", type: CourseDetailComponent, isStandalone: true, selector: "app-course-detail", providers: [MessageService], ngImport: i0, template: "@if (course(); as course) {\n<div class=\"course-detail-container p-4\">\n <p-card>\n <ng-template pTemplate=\"title\">\n <div class=\"flex justify-content-between align-items-center\">\n <span>{{ course.name }}</span>\n </div>\n </ng-template>\n <ng-template pTemplate=\"subtitle\">\n <div class=\"flex align-items-center gap-2\">\n <i class=\"pi pi-book\"></i>\n <span>{{ course.moduleCount }} Modules / {{ course.totalLessons }} Lessons</span>\n </div>\n </ng-template>\n <ng-template pTemplate=\"content\">\n <p>{{ course.description }}</p>\n\n <div class=\"grid mt-3\">\n @for (module of course.modules; track module.id) {\n <div class=\"col-12 md:col-6\">\n <p-panel [toggleable]=\"true\">\n <ng-template pTemplate=\"header\">\n <div class=\"flex align-items-center gap-2 w-full\">\n <i class=\"pi pi-list\"></i>\n <span class=\"font-bold white-space-nowrap\">{{ module.title }}</span>\n <span class=\"text-sm text-color-secondary ml-auto\">{{ module.lessonCount }} lessons</span>\n </div>\n </ng-template>\n <ng-template pTemplate=\"content\">\n <p>{{ module.description }}</p>\n <ul class=\"list-none p-0 m-0 lessons-list\">\n @for (lesson of module.lessons; track lesson.id) {\n <li class=\"flex align-items-center justify-content-between p-2 border-bottom-1 surface-border\">\n <div class=\"flex align-items-center gap-2\">\n @if(lesson.generated) {\n <i class=\"pi pi-play-circle text-green-500\"></i>\n } @else {\n <i class=\"pi pi-lock text-gray-500\"></i>\n }\n <span>{{ lesson.title }}</span>\n </div>\n @if(lesson.generated) {\n <p-button icon=\"pi pi-chevron-right\" [text]=\"true\" [rounded]=\"true\"></p-button>\n } @else {\n <p-button label=\"Generate\" icon=\"pi pi-cog\" [text]=\"true\" size=\"small\"></p-button>\n }\n </li>\n }\n </ul>\n </ng-template>\n </p-panel>\n </div>\n }\n </div>\n </ng-template>\n <ng-template pTemplate=\"footer\">\n <div class=\"flex justify-content-end\">\n <p-button label=\"Generate Pending Lessons\" icon=\"pi pi-cogs\" (onClick)=\"generatePendingLessons()\" [loading]=\"generatingLessons()\"></p-button>\n </div>\n </ng-template>\n </p-card>\n</div>\n} @else {\n<div class=\"flex justify-content-center align-items-center h-full\">\n <p-progressSpinner></p-progressSpinner>\n</div>\n}\n", styles: [":host{display:block;height:100%}.course-detail-container{max-width:960px;margin:auto}.lessons-list li:last-child{border-bottom:none!important}.modules-container{display:flex;flex-direction:row;flex-wrap:nowrap;overflow-x:auto;-webkit-overflow-scrolling:touch;padding-bottom:1rem}.modules-container .p-panel{flex:0 0 48%;max-width:48%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: CardModule }, { kind: "component", type: i1$2.Card, selector: "p-card", inputs: ["header", "subheader", "style", "styleClass"] }, { kind: "directive", type: i2$3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: PanelModule }, { kind: "component", type: i3$2.Panel, selector: "p-panel", inputs: ["toggleable", "header", "collapsed", "id", "styleClass", "iconPos", "showHeader", "toggler", "transitionOptions", "toggleButtonProps"], outputs: ["collapsedChange", "onBeforeToggle", "onAfterToggle"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: ProgressSpinnerModule }, { kind: "component", type: i5$2.ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }, { kind: "ngmodule", type: ToastModule }, { kind: "ngmodule", type: TagModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2659
+ }
2660
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: CourseDetailComponent, decorators: [{
2661
+ type: Component,
2662
+ args: [{ selector: 'app-course-detail', imports: [CommonModule, CardModule, PanelModule, ButtonModule, ProgressSpinnerModule, ToastModule, TagModule], changeDetection: ChangeDetectionStrategy.OnPush, providers: [MessageService], template: "@if (course(); as course) {\n<div class=\"course-detail-container p-4\">\n <p-card>\n <ng-template pTemplate=\"title\">\n <div class=\"flex justify-content-between align-items-center\">\n <span>{{ course.name }}</span>\n </div>\n </ng-template>\n <ng-template pTemplate=\"subtitle\">\n <div class=\"flex align-items-center gap-2\">\n <i class=\"pi pi-book\"></i>\n <span>{{ course.moduleCount }} Modules / {{ course.totalLessons }} Lessons</span>\n </div>\n </ng-template>\n <ng-template pTemplate=\"content\">\n <p>{{ course.description }}</p>\n\n <div class=\"grid mt-3\">\n @for (module of course.modules; track module.id) {\n <div class=\"col-12 md:col-6\">\n <p-panel [toggleable]=\"true\">\n <ng-template pTemplate=\"header\">\n <div class=\"flex align-items-center gap-2 w-full\">\n <i class=\"pi pi-list\"></i>\n <span class=\"font-bold white-space-nowrap\">{{ module.title }}</span>\n <span class=\"text-sm text-color-secondary ml-auto\">{{ module.lessonCount }} lessons</span>\n </div>\n </ng-template>\n <ng-template pTemplate=\"content\">\n <p>{{ module.description }}</p>\n <ul class=\"list-none p-0 m-0 lessons-list\">\n @for (lesson of module.lessons; track lesson.id) {\n <li class=\"flex align-items-center justify-content-between p-2 border-bottom-1 surface-border\">\n <div class=\"flex align-items-center gap-2\">\n @if(lesson.generated) {\n <i class=\"pi pi-play-circle text-green-500\"></i>\n } @else {\n <i class=\"pi pi-lock text-gray-500\"></i>\n }\n <span>{{ lesson.title }}</span>\n </div>\n @if(lesson.generated) {\n <p-button icon=\"pi pi-chevron-right\" [text]=\"true\" [rounded]=\"true\"></p-button>\n } @else {\n <p-button label=\"Generate\" icon=\"pi pi-cog\" [text]=\"true\" size=\"small\"></p-button>\n }\n </li>\n }\n </ul>\n </ng-template>\n </p-panel>\n </div>\n }\n </div>\n </ng-template>\n <ng-template pTemplate=\"footer\">\n <div class=\"flex justify-content-end\">\n <p-button label=\"Generate Pending Lessons\" icon=\"pi pi-cogs\" (onClick)=\"generatePendingLessons()\" [loading]=\"generatingLessons()\"></p-button>\n </div>\n </ng-template>\n </p-card>\n</div>\n} @else {\n<div class=\"flex justify-content-center align-items-center h-full\">\n <p-progressSpinner></p-progressSpinner>\n</div>\n}\n", styles: [":host{display:block;height:100%}.course-detail-container{max-width:960px;margin:auto}.lessons-list li:last-child{border-bottom:none!important}.modules-container{display:flex;flex-direction:row;flex-wrap:nowrap;overflow-x:auto;-webkit-overflow-scrolling:touch;padding-bottom:1rem}.modules-container .p-panel{flex:0 0 48%;max-width:48%}\n"] }]
2663
+ }] });
2664
+
2665
+ class CourseFormComponent extends EntityBaseFormComponent {
2666
+ constructor() {
2667
+ super();
2668
+ this.entityCommunicationService = inject(CourseService);
2669
+ this.loadingBarService = inject(LoadingBarService);
2704
2670
  this.fb = inject(FormBuilder);
2705
- this.router = inject(Router);
2706
- this.toastService = inject(TOAST_ALERTS_TOKEN);
2707
- this.cdr = inject(ChangeDetectorRef);
2671
+ this.languageOptions = getSupportedLanguageOptions('en');
2672
+ this.form = this.fb.group({
2673
+ name: ['', Validators.required],
2674
+ description: [''],
2675
+ image: [{}],
2676
+ targetLang: ['', Validators.required],
2677
+ baseLang: ['', Validators.required],
2678
+ });
2679
+ this.onSave = output();
2708
2680
  this.storageImgSettings = {
2709
2681
  path: `courses`,
2710
2682
  cropSettings: { aspectRatio: AspectType.Square, resolutions: [ResolutionType.MediumLarge], resizeToWidth: 700 },
@@ -2713,46 +2685,49 @@ class CourseFormComponent {
2713
2685
  { key: 'title', type: 'input', props: { label: 'Title', placeholder: 'Title', required: false } },
2714
2686
  { key: 'content', type: 'textarea', props: { label: 'Content', placeholder: 'Content', required: false } },
2715
2687
  ];
2716
- this.courseForm = this.fb.group({
2717
- name: ['', Validators.required],
2718
- description: [''],
2719
- image: [{}],
2688
+ effect(() => {
2689
+ console.log(this.entity());
2720
2690
  });
2721
- this.course = null;
2722
- this.courseId = this.route.snapshot.params['id'];
2723
2691
  }
2724
- async ngOnInit() {
2725
- if (this.courseId) {
2726
- this.course = await this.courseService.getCourse(this.courseId);
2727
- if (this.course) {
2728
- this.courseForm.patchValue(this.course);
2729
- }
2730
- }
2692
+ patchForm(entity) {
2693
+ this.form.patchValue(entity);
2731
2694
  }
2732
2695
  async save() {
2733
- if (this.courseForm.valid) {
2734
- const course = { ...this.course, ...this.courseForm.value };
2735
- const result = await this.courseService.saveCourse(course);
2736
- if (!this.courseId) {
2737
- this.router.navigate([result.id], { relativeTo: this.route });
2696
+ this.toastService.success({ title: 'Course', subtitle: 'Data was saved' });
2697
+ const result = await super.save();
2698
+ if (result) {
2699
+ this.onSave.emit(result);
2700
+ if (this.toastService) {
2701
+ this.toastService.success({ title: 'Course', subtitle: 'Data was saved' });
2738
2702
  }
2739
- this.toastService.success({ title: 'Origen guardado', subtitle: 'El origen ha sido guardado correctamente' });
2740
2703
  }
2704
+ return result;
2741
2705
  }
2742
2706
  handleImageUpload(event) {
2743
- // this.genericForm.patchValue({ image: event });
2744
- alert('Image uploaded');
2707
+ this.form.patchValue({ image: event });
2708
+ }
2709
+ async generateCourse() {
2710
+ const { baseLang, targetLang } = this.form.value;
2711
+ if (baseLang && targetLang) {
2712
+ this.toastService.info({ title: 'Course Generating', subtitle: 'Este proceso puede tomar unos minutos' });
2713
+ this.loadingBarService.showIndeterminate();
2714
+ const course = await this.entityCommunicationService.generateLanguageCourse(baseLang, targetLang, this.entity()?.id);
2715
+ this.form.patchValue(course);
2716
+ if (this.toastService) {
2717
+ this.toastService.success({ title: 'Course Generated', subtitle: 'Course content has been generated successfully.' });
2718
+ }
2719
+ this.loadingBarService.successAndHide();
2720
+ }
2745
2721
  }
2746
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: CourseFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2747
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.4", type: CourseFormComponent, isStandalone: true, selector: "app-source-form", ngImport: i0, template: "<h3>Courses Form</h3>\n\n<div class=\"source-form-card\">\n <p-card [header]=\"courseId ? 'Edit Course' : 'New Course'\">\n <form [formGroup]=\"courseForm\">\n <div style=\"display: flex; gap: 10px\">\n <div class=\"form-field\">\n <label class=\"block\" pTooltip=\"Image should be handle after upload\">Subir imagen</label>\n <img width=\"218px\" src=\"assets/images/face-3.jpg\" />\n <dc-cropper-modal [imgStorageSettings]=\"storageImgSettings\" (imageUploaded)=\"handleImageUpload($event)\"></dc-cropper-modal>\n </div>\n\n <div style=\"width: 100%\">\n <div class=\"form-field\">\n <label for=\"name\" class=\"block\">Name</label>\n <input pInputText id=\"name\" type=\"text\" formControlName=\"name\" placeholder=\"Enter source name\" />\n </div>\n\n <div class=\"form-field\">\n <label for=\"description\" class=\"block\">Description</label>\n <textarea id=\"description\" pTextarea formControlName=\"description\" rows=\"5\" class=\"w-full\" placeholder=\"Enter source content\"> </textarea>\n </div>\n </div>\n </div>\n </form>\n\n <div style=\"display: flex; justify-content: flex-end\">\n <p-button (click)=\"save()\" label=\"Save Course\" [disabled]=\"!courseForm.valid\" icon=\"pi pi-check\" iconPos=\"right\"> </p-button>\n </div>\n </p-card>\n</div>\n", styles: [":host{display:block;padding:1rem}.source-form-card{max-width:800px;margin:0 auto}.form-field{margin-bottom:1.5rem;display:flex;flex-direction:column}.form-field label{margin-bottom:.5rem;font-weight:500;color:#495057}.form-field input,.form-field textarea,.form-field ::ng-deep .p-element{margin-top:.25rem}:host ::ng-deep .p-card .p-card-content>div:last-child{margin-top:1.5rem;display:flex;justify-content:flex-end}:host ::ng-deep .p-card .p-card-header{background-color:#f8f9fa;padding:1rem;border-bottom:1px solid #dee2e6}h3{color:#495057;margin-bottom:1.5rem;text-align:center}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: CardModule }, { kind: "component", type: i3$1.Card, selector: "p-card", inputs: ["header", "subheader", "style", "styleClass"] }, { kind: "ngmodule", type: TextareaModule }, { kind: "directive", type: i3$3.Textarea, selector: "[pTextarea]", inputs: ["autoResize", "variant", "fluid", "pSize"], outputs: ["onResize"] }, { kind: "ngmodule", type: DropdownModule }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: SelectModule }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i3.InputText, selector: "[pInputText]", inputs: ["variant", "fluid", "pSize"] }, { kind: "ngmodule", type: ChipModule }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i6.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }, { kind: "component", type: CropperComponentModal, selector: "dc-cropper-modal", inputs: ["imgStorageSettings", "buttonLabel", "currentStorage"], outputs: ["imageUploaded", "onImageCropped", "onFileSelected"] }, { kind: "ngmodule", type: FormlyModule }, { kind: "ngmodule", type: DialogModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2722
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: CourseFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2723
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.6", type: CourseFormComponent, isStandalone: true, selector: "app-source-form", outputs: { onSave: "onSave" }, usesInheritance: true, ngImport: i0, template: "<h3>Courses Form</h3>\n\n<div class=\"source-form-card\">\n <p-card [header]=\"entityId() ? 'Edit Course' : 'New Course'\">\n <form [formGroup]=\"form\">\n <div class=\"form-field\">\n <label for=\"baseLang\">Base Language <span pTooltip=\"Select the primary language for the conversation\">\u2139\uFE0F</span></label>\n <p-select\n id=\"baseLang\"\n [options]=\"languageOptions\"\n [filter]=\"true\"\n formControlName=\"baseLang\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [placeholder]=\"'Select Language'\"></p-select>\n </div>\n <div class=\"form-field\">\n <label for=\"targetLang\">Target Language <span pTooltip=\"Select the primary language for the conversation\">\u2139\uFE0F</span></label>\n <p-select\n id=\"targetLang\"\n [filter]=\"true\"\n [options]=\"languageOptions\"\n formControlName=\"targetLang\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [placeholder]=\"'Select Language'\"></p-select>\n </div>\n\n <div style=\"display: flex; gap: 10px\">\n <div class=\"form-field\">\n <label class=\"block\" pTooltip=\"Image should be handle after upload\">Subir imagen</label>\n <img width=\"218px\" src=\"assets/images/face-3.jpg\" />\n <dc-cropper-modal [imgStorageSettings]=\"storageImgSettings\" (imageUploaded)=\"handleImageUpload($event)\"></dc-cropper-modal>\n </div>\n\n <div style=\"width: 100%\">\n <div class=\"form-field\">\n <label for=\"name\" class=\"block\">Name</label>\n <input pInputText id=\"name\" type=\"text\" formControlName=\"name\" placeholder=\"Enter source name\" />\n </div>\n\n <div class=\"form-field\">\n <label for=\"description\" class=\"block\">Description</label>\n <textarea id=\"description\" pTextarea formControlName=\"description\" rows=\"5\" class=\"w-full\" placeholder=\"Enter source content\"> </textarea>\n </div>\n </div>\n </div>\n </form>\n\n <div>\n @if (entity()?.modules?.length > 0) {\n <p-message severity=\"info\"\n >El curso ya tiene modulos,\n\n <a routerLink=\"../../details/{{ entity()?.id }}\"> <p-button icon=\"pi pi-eye\" label=\"Ver a los detalles\" [link]=\"true\"></p-button></a>\n </p-message>\n } @else {\n <p-message severity=\"warn\">Este curso no tiene modulos intentega generalos abajo.</p-message>\n }\n </div>\n\n <div style=\"display: flex; justify-content: flex-end\">\n <p-button\n (click)=\"generateCourse()\"\n label=\"Generate Course\"\n [disabled]=\"!form.controls['baseLang'].valid || !form.controls['targetLang'].valid\"\n icon=\"pi pi-sparkles\"\n iconPos=\"right\"\n styleClass=\"p-button-secondary\"></p-button>\n <p-button (click)=\"save()\" label=\"Save Course\" [disabled]=\"!form.valid\" icon=\"pi pi-check\" iconPos=\"right\"> </p-button>\n </div>\n </p-card>\n</div>\n", styles: [":host{display:block;padding:1rem}.source-form-card{max-width:800px;margin:0 auto}.form-field{margin-bottom:1.5rem;display:flex;flex-direction:column}.form-field label{margin-bottom:.5rem;font-weight:500;color:#495057}.form-field input,.form-field textarea,.form-field ::ng-deep .p-element{margin-top:.25rem}:host ::ng-deep .p-card .p-card-content>div:last-child{margin-top:1.5rem;display:flex;justify-content:flex-end}:host ::ng-deep .p-card .p-card-header{background-color:#f8f9fa;padding:1rem;border-bottom:1px solid #dee2e6}h3{color:#495057;margin-bottom:1.5rem;text-align:center}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: CardModule }, { kind: "component", type: i1$2.Card, selector: "p-card", inputs: ["header", "subheader", "style", "styleClass"] }, { kind: "ngmodule", type: TextareaModule }, { kind: "directive", type: i3$3.Textarea, selector: "[pTextarea], [pInputTextarea]", inputs: ["autoResize", "pSize", "variant", "fluid", "invalid"], outputs: ["onResize"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i2.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i3.InputText, selector: "[pInputText]", inputs: ["pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: ChipModule }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i7.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo"] }, { kind: "component", type: CropperComponentModal, selector: "dc-cropper-modal", inputs: ["imgStorageSettings", "buttonLabel", "currentStorage"], outputs: ["imageUploaded", "onImageCropped", "onFileSelected"] }, { kind: "ngmodule", type: FormlyModule }, { kind: "ngmodule", type: DialogModule }, { kind: "ngmodule", type: MessageModule }, { kind: "component", type: i4.Message, selector: "p-message", inputs: ["severity", "text", "escape", "style", "styleClass", "closable", "icon", "closeIcon", "life", "showTransitionOptions", "hideTransitionOptions", "size", "variant"], outputs: ["onClose"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2748
2724
  }
2749
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: CourseFormComponent, decorators: [{
2725
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: CourseFormComponent, decorators: [{
2750
2726
  type: Component,
2751
2727
  args: [{ selector: 'app-source-form', imports: [
2752
2728
  ReactiveFormsModule,
2753
2729
  CardModule,
2754
2730
  TextareaModule,
2755
- DropdownModule,
2756
2731
  ButtonModule,
2757
2732
  SelectModule,
2758
2733
  InputTextModule,
@@ -2762,7 +2737,44 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImpor
2762
2737
  FormlyModule,
2763
2738
  DialogModule,
2764
2739
  CourseListComponent,
2765
- ], changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, template: "<h3>Courses Form</h3>\n\n<div class=\"source-form-card\">\n <p-card [header]=\"courseId ? 'Edit Course' : 'New Course'\">\n <form [formGroup]=\"courseForm\">\n <div style=\"display: flex; gap: 10px\">\n <div class=\"form-field\">\n <label class=\"block\" pTooltip=\"Image should be handle after upload\">Subir imagen</label>\n <img width=\"218px\" src=\"assets/images/face-3.jpg\" />\n <dc-cropper-modal [imgStorageSettings]=\"storageImgSettings\" (imageUploaded)=\"handleImageUpload($event)\"></dc-cropper-modal>\n </div>\n\n <div style=\"width: 100%\">\n <div class=\"form-field\">\n <label for=\"name\" class=\"block\">Name</label>\n <input pInputText id=\"name\" type=\"text\" formControlName=\"name\" placeholder=\"Enter source name\" />\n </div>\n\n <div class=\"form-field\">\n <label for=\"description\" class=\"block\">Description</label>\n <textarea id=\"description\" pTextarea formControlName=\"description\" rows=\"5\" class=\"w-full\" placeholder=\"Enter source content\"> </textarea>\n </div>\n </div>\n </div>\n </form>\n\n <div style=\"display: flex; justify-content: flex-end\">\n <p-button (click)=\"save()\" label=\"Save Course\" [disabled]=\"!courseForm.valid\" icon=\"pi pi-check\" iconPos=\"right\"> </p-button>\n </div>\n </p-card>\n</div>\n", styles: [":host{display:block;padding:1rem}.source-form-card{max-width:800px;margin:0 auto}.form-field{margin-bottom:1.5rem;display:flex;flex-direction:column}.form-field label{margin-bottom:.5rem;font-weight:500;color:#495057}.form-field input,.form-field textarea,.form-field ::ng-deep .p-element{margin-top:.25rem}:host ::ng-deep .p-card .p-card-content>div:last-child{margin-top:1.5rem;display:flex;justify-content:flex-end}:host ::ng-deep .p-card .p-card-header{background-color:#f8f9fa;padding:1rem;border-bottom:1px solid #dee2e6}h3{color:#495057;margin-bottom:1.5rem;text-align:center}\n"] }]
2740
+ MessageModule,
2741
+ RouterLink,
2742
+ ], changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, template: "<h3>Courses Form</h3>\n\n<div class=\"source-form-card\">\n <p-card [header]=\"entityId() ? 'Edit Course' : 'New Course'\">\n <form [formGroup]=\"form\">\n <div class=\"form-field\">\n <label for=\"baseLang\">Base Language <span pTooltip=\"Select the primary language for the conversation\">\u2139\uFE0F</span></label>\n <p-select\n id=\"baseLang\"\n [options]=\"languageOptions\"\n [filter]=\"true\"\n formControlName=\"baseLang\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [placeholder]=\"'Select Language'\"></p-select>\n </div>\n <div class=\"form-field\">\n <label for=\"targetLang\">Target Language <span pTooltip=\"Select the primary language for the conversation\">\u2139\uFE0F</span></label>\n <p-select\n id=\"targetLang\"\n [filter]=\"true\"\n [options]=\"languageOptions\"\n formControlName=\"targetLang\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [placeholder]=\"'Select Language'\"></p-select>\n </div>\n\n <div style=\"display: flex; gap: 10px\">\n <div class=\"form-field\">\n <label class=\"block\" pTooltip=\"Image should be handle after upload\">Subir imagen</label>\n <img width=\"218px\" src=\"assets/images/face-3.jpg\" />\n <dc-cropper-modal [imgStorageSettings]=\"storageImgSettings\" (imageUploaded)=\"handleImageUpload($event)\"></dc-cropper-modal>\n </div>\n\n <div style=\"width: 100%\">\n <div class=\"form-field\">\n <label for=\"name\" class=\"block\">Name</label>\n <input pInputText id=\"name\" type=\"text\" formControlName=\"name\" placeholder=\"Enter source name\" />\n </div>\n\n <div class=\"form-field\">\n <label for=\"description\" class=\"block\">Description</label>\n <textarea id=\"description\" pTextarea formControlName=\"description\" rows=\"5\" class=\"w-full\" placeholder=\"Enter source content\"> </textarea>\n </div>\n </div>\n </div>\n </form>\n\n <div>\n @if (entity()?.modules?.length > 0) {\n <p-message severity=\"info\"\n >El curso ya tiene modulos,\n\n <a routerLink=\"../../details/{{ entity()?.id }}\"> <p-button icon=\"pi pi-eye\" label=\"Ver a los detalles\" [link]=\"true\"></p-button></a>\n </p-message>\n } @else {\n <p-message severity=\"warn\">Este curso no tiene modulos intentega generalos abajo.</p-message>\n }\n </div>\n\n <div style=\"display: flex; justify-content: flex-end\">\n <p-button\n (click)=\"generateCourse()\"\n label=\"Generate Course\"\n [disabled]=\"!form.controls['baseLang'].valid || !form.controls['targetLang'].valid\"\n icon=\"pi pi-sparkles\"\n iconPos=\"right\"\n styleClass=\"p-button-secondary\"></p-button>\n <p-button (click)=\"save()\" label=\"Save Course\" [disabled]=\"!form.valid\" icon=\"pi pi-check\" iconPos=\"right\"> </p-button>\n </div>\n </p-card>\n</div>\n", styles: [":host{display:block;padding:1rem}.source-form-card{max-width:800px;margin:0 auto}.form-field{margin-bottom:1.5rem;display:flex;flex-direction:column}.form-field label{margin-bottom:.5rem;font-weight:500;color:#495057}.form-field input,.form-field textarea,.form-field ::ng-deep .p-element{margin-top:.25rem}:host ::ng-deep .p-card .p-card-content>div:last-child{margin-top:1.5rem;display:flex;justify-content:flex-end}:host ::ng-deep .p-card .p-card-header{background-color:#f8f9fa;padding:1rem;border-bottom:1px solid #dee2e6}h3{color:#495057;margin-bottom:1.5rem;text-align:center}\n"] }]
2743
+ }], ctorParameters: () => [] });
2744
+
2745
+ const COURSES_ROUTES = [
2746
+ {
2747
+ path: '',
2748
+ component: CoursesComponent,
2749
+ children: [
2750
+ {
2751
+ path: '',
2752
+ component: CourseListComponent,
2753
+ },
2754
+ {
2755
+ path: 'details/:id',
2756
+ component: CourseDetailComponent,
2757
+ },
2758
+ {
2759
+ path: 'edit',
2760
+ component: CourseFormComponent,
2761
+ },
2762
+ {
2763
+ path: 'edit/:id',
2764
+ component: CourseFormComponent,
2765
+ },
2766
+ ],
2767
+ },
2768
+ ];
2769
+
2770
+ class CoursesComponent {
2771
+ static { this.routes = COURSES_ROUTES; }
2772
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: CoursesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2773
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.6", type: CoursesComponent, isStandalone: true, selector: "app-courses", ngImport: i0, template: "<router-outlet />\n", styles: [":host{display:block;height:100%}\n"], dependencies: [{ kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1$4.RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2774
+ }
2775
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: CoursesComponent, decorators: [{
2776
+ type: Component,
2777
+ args: [{ selector: 'app-courses', imports: [RouterModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<router-outlet />\n", styles: [":host{display:block;height:100%}\n"] }]
2766
2778
  }] });
2767
2779
 
2768
2780
  /*
@@ -2773,5 +2785,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImpor
2773
2785
  * Generated bundle index. Do not edit.
2774
2786
  */
2775
2787
 
2776
- export { ComponentBuilder, ComponentWithForm, CourseDetailComponent, CourseFormComponent, CourseListComponent, CourseService, CoursesAdminComponent, CoursesComponent, CoursesService, DCLessonEditorComponent, DCLessonFormComponent, DCLessonListComponent, DCLessonRendererComponent, DcLessonCardComponent, DefaultLessonsService, DynamicComponentBuilders, DynamicComponents, DynamicComponentsService, FlagLanguagePipe, LESSONS_TOKEN, LangCodeDescription, LangCodeDescriptionEs, LangDescTranslationPipe, LessonComponentBuilders, LessonComponentEnum, LessonComponents, LessonDynamicComponent, LessonsAbstractService, NOTION_SERVICE_TOKEN, NotionAbstractService, NotionExportType, SelectorBuilderComponent, SelectorComponent, TextWriterBuiderComponent, TextWriterComponent, TranslationSwitcherBuilderComponent, TranslationSwitcherComponent, getLanguageSimpleAgent, getLessonComponentClass, provideLessonsService, provideNotionService };
2788
+ export { ComponentBuilder, ComponentWithForm, CourseDetailComponent, CourseFormComponent, CourseListComponent, CourseService, CoursesAdminComponent, CoursesComponent, CoursesService, DCLessonEditorComponent, DCLessonFormComponent, DCLessonListComponent, DCLessonRendererComponent, DcLessonCardComponent, DefaultLessonsService, DynamicComponentBuilders, DynamicComponents, DynamicComponentsService, FlagLanguagePipe, LESSONS_TOKEN, LangCodeDescription, LangCodeDescriptionEs, LessonComponentBuilders, LessonComponentEnum, LessonComponents, LessonConversationService, LessonDynamicComponent, LessonRendererService, LessonsV2Component, NOTION_SERVICE_TOKEN, NotionAbstractService, NotionExportType, SelectorBuilderComponent, SelectorComponent, TextWriterBuiderComponent, TextWriterComponent, TranslationSwitcherBuilderComponent, TranslationSwitcherComponent, getLanguageSimpleAgent, getLessonComponentClass, provideLessonsService, provideNotionService };
2777
2789
  //# sourceMappingURL=dataclouder-ngx-lessons.mjs.map