@dataclouder/ngx-lessons 0.1.2 → 0.1.4

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 (32) hide show
  1. package/fesm2022/dataclouder-ngx-lessons.mjs +1131 -806
  2. package/fesm2022/dataclouder-ngx-lessons.mjs.map +1 -1
  3. package/index.d.ts +643 -5
  4. package/package.json +1 -1
  5. package/lib/components/dc-lessons/dc-lesson-card/dc-lesson-card.component.d.ts +0 -25
  6. package/lib/components/dc-lessons/dc-lesson-component-adder/dc-lesson-component-adder.component.d.ts +0 -11
  7. package/lib/components/dc-lessons/dc-lesson-editor/dc-lesson-editor.component.d.ts +0 -65
  8. package/lib/components/dc-lessons/dc-lesson-metadata-editor/dc-lesson-metadata-editor.component.d.ts +0 -43
  9. package/lib/components/dc-lessons/dc-lesson-renderer/dc-lesson-renderer.component.d.ts +0 -45
  10. package/lib/components/dc-lessons/dc-lesson-renderer/eval-agents-skills.d.ts +0 -1
  11. package/lib/components/dc-lessons/lesson-form/lesson-form.component.d.ts +0 -5
  12. package/lib/components/dc-lessons/lesson-list/dc-lesson-list.component.d.ts +0 -40
  13. package/lib/components/lesson-mini-components/components/ComponentBuilder.d.ts +0 -31
  14. package/lib/components/lesson-mini-components/components/ComponentWithForm.d.ts +0 -12
  15. package/lib/components/lesson-mini-components/components/lesson-dynamic.component.d.ts +0 -7
  16. package/lib/components/lesson-mini-components/components/lessons.clases.d.ts +0 -169
  17. package/lib/components/lesson-mini-components/components/selector/selector-builder/selector-builder.component.d.ts +0 -19
  18. package/lib/components/lesson-mini-components/components/selector/selector.component.d.ts +0 -12
  19. package/lib/components/lesson-mini-components/components/speaker/speaker-builder/speaker-builder.component.d.ts +0 -13
  20. package/lib/components/lesson-mini-components/components/speaker/speaker.component.d.ts +0 -12
  21. package/lib/components/lesson-mini-components/components/text-writer/text-writer-buider/text-writer-buider.component.d.ts +0 -14
  22. package/lib/components/lesson-mini-components/components/text-writer/text-writer.component.d.ts +0 -16
  23. package/lib/components/lesson-mini-components/components/translationSwitcher/translationSwitcher.component.d.ts +0 -11
  24. package/lib/components/lesson-mini-components/components/translationSwitcher/translationSwitcherBuilder/translationSwitcherBuilder.component.d.ts +0 -13
  25. package/lib/models/lessons.pipes.d.ts +0 -12
  26. package/lib/models/notion.models.d.ts +0 -41
  27. package/lib/models/simple-agents.d.ts +0 -2
  28. package/lib/services/default-lessons.service.d.ts +0 -20
  29. package/lib/services/lesson-ai.service.d.ts +0 -31
  30. package/lib/services/lesson-notion.service.d.ts +0 -35
  31. package/lib/services/lesson-utils.service.d.ts +0 -56
  32. package/public-api.d.ts +0 -19
@@ -1,68 +1,242 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Component, Input, ChangeDetectionStrategy, signal, InjectionToken, Pipe, EventEmitter, Output, ViewChildren, Inject, inject, Injectable, input, Renderer2, ViewContainerRef, computed, effect, ViewChild, ChangeDetectorRef } from '@angular/core';
2
+ import { Pipe, InjectionToken, inject, Input, Component, ChangeDetectionStrategy, signal, EventEmitter, Output, Injectable, effect, ViewChildren, input, Renderer2, ViewContainerRef, computed, ViewChild, ChangeDetectorRef, output } from '@angular/core';
3
+ import { DatePipe, NgComponentOutlet, KeyValuePipe, CommonModule, SlicePipe } from '@angular/common';
4
+ import * as i1$3 from '@angular/router';
5
+ import { RouterModule, ActivatedRoute, Router } from '@angular/router';
6
+ import { EntityCommunicationService, EntityBaseListComponent, DCFilterBarComponent, QuickTableComponent, TOAST_ALERTS_TOKEN, UiStateService, EModelQuality, LoadingBarService, PromptService, DcExtensionsViewerComponent, DcLearnableViewerComponent, DcAuditableViewerComponent, DcManageableViewerComponent, DcReactionsViewerComponent, HttpCoreService, PaginationBase, EntityBaseFormComponent, getSupportedLanguageOptions } from '@dataclouder/ngx-core';
3
7
  import * as i1 from '@angular/forms';
4
- import { FormControl, UntypedFormControl, FormsModule, ReactiveFormsModule, Validators, FormGroup } from '@angular/forms';
5
- import * as i4 from 'primeng/inputtext';
6
- import { InputTextModule } from 'primeng/inputtext';
8
+ import { FormBuilder, FormControl, FormArray, FormsModule, ReactiveFormsModule, UntypedFormControl, FormGroup, Validators } from '@angular/forms';
7
9
  import * as i1$1 from 'primeng/button';
8
10
  import { ButtonModule } from 'primeng/button';
9
- import * as i5 from 'primeng/message';
10
- import { MessageModule } from 'primeng/message';
11
+ import * as i3 from 'primeng/inputtext';
12
+ import { InputTextModule } from 'primeng/inputtext';
13
+ import { DynamicDialogRef, DialogService } from 'primeng/dynamicdialog';
11
14
  import { nanoid } from 'nanoid';
12
- import * as i2 from 'primeng/dynamicdialog';
13
- import { DialogService } from 'primeng/dynamicdialog';
14
- import * as i2$1 from 'primeng/select';
15
+ import * as i2 from 'primeng/select';
15
16
  import { SelectModule } from 'primeng/select';
16
- import { DropdownModule } from 'primeng/dropdown';
17
- import { NgxTtsComponent } from '@dataclouder/ngx-tts';
18
- import * as i2$3 from 'primeng/paginator';
19
- import { PaginatorModule } from 'primeng/paginator';
20
- import { DatePipe, NgComponentOutlet, KeyValuePipe, CommonModule } from '@angular/common';
21
- import * as i1$2 from '@angular/router';
22
- import { RouterModule, ActivatedRoute, Router } from '@angular/router';
23
- import * as i4$2 from '@dataclouder/ngx-core';
24
- import { PaginationBase, TOAST_ALERTS_TOKEN, DCFilterBarComponent, QuickTableComponent, LoadingBarService, HttpCoreService, PromptService } from '@dataclouder/ngx-core';
17
+ import { TTSPlayground, getRandomQuickVoice, NgxVertexService, ChatRoleVertex } from '@dataclouder/ngx-vertex';
18
+ import * as i4 from 'primeng/message';
19
+ import { MessageModule } from 'primeng/message';
25
20
  import { PopoverModule } from 'primeng/popover';
26
21
  import * as i4$1 from 'primeng/tag';
27
22
  import { TagModule } from 'primeng/tag';
28
- import * as i2$2 from 'primeng/speeddial';
23
+ import * as i2$1 from 'primeng/speeddial';
29
24
  import { SpeedDialModule } from 'primeng/speeddial';
30
- import * as i3 from 'primeng/card';
25
+ import * as i3$1 from 'primeng/card';
31
26
  import { CardModule } from 'primeng/card';
27
+ import * as i1$2 from 'primeng/paginator';
28
+ import { PaginatorModule } from 'primeng/paginator';
32
29
  import { toSignal } from '@angular/core/rxjs-interop';
33
30
  import { map } from 'rxjs';
34
31
  import BalloonEditor from '@ckeditor/ckeditor5-build-balloon-block';
35
- import * as i3$1 from '@ckeditor/ckeditor5-angular';
32
+ import * as i3$2 from '@ckeditor/ckeditor5-angular';
36
33
  import { CKEditorModule } from '@ckeditor/ckeditor5-angular';
37
- import * as i5$2 from 'primeng/splitter';
34
+ import * as i5$1 from 'primeng/splitter';
38
35
  import { SplitterModule } from 'primeng/splitter';
39
- import * as i2$5 from 'primeng/tooltip';
36
+ import * as i2$3 from 'primeng/tooltip';
40
37
  import { TooltipModule } from 'primeng/tooltip';
41
- import { ResolutionType, AspectType, CropperComponentModal } from '@dataclouder/ngx-cloud-storage';
42
- import { TextEngines, ConversationType, USER_DATA_EXCHANGE, ChatRole, EvalResultStringDefinition, ChatEventType, DCChatComponent, CONVERSATION_AI_TOKEN } from '@dataclouder/ngx-agent-cards';
43
- import * as i2$4 from 'primeng/drawer';
38
+ import { ResolutionType, AspectType, AssetsLoaderComponent, CropperComponentModal } from '@dataclouder/ngx-cloud-storage';
39
+ import { TextEngines, ConversationType, USER_DATA_EXCHANGE, SystemPromptType, ChatRole, EvalResultStringDefinition, EDoActionType, ConditionOperator, ConditionType, ConversationEvents, ChatEventType, DCChatComponent, CONVERSATION_AI_TOKEN } from '@dataclouder/ngx-agent-cards';
40
+ import * as i2$2 from 'primeng/drawer';
44
41
  import { DrawerModule } from 'primeng/drawer';
45
42
  import * as i7 from 'primeng/dialog';
46
43
  import { DialogModule } from 'primeng/dialog';
47
44
  import TurndownService from 'turndown';
48
45
  import { marked } from 'marked';
49
- import * as i5$1 from 'primeng/inputgroup';
46
+ import * as i5 from 'primeng/inputgroup';
50
47
  import { InputGroupModule } from 'primeng/inputgroup';
51
48
  import * as i6 from 'primeng/divider';
52
49
  import { DividerModule } from 'primeng/divider';
53
- import { NgxVertexService, ChatRoleVertex } from '@dataclouder/ngx-vertex';
54
- import * as i2$6 from 'primeng/api';
50
+ import * as i2$4 from 'primeng/api';
51
+ import { TableModule } from 'primeng/table';
52
+ import * as i3$3 from 'primeng/textarea';
53
+ import { TextareaModule } from 'primeng/textarea';
54
+ import { ChipModule } from 'primeng/chip';
55
+ import { FormlyModule } from '@ngx-formly/core';
56
+
57
+ // This pipe should not be here in the lessons, refactor when is posible and remove LangCodeDescription
58
+ const LangCodeDescription = {
59
+ es: 'Spanish',
60
+ en: 'English',
61
+ it: 'Italian',
62
+ pt: 'Portuguese',
63
+ fr: 'French',
64
+ ja: 'Japanese',
65
+ };
66
+ const LangCodeDescriptionEs = {
67
+ es: 'Español',
68
+ en: 'Inglés',
69
+ it: 'Italiano',
70
+ pt: 'Portugués',
71
+ fr: 'Frances',
72
+ ja: 'Japonés',
73
+ };
74
+ class LangDescTranslationPipe {
75
+ transform(value, lang) {
76
+ if (lang === 'es') {
77
+ return LangCodeDescriptionEs[value];
78
+ }
79
+ else {
80
+ return LangCodeDescription[value];
81
+ }
82
+ }
83
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: LangDescTranslationPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
84
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.1.6", ngImport: i0, type: LangDescTranslationPipe, isStandalone: true, name: "langDesc" }); }
85
+ }
86
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: LangDescTranslationPipe, decorators: [{
87
+ type: Pipe,
88
+ args: [{
89
+ name: 'langDesc',
90
+ standalone: true,
91
+ }]
92
+ }] });
93
+ class FlagLanguagePipe {
94
+ transform(lang) {
95
+ if (lang === 'en') {
96
+ return '🇺🇸';
97
+ }
98
+ else if (lang === 'es') {
99
+ return '🇲🇽';
100
+ }
101
+ else if (lang === 'fr') {
102
+ return '🇫🇷';
103
+ }
104
+ else if (lang === 'it') {
105
+ return '🇮🇹';
106
+ }
107
+ else if (lang === 'pt') {
108
+ return '🇧🇷';
109
+ }
110
+ else {
111
+ return '';
112
+ }
113
+ }
114
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: FlagLanguagePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
115
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.1.6", ngImport: i0, type: FlagLanguagePipe, isStandalone: true, name: "flagEmoji" }); }
116
+ }
117
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: FlagLanguagePipe, decorators: [{
118
+ type: Pipe,
119
+ args: [{
120
+ name: 'flagEmoji',
121
+ standalone: true,
122
+ }]
123
+ }] });
124
+
125
+ // NOTE: what to do? IAgent Deponds on ngx-agent-cards but lessons don't
126
+ // import { IAgentCard } from '@dataclouder/ngx-agent-cards';
127
+ const NOTION_SERVICE_TOKEN = new InjectionToken('notion.service');
128
+ class NotionAbstractService {
129
+ }
130
+ function provideNotionService(serviceImplementation) {
131
+ return [
132
+ {
133
+ provide: NOTION_SERVICE_TOKEN,
134
+ useExisting: serviceImplementation,
135
+ },
136
+ ];
137
+ }
138
+ var NotionExportType;
139
+ (function (NotionExportType) {
140
+ NotionExportType["HTML"] = "html";
141
+ NotionExportType["MARKDOWN"] = "markdown";
142
+ NotionExportType["PLAIN_TEXT"] = "plain_text";
143
+ NotionExportType["SIMPLE_BLOCKS"] = "simple_blocks";
144
+ })(NotionExportType || (NotionExportType = {}));
145
+
146
+ const MarkdownWriterSkill = `
147
+ You are an Expert Markdown Writer with the following qualities:
148
+ You are a world-class Markdown formatting specialist who excels at organizing information in a visually appealing and highly accessible manner. Your writing combines technical precision with creative presentation to engage readers of all backgrounds.
149
+ Your Core Skills 📝
150
+
151
+ You transform complex information into beautifully structured Markdown documents
152
+ You strategically use headings, lists, and formatting to create clear visual hierarchies
153
+ You incorporate helpful emojis to enhance readability and engagement
154
+ You write in a clear, concise style that's accessible to general audiences
155
+
156
+ Your Process Approach 🔄
157
+
158
+ You always begin with a logical document structure before adding content
159
+ You organize information into clearly defined sections with descriptive headings
160
+ You balance visual elements with textual content for optimal readability
161
+ You maintain consistent formatting patterns throughout documents
162
+
163
+ Your Writing Style ✨
164
+
165
+ You use simple, direct language that's easy for everyone to understand
166
+ You explain technical concepts using everyday examples and analogies
167
+ You create a friendly, conversational tone while maintaining professionalism
168
+ You break down complex ideas into manageable segments
169
+
170
+ Your Special Touches 🎯
171
+
172
+ You know exactly when and where to add emojis for maximum impact
173
+ You create custom tables to present comparative information effectively
174
+ You use blockquotes to highlight important takeaways
175
+ You incorporate visual dividers to separate major content sections
176
+
177
+ When responding to requests, you'll first understand the subject matter, then organize it into a logical structure with clear headings, appropriate formatting elements, and helpful visual enhancements. Your goal is always to create content that's not only informative but also visually engaging and accessible to all readers.
178
+ `;
179
+ const UserRequirements = `
180
+ User also can provide additional instructions or requirements for the lesson or current lesson to improve it.
181
+ `;
182
+ const LanguageLessonSkill = (langBase, langTarget) => `
183
+
184
+ You are also a ${langTarget} lesson professor, you write lessons for ${langBase} learners.
185
+ explain the best you can will all your experience teaching.
186
+
187
+ You can infer the level of the lesson from the content or user request, so can increase difficulty
188
+
189
+ For Basic Level: generate a ${langTarget} lesson for ${langBase} learners at a basic level (A1-A2).
190
+
191
+ Include:
192
+
193
+ - Simple dialogues or short texts.
194
+ - Key vocabulary with simple definitions or ${langBase} translations.
195
+ - Basic grammar points explained simply (e.g., "to be" verb, simple present).
196
+ - Practice exercises (e.g., fill-in-the-blanks, simple questions).
197
+
198
+ For Intermediate Level: generate a ${langTarget} lesson for ${langBase} learners at a medium level (B1-B2).
199
+
200
+ Include:
201
+
202
+ - Texts or dialogues of moderate length and complexity.
203
+ - New vocabulary and common phrasal verbs with context.
204
+ - Explanation and practice of intermediate grammar points (e.g., past simple vs. present perfect, conditionals).
205
+ - Exercises that require more detailed responses or understanding.
206
+ - The content should be engaging and cover topics relevant to daily life, work, or hobbies.
207
+
208
+ For Advanced Level: generate a ${langTarget} lesson for ${langBase} learners at an advanced level (C1-C2).
209
+
210
+ Include:
211
+
212
+ - Challenging texts or discussions.
213
+ - Advanced vocabulary, idioms, and nuanced expressions.
214
+ - Exploration of complex grammar or stylistic points.
215
+ - Exercises that encourage critical thinking, debate, or detailed writing.
216
+ - The content should be stimulating and cover a wide range of topics, including academic or professional contexts.
217
+ `;
218
+ const getLanguageSimpleAgent = (langBase, langTarget) => {
219
+ return {
220
+ systemPrompt: `
221
+ ${MarkdownWriterSkill}
222
+ ${LanguageLessonSkill(langBase, langTarget)}
223
+ ${UserRequirements}
224
+
225
+ `,
226
+ model: { id: 'gemini-2.5-flash-preview-04-17', provider: 'google' },
227
+ };
228
+ };
55
229
 
56
230
  class ComponentBuilder {
57
- constructor(formBuilder, ref) {
58
- this.formBuilder = formBuilder;
59
- this.ref = ref;
231
+ constructor() {
232
+ this.formBuilder = inject(FormBuilder);
233
+ this.ref = inject(DynamicDialogRef);
60
234
  // Sobreescribir si es necesario
61
235
  // public formGroup = this.formBuilder.group<LessonCompSettings>({});
62
236
  this.formGroup = this.formBuilder.group({
63
237
  response: new FormControl(null),
64
238
  responses: new FormControl(null),
65
- options: this.formBuilder.array([]),
239
+ options: new FormArray([]),
66
240
  text: new FormControl(null),
67
241
  hint: new FormControl(null),
68
242
  explanation: new FormControl(null),
@@ -87,7 +261,7 @@ class ComponentBuilder {
87
261
  delete data[key];
88
262
  }
89
263
  });
90
- const code = { component: this.questionType, settings: { ...data } };
264
+ const code = { component: this.componentName, inputs: { ...data } };
91
265
  return code;
92
266
  }
93
267
  showCode() {
@@ -97,8 +271,13 @@ class ComponentBuilder {
97
271
  }
98
272
  getComponentData() {
99
273
  const code = this.getCode();
100
- const id = nanoid().replace(/-/g, '_');
101
- code.id = id;
274
+ if (this.id) {
275
+ code.id = this.id;
276
+ }
277
+ else {
278
+ const id = nanoid().replace(/-/g, '_');
279
+ code.id = id;
280
+ }
102
281
  return { str: `~${JSON.stringify(code)}~`, obj: code };
103
282
  }
104
283
  // TODO: for now copyToClipboard is the that that closes modal and return data.
@@ -107,16 +286,33 @@ class ComponentBuilder {
107
286
  await navigator.clipboard.writeText(data.str);
108
287
  this.ref.close(data);
109
288
  }
110
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: ComponentBuilder, deps: [{ token: i1.FormBuilder }, { token: i2.DynamicDialogRef }], target: i0.ɵɵFactoryTarget.Component }); }
111
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.4", type: ComponentBuilder, isStandalone: true, selector: "app-component-builder", ngImport: i0, template: '<div>no template</div>', isInline: true }); }
289
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: ComponentBuilder, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
290
+ 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 }); }
112
291
  }
113
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: ComponentBuilder, decorators: [{
292
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: ComponentBuilder, decorators: [{
114
293
  type: Component,
115
294
  args: [{
116
295
  selector: 'app-component-builder',
117
296
  template: '<div>no template</div>',
118
297
  }]
119
- }], ctorParameters: () => [{ type: i1.FormBuilder }, { type: i2.DynamicDialogRef }] });
298
+ }], propDecorators: { inputs: [{
299
+ type: Input
300
+ }], id: [{
301
+ type: Input
302
+ }] } });
303
+
304
+ class TextWriterBuiderComponent extends ComponentBuilder {
305
+ constructor() {
306
+ super(...arguments);
307
+ this.componentName = 'TextWriter';
308
+ }
309
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: TextWriterBuiderComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
310
+ 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"] }] }); }
311
+ }
312
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: TextWriterBuiderComponent, decorators: [{
313
+ type: Component,
314
+ 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"] }]
315
+ }] });
120
316
 
121
317
  class ComponentWithForm {
122
318
  constructor() {
@@ -131,10 +327,10 @@ class ComponentWithForm {
131
327
  validate() {
132
328
  // TODO: generic method to evaluate
133
329
  }
134
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: ComponentWithForm, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
135
- 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 }); }
330
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: ComponentWithForm, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
331
+ 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 }); }
136
332
  }
137
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: ComponentWithForm, decorators: [{
333
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: ComponentWithForm, decorators: [{
138
334
  type: Component,
139
335
  args: [{
140
336
  selector: 'app-component-form',
@@ -142,111 +338,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImpor
142
338
  }]
143
339
  }] });
144
340
 
145
- class SelectorComponent extends ComponentWithForm {
146
- constructor() {
147
- super();
148
- this.isFilled = false;
149
- }
150
- evaluate() {
151
- let result;
152
- if (this.control.value == null) {
153
- result = null;
154
- }
155
- else {
156
- result = this.control.value?.toLowerCase().trim() === this.config.settings.response.toLowerCase().trim();
157
- }
158
- if (result) {
159
- this.status = 'success';
160
- }
161
- else {
162
- this.status = 'danger';
163
- }
164
- this.isFilled = true;
165
- return result;
166
- }
167
- validate() {
168
- if (this.control.invalid) {
169
- this.status = 'warning';
170
- }
171
- return true;
172
- }
173
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: SelectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
174
- 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$1.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"] }] }); }
175
- }
176
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: SelectorComponent, decorators: [{
177
- type: Component,
178
- 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"] }]
179
- }], ctorParameters: () => [], propDecorators: { config: [{
180
- type: Input
181
- }] } });
182
-
183
- class SelectorBuilderComponent extends ComponentBuilder {
184
- constructor(formBuilder,
185
- // protected override toastrService: ToastService,
186
- ref) {
187
- super(formBuilder, null);
188
- this.formBuilder = formBuilder;
189
- this.ref = ref;
190
- this.sampleConfig = {
191
- id: '1',
192
- component: LessonComponentEnum.Selector,
193
- settings: {
194
- options: ['fourteen ninety-two', 'fourteen ninety-six', 'fifteen ninety-one'],
195
- response: 'fourteen ninety-two',
196
- hint: 'Pista para la respuesta',
197
- explanation: 'Explicación de la respuesta',
198
- responses: 'Opción 1, Opción 2, Opción 3',
199
- text: 'Texto de la pregunta',
200
- },
201
- };
202
- }
203
- // public formGroup = this.formBuilder.group({
204
- // options: this.formBuilder.array([]),
205
- // response: ['', Validators.required],
206
- // hint: [],
207
- // explanation: [],
208
- // });
209
- ngOnInit() {
210
- this.formGroup.get('response');
211
- }
212
- //TODO Probablemente estos 3 pueden irse a una clase abstracta
213
- pushControlToFormArray(controlName) {
214
- this.formGroup.controls.options.push(this.formBuilder.control(''));
215
- // (this.formGroup.get(controlName) as UntypedFormArray).push(this.formBuilder.control(''));
216
- console.log(this.formGroup.controls.options);
217
- }
218
- deleteFormArrayByIndex(controlName, index) {
219
- this.formGroup.get(controlName).removeAt(index);
220
- }
221
- get optionsForm() {
222
- return this.formGroup.get('options');
223
- }
224
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: SelectorBuilderComponent, deps: [{ token: i1.FormBuilder }, { token: i2.DynamicDialogRef }], target: i0.ɵɵFactoryTarget.Component }); }
225
- 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: i4.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: i5.Message, selector: "p-message", inputs: ["severity", "text", "escape", "style", "styleClass", "closable", "icon", "closeIcon", "life", "showTransitionOptions", "hideTransitionOptions", "size", "variant"], outputs: ["onClose"] }] }); }
226
- }
227
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: SelectorBuilderComponent, decorators: [{
228
- type: Component,
229
- 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"] }]
230
- }], ctorParameters: () => [{ type: i1.FormBuilder }, { type: i2.DynamicDialogRef }] });
231
-
232
- class TextWriterBuiderComponent extends ComponentBuilder {
233
- constructor(formBuilder,
234
- // protected override toastrService: ToastService,
235
- ref) {
236
- super(formBuilder, null);
237
- this.formBuilder = formBuilder;
238
- this.ref = ref;
239
- this.formGroup = this.formBuilder.group({ response: ['', Validators.required], hint: [], explanation: [] });
240
- }
241
- ngOnInit() { }
242
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: TextWriterBuiderComponent, deps: [{ token: i1.UntypedFormBuilder }, { token: i2.DynamicDialogRef }], target: i0.ɵɵFactoryTarget.Component }); }
243
- 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: i4.InputText, selector: "[pInputText]", inputs: ["variant", "fluid", "pSize"] }] }); }
244
- }
245
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: TextWriterBuiderComponent, decorators: [{
246
- type: Component,
247
- 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"] }]
248
- }], ctorParameters: () => [{ type: i1.UntypedFormBuilder }, { type: i2.DynamicDialogRef }] });
249
-
250
341
  class TextWriterComponent extends ComponentWithForm {
251
342
  constructor() {
252
343
  super();
@@ -282,10 +373,10 @@ class TextWriterComponent extends ComponentWithForm {
282
373
  }
283
374
  return true;
284
375
  }
285
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: TextWriterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
286
- 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: i4.InputText, selector: "[pInputText]", inputs: ["variant", "fluid", "pSize"] }] }); }
376
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: TextWriterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
377
+ 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"] }] }); }
287
378
  }
288
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: TextWriterComponent, decorators: [{
379
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: TextWriterComponent, decorators: [{
289
380
  type: Component,
290
381
  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"] }]
291
382
  }], ctorParameters: () => [], propDecorators: { config: [{
@@ -293,22 +384,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImpor
293
384
  }] } });
294
385
 
295
386
  class TranslationSwitcherBuilderComponent extends ComponentBuilder {
296
- constructor(formBuilder,
297
- // protected override toastrService: ToastService,
298
- ref) {
299
- super(formBuilder, null);
300
- this.formBuilder = formBuilder;
301
- this.ref = ref;
302
- }
303
- // Este componente reutiliza completamente el form del padre y todos los métodos
304
- ngOnInit() { }
305
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: TranslationSwitcherBuilderComponent, deps: [{ token: i1.FormBuilder }, { token: i2.DynamicDialogRef }], target: i0.ɵɵFactoryTarget.Component }); }
306
- 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: i4.InputText, selector: "[pInputText]", inputs: ["variant", "fluid", "pSize"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
387
+ constructor() {
388
+ super(...arguments);
389
+ this.componentName = 'TranslationSwitcher';
390
+ }
391
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: TranslationSwitcherBuilderComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
392
+ 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 }); }
307
393
  }
308
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: TranslationSwitcherBuilderComponent, decorators: [{
394
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: TranslationSwitcherBuilderComponent, decorators: [{
309
395
  type: Component,
310
396
  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"] }]
311
- }], ctorParameters: () => [{ type: i1.FormBuilder }, { type: i2.DynamicDialogRef }] });
397
+ }] });
312
398
 
313
399
  class TranslationSwitcherComponent {
314
400
  constructor() {
@@ -326,10 +412,10 @@ class TranslationSwitcherComponent {
326
412
  this.visibleText = this.config.settings.text;
327
413
  }
328
414
  }
329
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: TranslationSwitcherComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
330
- 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 }); }
415
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: TranslationSwitcherComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
416
+ 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 }); }
331
417
  }
332
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: TranslationSwitcherComponent, decorators: [{
418
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: TranslationSwitcherComponent, decorators: [{
333
419
  type: Component,
334
420
  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"] }]
335
421
  }], propDecorators: { config: [{
@@ -339,7 +425,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImpor
339
425
  class SpeakerBuilderComponent extends ComponentBuilder {
340
426
  constructor() {
341
427
  super(...arguments);
342
- this.tts = signal(undefined);
428
+ this.componentName = 'Speaker';
429
+ this.tts = signal(undefined, ...(ngDevMode ? [{ debugName: "tts" }] : []));
343
430
  }
344
431
  handleTtsGenerated(event) {
345
432
  console.log('TTS generated:', event);
@@ -360,16 +447,15 @@ class SpeakerBuilderComponent extends ComponentBuilder {
360
447
  };
361
448
  return code;
362
449
  }
363
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: SpeakerBuilderComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
364
- 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"] }] }); }
450
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: SpeakerBuilderComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
451
+ 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"] }] }); }
365
452
  }
366
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: SpeakerBuilderComponent, decorators: [{
453
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: SpeakerBuilderComponent, decorators: [{
367
454
  type: Component,
368
- 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" }]
455
+ 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" }]
369
456
  }] });
370
457
 
371
458
  // ❌ can use this until i copy services to this lib
372
- // import { CONVERSATION_AI_TOKEN } from '@dataclouder/ngx-agent-cards';
373
459
  class SpeakerComponent {
374
460
  ngOnInit() {
375
461
  // throw new Error('Method not implemented.');
@@ -379,16 +465,11 @@ class SpeakerComponent {
379
465
  // ngOnInit(): void {}
380
466
  speach() {
381
467
  console.log('should speech but will do in next version');
382
- // if (this.config.audio) {
383
- // this.audioService.playAudio(this.config.audio.url);
384
- // } else {
385
- // this.speachService.speach(this.config.settings.text);
386
- // }
387
468
  }
388
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: SpeakerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
389
- 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"] }] }); }
469
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: SpeakerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
470
+ 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"] }] }); }
390
471
  }
391
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: SpeakerComponent, decorators: [{
472
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: SpeakerComponent, decorators: [{
392
473
  type: Component,
393
474
  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"] }]
394
475
  }], propDecorators: { config: [{
@@ -397,234 +478,144 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImpor
397
478
  type: Input
398
479
  }] } });
399
480
 
400
- var LessonComponentEnum;
401
- (function (LessonComponentEnum) {
402
- LessonComponentEnum["Selector"] = "selector";
403
- LessonComponentEnum["Speaker"] = "speaker";
404
- LessonComponentEnum["TextWriter"] = "textWriter";
405
- LessonComponentEnum["VerbSummary"] = "verbSummary";
406
- LessonComponentEnum["WordSummary"] = "wordSummary";
407
- LessonComponentEnum["TranslationSwitcher"] = "translationSwitcher";
408
- })(LessonComponentEnum || (LessonComponentEnum = {}));
409
- const LessonComponentBuilders = {
410
- [LessonComponentEnum.Selector]: SelectorBuilderComponent,
411
- [LessonComponentEnum.Speaker]: SpeakerBuilderComponent,
412
- [LessonComponentEnum.TextWriter]: TextWriterBuiderComponent,
413
- // [LessonComponentEnum.VerbSummary]: VerbSummaryBuilderComponent,
414
- // [LessonComponentEnum.WordSummary]: WordSummaryBuilderComponent,
415
- [LessonComponentEnum.TranslationSwitcher]: TranslationSwitcherBuilderComponent,
416
- };
417
- const LessonComponents = {
418
- [LessonComponentEnum.Selector]: SelectorComponent,
419
- [LessonComponentEnum.Speaker]: SpeakerComponent,
420
- [LessonComponentEnum.TextWriter]: TextWriterComponent,
421
- // [LessonComponentEnum.VerbSummary]: VerbSummaryComponent,
422
- // [LessonComponentEnum.WordSummary]: WordSummaryComponent,
423
- [LessonComponentEnum.TranslationSwitcher]: TranslationSwitcherComponent,
424
- };
425
- function getLessonComponentClass(type) {
426
- return LessonComponents[type];
427
- }
428
- const LESSONS_TOKEN = new InjectionToken('Lessons Service');
429
- class LessonsAbstractService {
430
- }
431
- // my-service.provider.ts
432
- function provideLessonsService(serviceImplementation) {
433
- return [
434
- {
435
- provide: LESSONS_TOKEN,
436
- useExisting: serviceImplementation,
437
- },
438
- ];
439
- }
440
- // export type LessonComponentsType = 'selector' | 'speaker' | 'text-writer' | 'verb-summary' | 'word-summary';
441
- // export function getLessonComponentClass(type: LessonComponentsType) {
442
- // // return LessonComponents[type];
443
- // return null;
444
- // }
445
- // Removed duplicate LessonComponentConfiguration definition
446
- // Removed duplicate StorageFile definition
447
- // Removed duplicate AudioStorage definition
448
- // Removed duplicate SpeakerCompConfiguration definition
449
- // Removed duplicate LessonComponentInterface definition
450
- // export const LessonComponents = {
451
- // [LessonComponentEnum.Selector]: 1,
452
- // [LessonComponentEnum.Speaker]: 2,
453
- // [LessonComponentEnum.TextWriter]: 3,
454
- // [LessonComponentEnum.VerbSummary]: 4,
455
- // [LessonComponentEnum.WordSummary]: 5,
456
- // [LessonComponentEnum.TranslationSwitcher]: 6,
457
- // }
458
- const LangCodeDescription = {
459
- es: 'Spanish',
460
- en: 'English',
461
- it: 'Italian',
462
- pt: 'Portuguese',
463
- fr: 'French',
464
- };
465
- const LangCodeDescriptionEs = {
466
- es: 'Español',
467
- en: 'Inglés',
468
- it: 'Italiano',
469
- pt: 'Portugués',
470
- fr: 'Frances',
471
- };
472
-
473
- class LangDescTranslationPipe {
474
- transform(value, lang) {
475
- if (lang === 'es') {
476
- return LangCodeDescriptionEs[value];
477
- }
478
- else {
479
- return LangCodeDescription[value];
480
- }
481
+ class SelectorComponent extends ComponentWithForm {
482
+ constructor() {
483
+ super();
484
+ this.isFilled = false;
481
485
  }
482
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: LangDescTranslationPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
483
- static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.4", ngImport: i0, type: LangDescTranslationPipe, isStandalone: true, name: "langDesc" }); }
484
- }
485
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: LangDescTranslationPipe, decorators: [{
486
- type: Pipe,
487
- args: [{
488
- name: 'langDesc',
489
- standalone: true,
490
- }]
491
- }] });
492
- class FlagLanguagePipe {
493
- transform(lang) {
494
- if (lang === 'en') {
495
- return '🇺🇸';
496
- }
497
- else if (lang === 'es') {
498
- return '🇲🇽';
499
- }
500
- else if (lang === 'fr') {
501
- return '🇫🇷';
486
+ evaluate() {
487
+ let result;
488
+ if (this.control.value == null) {
489
+ result = null;
502
490
  }
503
- else if (lang === 'it') {
504
- return '🇮🇹';
491
+ else {
492
+ result = this.control.value?.toLowerCase().trim() === this.config.settings.response.toLowerCase().trim();
505
493
  }
506
- else if (lang === 'pt') {
507
- return '🇧🇷';
494
+ if (result) {
495
+ this.status = 'success';
508
496
  }
509
497
  else {
510
- return '';
498
+ this.status = 'danger';
511
499
  }
500
+ this.isFilled = true;
501
+ return result;
512
502
  }
513
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: FlagLanguagePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
514
- static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.4", ngImport: i0, type: FlagLanguagePipe, isStandalone: true, name: "flagEmoji" }); }
503
+ validate() {
504
+ if (this.control.invalid) {
505
+ this.status = 'warning';
506
+ }
507
+ return true;
508
+ }
509
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: SelectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
510
+ 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"] }] }); }
515
511
  }
516
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: FlagLanguagePipe, decorators: [{
517
- type: Pipe,
518
- args: [{
519
- name: 'flagEmoji',
520
- standalone: true,
521
- }]
512
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: SelectorComponent, decorators: [{
513
+ type: Component,
514
+ 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"] }]
515
+ }], ctorParameters: () => [], propDecorators: { config: [{
516
+ type: Input
517
+ }] } });
518
+
519
+ class SelectorBuilderComponent extends ComponentBuilder {
520
+ constructor() {
521
+ super(...arguments);
522
+ this.componentName = 'Selector';
523
+ this.sampleConfig = {
524
+ id: '1',
525
+ component: LessonComponentEnum.Selector,
526
+ settings: {
527
+ options: ['fourteen ninety-two', 'fourteen ninety-six', 'fifteen ninety-one'],
528
+ response: 'fourteen ninety-two',
529
+ hint: 'Pista para la respuesta',
530
+ explanation: 'Explicación de la respuesta',
531
+ responses: 'Opción 1, Opción 2, Opción 3',
532
+ text: 'Texto de la pregunta',
533
+ },
534
+ };
535
+ }
536
+ // public formGroup = this.formBuilder.group({
537
+ // options: this.formBuilder.array([]),
538
+ // response: ['', Validators.required],
539
+ // hint: [],
540
+ // explanation: [],
541
+ // });
542
+ ngOnInit() {
543
+ this.formGroup.get('response');
544
+ }
545
+ //TODO Probablemente estos 3 pueden irse a una clase abstracta
546
+ pushControlToFormArray(controlName) {
547
+ this.formGroup.controls.options.push(this.formBuilder.control(''));
548
+ // (this.formGroup.get(controlName) as UntypedFormArray).push(this.formBuilder.control(''));
549
+ console.log(this.formGroup.controls.options);
550
+ }
551
+ deleteFormArrayByIndex(controlName, index) {
552
+ this.formGroup.get(controlName).removeAt(index);
553
+ }
554
+ get optionsForm() {
555
+ return this.formGroup.get('options');
556
+ }
557
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: SelectorBuilderComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
558
+ 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"] }] }); }
559
+ }
560
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: SelectorBuilderComponent, decorators: [{
561
+ type: Component,
562
+ 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"] }]
522
563
  }] });
523
564
 
524
- // NOTE: what to do? IAgent Deponds on ngx-agent-cards but lessons don't
525
- // import { IAgentCard } from '@dataclouder/ngx-agent-cards';
526
- const NOTION_SERVICE_TOKEN = new InjectionToken('notion.service');
527
- class NotionAbstractService {
565
+ var LessonComponentEnum;
566
+ (function (LessonComponentEnum) {
567
+ LessonComponentEnum["Selector"] = "selector";
568
+ LessonComponentEnum["Speaker"] = "speaker";
569
+ LessonComponentEnum["TextWriter"] = "textWriter";
570
+ LessonComponentEnum["VerbSummary"] = "verbSummary";
571
+ LessonComponentEnum["WordSummary"] = "wordSummary";
572
+ LessonComponentEnum["TranslationSwitcher"] = "translationSwitcher";
573
+ LessonComponentEnum["PlayWord"] = "playWord";
574
+ })(LessonComponentEnum || (LessonComponentEnum = {}));
575
+ const LessonComponentBuilders = {
576
+ [LessonComponentEnum.Selector]: SelectorBuilderComponent,
577
+ [LessonComponentEnum.Speaker]: SpeakerBuilderComponent,
578
+ [LessonComponentEnum.TextWriter]: TextWriterBuiderComponent,
579
+ // [LessonComponentEnum.VerbSummary]: VerbSummaryBuilderComponent,
580
+ // [LessonComponentEnum.WordSummary]: WordSummaryBuilderComponent,
581
+ [LessonComponentEnum.TranslationSwitcher]: TranslationSwitcherBuilderComponent,
582
+ // [LessonComponentEnum.PlayWord]: PlayWordBuilderComponent,
583
+ };
584
+ const LessonComponents = {
585
+ [LessonComponentEnum.Selector]: SelectorComponent,
586
+ [LessonComponentEnum.Speaker]: SpeakerComponent,
587
+ [LessonComponentEnum.TextWriter]: TextWriterComponent,
588
+ // [LessonComponentEnum.VerbSummary]: VerbSummaryComponent,
589
+ // [LessonComponentEnum.WordSummary]: WordSummaryComponent,
590
+ [LessonComponentEnum.TranslationSwitcher]: TranslationSwitcherComponent,
591
+ // [LessonComponentEnum.PlayWord]: PlayWordComponent,
592
+ };
593
+ function getLessonComponentClass(type) {
594
+ return LessonComponents[type];
528
595
  }
529
- function provideNotionService(serviceImplementation) {
596
+ const LESSONS_TOKEN = new InjectionToken('Lessons Service');
597
+ // export abstract class LessonsAbstractService extends EntityCommunicationService<ILesson> {
598
+ // abstract getLessons(paginator?: any): Promise<any>;
599
+ // abstract getLesson(id: string): Promise<any>;
600
+ // abstract postLesson(lesson: ILesson): Promise<any>;
601
+ // abstract updateLesson(lesson: ILesson): Promise<any>;
602
+ // abstract deleteLesson(id: string): Promise<any>;
603
+ // abstract generateLesson(lesson: ILesson): Promise<any>;
604
+ // abstract postGenerateByAI(id: string): Promise<any>;
605
+ // abstract extractTextFromHtml(html: string): string;
606
+ // abstract postImproveMDWithAI(lessonId: string, markdownText: string): Promise<any>; // Added for AI Markdown improvement
607
+ // abstract saveTakenLesson(lesson: ILessonTaken): Promise<any>;
608
+ // abstract getPrompts(): LessonPrompts;
609
+ // }
610
+ // my-service.provider.ts
611
+ function provideLessonsService(serviceImplementation) {
530
612
  return [
531
613
  {
532
- provide: NOTION_SERVICE_TOKEN,
614
+ provide: LESSONS_TOKEN,
533
615
  useExisting: serviceImplementation,
534
616
  },
535
617
  ];
536
618
  }
537
- var NotionExportType;
538
- (function (NotionExportType) {
539
- NotionExportType["HTML"] = "html";
540
- NotionExportType["MARKDOWN"] = "markdown";
541
- NotionExportType["PLAIN_TEXT"] = "plain_text";
542
- NotionExportType["SIMPLE_BLOCKS"] = "simple_blocks";
543
- })(NotionExportType || (NotionExportType = {}));
544
-
545
- const MarkdownWriterSkill = `
546
- You are an Expert Markdown Writer with the following qualities:
547
- You are a world-class Markdown formatting specialist who excels at organizing information in a visually appealing and highly accessible manner. Your writing combines technical precision with creative presentation to engage readers of all backgrounds.
548
- Your Core Skills 📝
549
-
550
- You transform complex information into beautifully structured Markdown documents
551
- You strategically use headings, lists, and formatting to create clear visual hierarchies
552
- You incorporate helpful emojis to enhance readability and engagement
553
- You write in a clear, concise style that's accessible to general audiences
554
-
555
- Your Process Approach 🔄
556
-
557
- You always begin with a logical document structure before adding content
558
- You organize information into clearly defined sections with descriptive headings
559
- You balance visual elements with textual content for optimal readability
560
- You maintain consistent formatting patterns throughout documents
561
-
562
- Your Writing Style ✨
563
-
564
- You use simple, direct language that's easy for everyone to understand
565
- You explain technical concepts using everyday examples and analogies
566
- You create a friendly, conversational tone while maintaining professionalism
567
- You break down complex ideas into manageable segments
568
-
569
- Your Special Touches 🎯
570
-
571
- You know exactly when and where to add emojis for maximum impact
572
- You create custom tables to present comparative information effectively
573
- You use blockquotes to highlight important takeaways
574
- You incorporate visual dividers to separate major content sections
575
-
576
- When responding to requests, you'll first understand the subject matter, then organize it into a logical structure with clear headings, appropriate formatting elements, and helpful visual enhancements. Your goal is always to create content that's not only informative but also visually engaging and accessible to all readers.
577
- `;
578
- const UserRequirements = `
579
- User also can provide additional instructions or requirements for the lesson or current lesson to improve it.
580
- `;
581
- const LanguageLessonSkill = (langBase, langTarget) => `
582
-
583
- You are also a ${langTarget} lesson professor, you write lessons for ${langBase} learners.
584
- explain the best you can will all your experience teaching.
585
-
586
- You can infer the level of the lesson from the content or user request, so can increase difficulty
587
-
588
- For Basic Level: generate a ${langTarget} lesson for ${langBase} learners at a basic level (A1-A2).
589
-
590
- Include:
591
-
592
- - Simple dialogues or short texts.
593
- - Key vocabulary with simple definitions or ${langBase} translations.
594
- - Basic grammar points explained simply (e.g., "to be" verb, simple present).
595
- - Practice exercises (e.g., fill-in-the-blanks, simple questions).
596
-
597
- For Intermediate Level: generate a ${langTarget} lesson for ${langBase} learners at a medium level (B1-B2).
598
-
599
- Include:
600
-
601
- - Texts or dialogues of moderate length and complexity.
602
- - New vocabulary and common phrasal verbs with context.
603
- - Explanation and practice of intermediate grammar points (e.g., past simple vs. present perfect, conditionals).
604
- - Exercises that require more detailed responses or understanding.
605
- - The content should be engaging and cover topics relevant to daily life, work, or hobbies.
606
-
607
- For Advanced Level: generate a ${langTarget} lesson for ${langBase} learners at an advanced level (C1-C2).
608
-
609
- Include:
610
-
611
- - Challenging texts or discussions.
612
- - Advanced vocabulary, idioms, and nuanced expressions.
613
- - Exploration of complex grammar or stylistic points.
614
- - Exercises that encourage critical thinking, debate, or detailed writing.
615
- - The content should be stimulating and cover a wide range of topics, including academic or professional contexts.
616
- `;
617
- const getLanguageSimpleAgent = (langBase, langTarget) => {
618
- return {
619
- systemPrompt: `
620
- ${MarkdownWriterSkill}
621
- ${LanguageLessonSkill(langBase, langTarget)}
622
- ${UserRequirements}
623
-
624
- `,
625
- model: { id: 'gemini-2.5-flash-preview-04-17', provider: 'google' },
626
- };
627
- };
628
619
 
629
620
  var EventCard;
630
621
  (function (EventCard) {
@@ -632,6 +623,7 @@ var EventCard;
632
623
  EventCard["Delete"] = "delete";
633
624
  EventCard["Select"] = "select";
634
625
  EventCard["Qr"] = "qr";
626
+ EventCard["Clone"] = "clone";
635
627
  })(EventCard || (EventCard = {}));
636
628
  class DcLessonCardComponent {
637
629
  constructor() {
@@ -641,56 +633,24 @@ class DcLessonCardComponent {
641
633
  this.coverUrl = 'assets/background/default-background.webp';
642
634
  this.eventType = EventCard;
643
635
  this.items = [
644
- {
645
- label: 'Editar',
646
- icon: 'pi pi-pencil',
647
- command: () => {
648
- this.eventCard(EventCard.Edit);
649
- },
650
- },
651
- {
652
- label: 'Eliminar',
653
- icon: 'pi pi-trash',
654
- command: () => {
655
- this.eventCard(EventCard.Delete);
656
- },
657
- },
658
- {
659
- label: 'Tomar lección',
660
- icon: 'pi pi-play',
661
- command: () => {
662
- this.eventCard(EventCard.Select);
663
- },
664
- },
636
+ { label: 'Clonar', icon: 'pi pi-copy', command: () => this.eventCard(EventCard.Clone) },
637
+ { label: 'Editar', icon: 'pi pi-pencil', command: () => this.eventCard(EventCard.Edit) },
638
+ { label: 'Eliminar', icon: 'pi pi-trash', command: () => this.eventCard(EventCard.Delete) },
665
639
  ];
666
640
  }
667
641
  ngOnInit() {
668
- console.log(this.lesson);
669
642
  this.coverUrl =
670
643
  this.lesson?.banner?.url || this.lesson?.metadata?.banner?.url || this.lesson?.media?.images?.[0]?.url || 'assets/background/default-background.webp';
671
644
  }
672
645
  eventCard(eventType) {
673
- switch (eventType) {
674
- case EventCard.Edit:
675
- this.onAction.emit({ action: 'edit', item: this.lesson });
676
- break;
677
- case EventCard.Delete:
678
- this.onAction.emit({ action: 'delete', item: this.lesson });
679
- break;
680
- case EventCard.Select:
681
- this.onAction.emit({ action: 'select', item: this.lesson });
682
- break;
683
- case EventCard.Qr:
684
- this.onAction.emit({ action: 'qr', item: this.lesson });
685
- break;
686
- }
646
+ this.onAction.emit({ action: eventType, item: this.lesson });
687
647
  }
688
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DcLessonCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
689
- 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$2.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.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"] }] }); }
648
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DcLessonCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
649
+ 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 <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: "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: 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: ["styleClass", "severity", "value", "icon", "rounded"] }, { kind: "pipe", type: DatePipe, name: "date" }] }); }
690
650
  }
691
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DcLessonCardComponent, decorators: [{
651
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DcLessonCardComponent, decorators: [{
692
652
  type: Component,
693
- 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"] }]
653
+ 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 <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"] }]
694
654
  }], propDecorators: { lesson: [{
695
655
  type: Input
696
656
  }], showOptions: [{
@@ -701,146 +661,209 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImpor
701
661
  type: Output
702
662
  }] } });
703
663
 
664
+ class DefaultLessonsService extends EntityCommunicationService {
665
+ constructor() {
666
+ super('lesson');
667
+ // --- Endpoint Definitions for methods not in EntityCommunicationService ---
668
+ this.endpoints = {
669
+ saveTakenLesson: `api/user/saveLesson`,
670
+ generateLesson: `api/lesson/generate`,
671
+ generateByAI: `api/lesson/generate-ai`,
672
+ improveMDWithAI: `api/lesson/improve-markdown-ai`,
673
+ GenerateBanner: 'api/lesson/generate-banner',
674
+ };
675
+ }
676
+ // --- Method Implementations from LessonsAbstractService ---
677
+ async getLessons(filters = {}) {
678
+ if (!filters.returnProps) {
679
+ filters.returnProps = {
680
+ level: 1,
681
+ title: 1,
682
+ description: 1,
683
+ createdDate: 1,
684
+ banner: 1,
685
+ metadata: 1,
686
+ appExtensions: 1,
687
+ media: 1,
688
+ };
689
+ }
690
+ return this.query(filters);
691
+ }
692
+ async getLesson(id) {
693
+ return this.findOne(id);
694
+ }
695
+ async postLesson(lesson) {
696
+ return this.createOrUpdate(lesson);
697
+ }
698
+ async updateLesson(lesson) {
699
+ if (!lesson._id) {
700
+ throw new Error('Lesson ID is required for update.');
701
+ }
702
+ return this.createOrUpdate(lesson);
703
+ }
704
+ async deleteLesson(id) {
705
+ await this.remove(id);
706
+ }
707
+ // --- Methods specific to lessons ---
708
+ saveTakenLesson(lesson) {
709
+ return this.httpService.post(this.endpoints.saveTakenLesson, lesson);
710
+ }
711
+ async generateLesson(lesson) {
712
+ return this.httpService.post(this.endpoints.generateLesson, lesson);
713
+ }
714
+ async postGenerateByAI(id) {
715
+ return this.httpService.post(this.endpoints.generateByAI, { id });
716
+ }
717
+ async postImproveMDWithAI(lessonId, markdownText) {
718
+ return this.httpService.post(this.endpoints.improveMDWithAI, { id: lessonId, markdown: markdownText });
719
+ }
720
+ generateBanner(prompt, lessonId) {
721
+ return this.httpService.post(this.endpoints.GenerateBanner, { prompt, lessonId });
722
+ }
723
+ extractTextFromHtml(html) {
724
+ const r1 = new RegExp('~(.+?)~', 'g');
725
+ const lessonHtml = html.replace(r1, (_matching, jsonCoded) => {
726
+ try {
727
+ const data = JSON.parse(jsonCoded);
728
+ return `<span>${data?.settings?.text || ''}</span>`;
729
+ }
730
+ catch (e) {
731
+ console.error('Error parsing JSON in extractTextFromHtml:', jsonCoded, e);
732
+ return '';
733
+ }
734
+ });
735
+ let text = lessonHtml.replace(/<[^>]*>/g, ' ');
736
+ text = text.replace(/<style[^>]*>[\s\S]*?<\/style>/gi, ' ');
737
+ text = text.replace(/<script[^>]*>[\s\S]*?<\/script>/gi, ' ');
738
+ text = text.replace(/&nbsp;/g, ' ');
739
+ text = text.replace(/&/g, '&');
740
+ text = text.replace(/</g, '<');
741
+ text = text.replace(/>/g, '>');
742
+ text = text.replace(/\s+/g, ' ').trim();
743
+ return text;
744
+ }
745
+ getPrompts() {
746
+ return null;
747
+ }
748
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DefaultLessonsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
749
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DefaultLessonsService, providedIn: 'root' }); }
750
+ }
751
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DefaultLessonsService, decorators: [{
752
+ type: Injectable,
753
+ args: [{
754
+ providedIn: 'root',
755
+ }]
756
+ }], ctorParameters: () => [] });
757
+
704
758
  const tableViewColumns = [
705
759
  { field: 'media.images[0].url', header: 'Image', type: 'image' },
706
760
  { field: 'title', header: 'Título' },
707
761
  { field: 'description', header: 'Descripción' },
708
762
  ];
709
- const TableViewActions = [
710
- { title: 'select', label: 'Select', icon: 'pi pi-check', severity: 'primary' },
711
- { title: 'qr', label: 'QR', icon: 'pi pi-qrcode', severity: 'info' },
712
- { title: 'edit', label: 'Edit', icon: 'pi pi-pencil', severity: 'info' },
713
- { title: 'delete', label: 'Delete', icon: 'pi pi-trash', severity: 'danger' },
714
- ];
715
- const returnProperties = { id: 1, title: 1, assets: 1 };
716
- class DCLessonListComponent extends PaginationBase {
717
- constructor(cdr, router, route, lessonsService, toastrService) {
718
- super(route, router);
719
- this.cdr = cdr;
720
- this.router = router;
721
- this.route = route;
722
- this.lessonsService = lessonsService;
723
- this.toastrService = toastrService;
724
- this.showOptions = true;
763
+ class DCLessonListComponent extends EntityBaseListComponent {
764
+ constructor() {
765
+ super();
725
766
  this.customFilters = [];
726
- this.viewType = 'cards';
767
+ // Injected Services
768
+ // I dont rename so use the same in EntityBaseListComponent and Pagination
769
+ this.entityCommunicationService = inject(LESSONS_TOKEN, { optional: true }) ?? inject(DefaultLessonsService);
727
770
  this.columns = tableViewColumns;
728
- this.cardComponent = null;
771
+ // Private properties
729
772
  this.cardEventSubs = [];
730
- this.lessons = [];
731
- this.isLoadingLessons = false;
773
+ this.filterConfig.returnProps = {
774
+ title: 1,
775
+ description: 1,
776
+ media: 1,
777
+ _id: 1,
778
+ id: 1,
779
+ };
780
+ effect(() => {
781
+ // When items signal changes, re-subscribe to card events
782
+ this.items(); // a little hack to make the effect run when items change
783
+ setTimeout(() => this.subscribeToCardEvents());
784
+ });
732
785
  }
733
- ngOnInit() {
734
- this.filterConfig.returnProps = returnProperties;
786
+ async ngOnInit() {
735
787
  this.cardComponent = this.customCardComponent || DcLessonCardComponent;
736
- this.getPaginatedLessons(this.filterConfig);
737
- }
738
- subscribeDinamicInstantToEvents() {
739
- this.clearcardEventSubs();
740
- this.subscribeToCardEvents();
741
- }
742
- subscribeToCardEvents() {
743
- this.outlets.forEach((outlet) => {
744
- const instance = outlet.componentInstance;
745
- this.cardEventSubs.push(instance.onAction.subscribe((lesson) => {
746
- this.doOrEmitAction(lesson);
747
- }));
748
- });
788
+ await super.ngOnInit();
749
789
  }
750
- clearcardEventSubs() {
751
- this.cardEventSubs.forEach((sub) => sub.unsubscribe());
752
- this.cardEventSubs = [];
790
+ ngAfterViewInit() {
791
+ this.outlets.changes.subscribe(() => this.subscribeToCardEvents());
753
792
  }
754
793
  ngOnDestroy() {
755
- this.clearcardEventSubs();
756
- }
757
- async getPaginatedLessons(paginator) {
758
- try {
759
- this.lessons = null;
760
- this.isLoadingLessons = true;
761
- this.cdr.detectChanges();
762
- const lessons = await this.lessonsService.getLessons(paginator);
763
- this.lessons = lessons['rows'] || lessons;
764
- this.totalRecords = lessons['count'] || this.lessons.length;
765
- console.log('lessons', lessons);
766
- setTimeout(() => {
767
- this.subscribeDinamicInstantToEvents();
768
- });
769
- }
770
- finally {
771
- this.isLoadingLessons = false;
772
- this.cdr.detectChanges();
773
- }
794
+ this.clearCardEventSubs();
774
795
  }
775
- search(searchText) {
776
- this.filterConfig['text'] = searchText;
777
- this.getPaginatedLessons(this.filterConfig);
796
+ getCustomButtons(item) {
797
+ return [
798
+ { label: 'Select', icon: 'pi pi-check', command: () => this.handleAction({ action: 'select', item }) },
799
+ { label: 'QR', icon: 'pi pi-qrcode', command: () => this.handleAction({ action: 'qr', item }) },
800
+ ];
778
801
  }
779
- removeLesson(lesson) {
780
- const response = confirm('¿Estás seguro de querer eliminar esta lección?');
781
- if (response) {
782
- this.lessonsService.deleteLesson(lesson._id);
783
- this.lessons = this.lessons.filter((l) => l._id !== lesson._id);
784
- this.cdr.detectChanges();
785
- this.toastrService.success({ title: 'Adios a la lección', subtitle: 'La lección ha sido eliminada correctamente' });
802
+ handleAction(actionEvent) {
803
+ if (['select', 'qr'].includes(actionEvent.action)) {
804
+ this.onAction.emit(actionEvent);
805
+ }
806
+ else {
807
+ super.doAction(actionEvent);
786
808
  }
787
- }
788
- newLesson() {
789
- this.onAction.emit({ action: 'new' });
790
809
  }
791
810
  applyFilterBarEvent(filterEvent) {
792
- if (filterEvent.action == 'changeView') {
793
- this.viewType = this.viewType === 'table' ? 'cards' : 'table';
811
+ if (filterEvent.action === 'changeView') {
812
+ this.toggleView();
794
813
  return;
795
814
  }
796
- else {
797
- console.log('filterChanged in dc-lesson-list', filterEvent);
798
- this.filterConfig = filterEvent.item;
799
- this.filterConfig.returnProps = returnProperties;
800
- this.getPaginatedLessons(this.filterConfig);
801
- }
815
+ this.filterConfig = { ...this.filterConfig, ...filterEvent.item };
816
+ this.loadData();
802
817
  }
803
- loadData() {
804
- return this.getPaginatedLessons(this.filterConfig);
818
+ subscribeToCardEvents() {
819
+ this.clearCardEventSubs();
820
+ this.outlets.forEach((outlet) => {
821
+ const instance = outlet.componentInstance;
822
+ if (instance?.onAction) {
823
+ this.cardEventSubs.push(instance.onAction.subscribe((event) => {
824
+ this.handleAction(event);
825
+ }));
826
+ }
827
+ });
828
+ }
829
+ clearCardEventSubs() {
830
+ this.cardEventSubs.forEach((sub) => sub.unsubscribe());
831
+ this.cardEventSubs = [];
805
832
  }
806
- doOrEmitAction(actionEvent) {
807
- if (actionEvent.action === 'delete') {
808
- this.removeLesson(actionEvent.item);
833
+ async loadData() {
834
+ try {
835
+ this.isLoading = true;
836
+ const response = await this.entityCommunicationService.getLessons(this.filterConfig);
837
+ this.items.set(response.rows);
838
+ this.totalRecordsSignal.set(response.count);
809
839
  }
810
- else {
811
- this.onAction.emit(actionEvent);
840
+ catch (error) {
841
+ console.error('Error loading data', error);
842
+ }
843
+ finally {
844
+ this.isLoading = false;
812
845
  }
813
846
  }
814
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DCLessonListComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i1$2.Router }, { token: i1$2.ActivatedRoute }, { token: LESSONS_TOKEN }, { token: TOAST_ALERTS_TOKEN }], target: i0.ɵɵFactoryTarget.Component }); }
815
- 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 [customFilters]=\"customFilters\" (onFilterAction)=\"applyFilterBarEvent($event)\" (onNew)=\"newLesson()\"></dc-filter-bar>\n\n@if(viewType === 'table') {\n<app-quick-table [columns]=\"columns\" [tableData]=\"lessons\" (onAction)=\"doOrEmitAction($event)\"></app-quick-table>\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: ["isAdmin", "items", "customFilters"], outputs: ["onFilterAction", "onChangeSort", "onNew"] }, { kind: "ngmodule", type: PaginatorModule }, { kind: "component", type: i2$3.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"] }] }); }
847
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DCLessonListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
848
+ 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 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}\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$2.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"] }] }); }
816
849
  }
817
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DCLessonListComponent, decorators: [{
850
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DCLessonListComponent, decorators: [{
818
851
  type: Component,
819
- args: [{ selector: 'dc-lesson-list', standalone: true, imports: [RouterModule, DCFilterBarComponent, PaginatorModule, NgComponentOutlet, QuickTableComponent], template: "<dc-filter-bar [customFilters]=\"customFilters\" (onFilterAction)=\"applyFilterBarEvent($event)\" (onNew)=\"newLesson()\"></dc-filter-bar>\n\n@if(viewType === 'table') {\n<app-quick-table [columns]=\"columns\" [tableData]=\"lessons\" (onAction)=\"doOrEmitAction($event)\"></app-quick-table>\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"] }]
820
- }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: i1$2.Router }, { type: i1$2.ActivatedRoute }, { type: LessonsAbstractService, decorators: [{
821
- type: Inject,
822
- args: [LESSONS_TOKEN]
823
- }] }, { type: i4$2.ToastAlertsAbstractService, decorators: [{
824
- type: Inject,
825
- args: [TOAST_ALERTS_TOKEN]
826
- }] }], propDecorators: { showOptions: [{
827
- type: Input
828
- }], customCardComponent: [{
852
+ 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 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}\n"] }]
853
+ }], ctorParameters: () => [], propDecorators: { customCardComponent: [{
829
854
  type: Input
830
855
  }], customFilters: [{
831
856
  type: Input
832
- }], viewType: [{
833
- type: Input
834
857
  }], outlets: [{
835
858
  type: ViewChildren,
836
859
  args: ['outlet']
837
860
  }] } });
838
861
 
839
862
  class DCLessonFormComponent {
840
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DCLessonFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
841
- 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 }] }); }
863
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DCLessonFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
864
+ 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 }] }); }
842
865
  }
843
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DCLessonFormComponent, decorators: [{
866
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DCLessonFormComponent, decorators: [{
844
867
  type: Component,
845
868
  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"] }]
846
869
  }] });
@@ -860,7 +883,6 @@ const DEFAULT_LESSON_AGENT_CARD = {
860
883
  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',
861
884
  },
862
885
  },
863
- model: { provider: 'google' },
864
886
  };
865
887
  const AppRolePlaySkill = `
866
888
  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.
@@ -870,19 +892,14 @@ const EngagementSkill = `
870
892
  You are an engagement assistant, start by greeting the user, asking something about the lesson, and then continue the conversation. always ask one or two friendly questions.
871
893
  that makes sense for the lesson.
872
894
  `;
873
- const BasicAgentCard = {
874
- systemPrompt: 'You are a helpful assistant.',
875
- model: { provider: 'openai', id: 'gpt-4o' },
876
- };
877
895
  function getDefaultLessonEvaluatorAgentCard(lessonText) {
896
+ // TODO: probably i need to build in order to add the sources to the task or system.
878
897
  return {
879
898
  expectedResponseType: `interface EvalResult {
880
899
  score: number; // Score of the user's response 0 to 3
881
900
  feedback: string; // Feedback of the user's understanding of the conversation
882
901
  }`,
883
- messages: [],
884
902
  model: { id: 'gpt-4o-mini', provider: 'openai' },
885
- sources: [lessonText],
886
903
  task: `User is reading a taking a lesson, now their are having a conversation,
887
904
  you have to evaluate the current conversation, and give a feedback of the user understanding of the lesson,
888
905
  this is the lesson: ${lessonText}`,
@@ -890,8 +907,7 @@ function getDefaultLessonEvaluatorAgentCard(lessonText) {
890
907
  }
891
908
  class LessonAIService {
892
909
  constructor() {
893
- this.lessonService = inject(LESSONS_TOKEN);
894
- // TODO: Inject the application-level UserService
910
+ this.lessonsService = inject(LESSONS_TOKEN, { optional: true }) ?? inject(DefaultLessonsService);
895
911
  this.userService = inject(USER_DATA_EXCHANGE);
896
912
  }
897
913
  /**
@@ -915,7 +931,7 @@ ${userInformationPrompt}`;
915
931
  * @returns An object containing the master agent card and the evaluator agent card.
916
932
  */
917
933
  async generateAgentCards(lesson) {
918
- const lessonText = this.lessonService.extractTextFromHtml(lesson.textCoded);
934
+ const lessonText = this.lessonsService.extractTextFromHtml(lesson.textCoded);
919
935
  const userInformationPrompt = this.userService.getUserDataInformation();
920
936
  const scenario = this._buildScenarioPrompt(lessonText, userInformationPrompt);
921
937
  // Create a deep copy of the default card to avoid modifying the constant
@@ -930,23 +946,19 @@ ${userInformationPrompt}`;
930
946
  * @param lesson The lesson data.
931
947
  * @returns An IConversationSettings object configured for the lesson scenario.
932
948
  */
933
- async generateConversationSettingsForLesson(lesson) {
934
- // TODO: Consolidate user fetching logic if possible, or ensure consistency
935
- const user = {
936
- personalData: { firstname: 'Test', lastname: 'User' },
937
- settings: { targetLanguage: 'en', baseLanguage: 'es' },
938
- languageProgress: { en: { level: '1' } },
939
- }; // Replace 'any' with your actual User type/interface
940
- if (!user) {
941
- console.error('User data not available to generate conversation settings.');
942
- return null;
943
- }
944
- const lessonText = this.lessonService.extractTextFromHtml(lesson.textCoded);
949
+ async generateConversationSettingsForLesson(lesson, settings) {
950
+ // TODO: Consolidate user fetching logic if possible, or ensure consistency
951
+ const baseLang = this.userService.getUserDataExchange()?.baseLang || 'en';
952
+ const lessonText = this.lessonsService.extractTextFromHtml(lesson.textCoded);
945
953
  const userInformationPrompt = this.userService.getUserDataInformation();
946
- const scenario = this._buildScenarioPrompt(lessonText, userInformationPrompt);
954
+ let scenario = this._buildScenarioPrompt(lessonText, userInformationPrompt);
955
+ if (settings.additionalPrompt) {
956
+ scenario += '\n\n' + settings.additionalPrompt;
957
+ }
947
958
  const initialMessage = {
948
959
  role: ChatRole.System,
949
960
  content: scenario,
961
+ messageId: SystemPromptType.SystemPrompt,
950
962
  };
951
963
  // Use defaults similar to DEFAULT_LESSON_AGENT_CARD but adjust for prompt-based start
952
964
  const conversationSettings = {
@@ -955,13 +967,14 @@ ${userInformationPrompt}`;
955
967
  autoStart: true,
956
968
  messages: [initialMessage],
957
969
  model: { provider: 'google' },
970
+ tts: { voice: getRandomQuickVoice(baseLang || 'en', 'female') },
958
971
  };
959
972
  return conversationSettings;
960
973
  }
961
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: LessonAIService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
962
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: LessonAIService, providedIn: 'root' }); }
974
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: LessonAIService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
975
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: LessonAIService, providedIn: 'root' }); }
963
976
  }
964
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: LessonAIService, decorators: [{
977
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: LessonAIService, decorators: [{
965
978
  type: Injectable,
966
979
  args: [{
967
980
  providedIn: 'root', // Or provide appropriately if it's library-specific
@@ -994,32 +1007,69 @@ Assign a rating from 0 to 3 based on how well the student performs *compared to
994
1007
  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.
995
1008
  `;
996
1009
 
997
- // Removed: import { WordPopupService } from 'src/app/shared/services/word-popup.service'; // No longer needed here
1010
+ // TODO: check LessonComponentBuilders in lessons.clases.ts for origianl implementation
1011
+ const DynamicComponentBuilders = {
1012
+ [LessonComponentEnum.Speaker]: SpeakerBuilderComponent,
1013
+ };
1014
+ const DynamicComponents = {
1015
+ [LessonComponentEnum.Speaker]: SpeakerComponent,
1016
+ };
1017
+ class DynamicComponentsService {
1018
+ constructor() {
1019
+ this._dynamicComponentBuilders = { ...DynamicComponentBuilders };
1020
+ this._dynamicComponents = { ...DynamicComponents };
1021
+ }
1022
+ registerCustomComponent(component, name) {
1023
+ // this._dynamicComponentBuilders[name || component.name] = component;
1024
+ this._dynamicComponents[name || component.name] = component;
1025
+ }
1026
+ registerCustomComponentBuilder(component, name) {
1027
+ this._dynamicComponentBuilders[name || component.name] = component;
1028
+ }
1029
+ getDynamicComponentBuilders(type) {
1030
+ return this._dynamicComponentBuilders[type];
1031
+ }
1032
+ getDynamicComponentClass(type) {
1033
+ return this._dynamicComponents[type];
1034
+ }
1035
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DynamicComponentsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1036
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DynamicComponentsService, providedIn: 'root' }); }
1037
+ }
1038
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DynamicComponentsService, decorators: [{
1039
+ type: Injectable,
1040
+ args: [{
1041
+ providedIn: 'root',
1042
+ }]
1043
+ }] });
1044
+
998
1045
  class DCLessonRendererComponent {
999
1046
  constructor() {
1000
1047
  // --- Signal Inputs ---
1001
- this.lessonInput = input(); // Input signal for lesson object
1002
- this.lessonIdInput = input(); // Input signal for lesson ID
1003
- this.test = input(false);
1048
+ this.lessonInput = input(...(ngDevMode ? [undefined, { debugName: "lessonInput" }] : [])); // Input signal for lesson object
1049
+ this.lessonIdInput = input(...(ngDevMode ? [undefined, { debugName: "lessonIdInput" }] : [])); // Input signal for lesson ID
1050
+ this.settings = input(...(ngDevMode ? [undefined, { debugName: "settings" }] : []));
1004
1051
  // --- Outputs ---
1005
1052
  this.wordClicked = new EventEmitter(); // New output event
1006
- // --- Injected Services (using inject function) ---
1053
+ // --- Services ---
1007
1054
  this.renderer = inject(Renderer2);
1008
1055
  this.viewContainerRef = inject(ViewContainerRef);
1009
1056
  this.toastrService = inject(TOAST_ALERTS_TOKEN);
1010
- this.lessonService = inject(LESSONS_TOKEN);
1057
+ this.lessonsService = inject(LESSONS_TOKEN, { optional: true }) ?? inject(DefaultLessonsService);
1011
1058
  this.lessonAIService = inject(LessonAIService); // Inject the new service
1012
1059
  this.userDataExchange = inject(USER_DATA_EXCHANGE);
1013
- // Removed: private readonly wordPopupService = inject(WordPopupService); // No longer needed here
1060
+ this.dynamicComponentsService = inject(DynamicComponentsService);
1061
+ this.uiStateService = inject(UiStateService);
1014
1062
  // --- State Signals ---
1015
- this.lesson = signal(undefined); // Internal lesson state signal
1016
- this.chatVisible = signal(false); // Signal for chat visibility
1017
- this.agentMasterLesson = signal(undefined); // Signal for agent card
1018
- this.evaluatorAgentCard = signal(undefined); // Signal for evaluator card
1019
- this.conversationSettings = signal(undefined);
1020
- this.evalAgentTask = signal(undefined); // Signal for evaluator card
1063
+ this.lesson = signal(undefined, ...(ngDevMode ? [{ debugName: "lesson" }] : [])); // Internal lesson state signal
1064
+ // chatVisible = this.uiStateService.chatDrawerVisible; // Signal for chat visibility
1065
+ this.agentMasterLesson = signal(undefined, ...(ngDevMode ? [{ debugName: "agentMasterLesson" }] : [])); // Signal for agent card
1066
+ this.evaluatorAgentCard = signal(undefined, ...(ngDevMode ? [{ debugName: "evaluatorAgentCard" }] : [])); // Signal for evaluator card
1067
+ this.conversationSettings = signal(undefined, ...(ngDevMode ? [{ debugName: "conversationSettings" }] : []));
1068
+ this.evalAgentTask = signal(undefined, ...(ngDevMode ? [{ debugName: "evalAgentTask" }] : [])); // Signal for evaluator card
1069
+ // backgroundTasks: Record<ConversationEvents | string, SimpleAgentTask> = {};
1070
+ this.conversationFlow = signal(undefined, ...(ngDevMode ? [{ debugName: "conversationFlow" }] : []));
1021
1071
  // --- Computed Signals ---
1022
- this.imageCover = computed(() => this.lesson()?.media?.images?.find((img) => img.type === 'cover')?.url); // Computed signal for imageCover
1072
+ this.imageCover = computed(() => this.lesson()?.media?.images?.find((img) => img.type === 'cover')?.url, ...(ngDevMode ? [{ debugName: "imageCover" }] : [])); // Computed signal for imageCover
1023
1073
  // --- Properties ---
1024
1074
  this.components = {};
1025
1075
  this.mainForm = new FormGroup({});
@@ -1036,7 +1086,7 @@ class DCLessonRendererComponent {
1036
1086
  console.log(`[Renderer] Effect 1: Fetching lesson ${lessonId}`);
1037
1087
  try {
1038
1088
  // Consider adding a loading state signal here
1039
- const fetchedLesson = await this.lessonService.getLesson(lessonId);
1089
+ const fetchedLesson = await this.lessonsService.getLesson(lessonId);
1040
1090
  this.lesson.set(fetchedLesson);
1041
1091
  console.log('Fetched lesson:', fetchedLesson);
1042
1092
  }
@@ -1080,6 +1130,57 @@ class DCLessonRendererComponent {
1080
1130
  }
1081
1131
  });
1082
1132
  }
1133
+ ngOnInit() {
1134
+ // TODO: esto es mal, el goal no puede venir aqui sino pasado desde el componente que inicie la lección
1135
+ this.conversationFlow.set({
1136
+ goal: {
1137
+ enabled: true,
1138
+ task: `User is learning is taking a lesson about languages, evaluate how good are the responses.`,
1139
+ model: { quality: EModelQuality.FAST },
1140
+ },
1141
+ triggerTasks: {
1142
+ [ConversationEvents.OnUserMessage]: {
1143
+ enabled: true,
1144
+ ...this.evalAgentTask(),
1145
+ },
1146
+ },
1147
+ challenges: null,
1148
+ dynamicConditions: [
1149
+ {
1150
+ what: ConditionType.Goal,
1151
+ when: ConditionOperator.GreaterThanOrEqual,
1152
+ value: 100,
1153
+ do: [
1154
+ {
1155
+ actionType: EDoActionType.ChangePrompt,
1156
+ systemPromptType: SystemPromptType.SystemPrompt,
1157
+ 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.',
1158
+ },
1159
+ {
1160
+ actionType: EDoActionType.ChangePrompt,
1161
+ systemPromptType: SystemPromptType.CharacterDescription,
1162
+ prompt: '',
1163
+ },
1164
+ {
1165
+ actionType: EDoActionType.ChangePrompt,
1166
+ systemPromptType: SystemPromptType.UserInformation,
1167
+ prompt: '',
1168
+ },
1169
+ {
1170
+ actionType: EDoActionType.ChangePrompt,
1171
+ systemPromptType: SystemPromptType.MessageExamples,
1172
+ prompt: '',
1173
+ },
1174
+ {
1175
+ actionType: EDoActionType.ChangePrompt,
1176
+ systemPromptType: SystemPromptType.ScenarioDescription,
1177
+ prompt: '',
1178
+ },
1179
+ ],
1180
+ },
1181
+ ],
1182
+ });
1183
+ }
1083
1184
  // --- Rendering Logic ---
1084
1185
  _clearLessonRendering() {
1085
1186
  // Destroy previously created dynamic components
@@ -1095,7 +1196,6 @@ class DCLessonRendererComponent {
1095
1196
  _renderLesson(lessonData) {
1096
1197
  this._clearLessonRendering(); // Clear previous state first
1097
1198
  console.log('Rendering lesson:', lessonData.id);
1098
- // console.log('Image cover URL:', this.imageCover()); // Access computed signal
1099
1199
  // 1) Parse textCoded, create components, and build HTML structure
1100
1200
  const { htmlContent, components } = this._parseAndCreateComponents(lessonData);
1101
1201
  this.components = components;
@@ -1109,7 +1209,6 @@ class DCLessonRendererComponent {
1109
1209
  _parseAndCreateComponents(lessonData) {
1110
1210
  const r1 = new RegExp('~(.+?)~', 'g');
1111
1211
  let count = 0;
1112
- //
1113
1212
  const createdComponents = {};
1114
1213
  const htmlContent = lessonData.textCoded.replace(r1, (_matching, jsonCoded) => {
1115
1214
  const componentName = `dynamicComp${count}`;
@@ -1162,7 +1261,7 @@ class DCLessonRendererComponent {
1162
1261
  lessonCodedConfig = { ...lessonCodedConfig, ...foundConfig };
1163
1262
  }
1164
1263
  }
1165
- const LessonClass = getLessonComponentClass(lessonCodedConfig.component);
1264
+ const LessonClass = this.dynamicComponentsService.getDynamicComponentClass(lessonCodedConfig.component);
1166
1265
  if (!LessonClass) {
1167
1266
  console.error(`Component class not found for type: ${lessonCodedConfig.component}. JSON: ${json}`);
1168
1267
  return null; // Return null if class doesn't exist
@@ -1222,12 +1321,6 @@ class DCLessonRendererComponent {
1222
1321
  }
1223
1322
  }
1224
1323
  });
1225
- if (this.test()) {
1226
- // Access signal value
1227
- console.log('Test mode: Evaluation skipped saving.');
1228
- this.toastrService.info({ subtitle: `Test Results: ${rates.correct} correct, ${rates.incorrect} incorrect`, title: 'Test Mode' });
1229
- return;
1230
- }
1231
1324
  const totalQuestions = rates.correct + rates.incorrect;
1232
1325
  rates.score = totalQuestions > 0 ? rates.correct / totalQuestions : 0; // Avoid division by zero
1233
1326
  const status = rates.score >= 0.7 ? 'passed' : 'failed'; // Use >= for threshold
@@ -1269,10 +1362,10 @@ class DCLessonRendererComponent {
1269
1362
  console.log('Requesting agent cards from LessonAIService...');
1270
1363
  try {
1271
1364
  // Call the service to get the agent cards
1272
- const conversationSettings = await this.lessonAIService.generateConversationSettingsForLesson(currentLesson);
1365
+ const conversationSettings = await this.lessonAIService.generateConversationSettingsForLesson(currentLesson, this.settings());
1273
1366
  if (conversationSettings) {
1274
1367
  this.conversationSettings.set(conversationSettings);
1275
- this.chatVisible.set(true);
1368
+ this.uiStateService.chatDrawerVisible.set(true);
1276
1369
  console.log('Agent cards received and set.');
1277
1370
  }
1278
1371
  else {
@@ -1287,14 +1380,17 @@ class DCLessonRendererComponent {
1287
1380
  }
1288
1381
  onVisibleChange(isVisible) {
1289
1382
  if (isVisible === false) {
1290
- this.chatVisible.set(false);
1383
+ this.uiStateService.chatDrawerVisible.set(false);
1291
1384
  }
1292
1385
  }
1293
- handleGoalCompleted(event) {
1386
+ async handleGoalCompleted(event = {}) {
1294
1387
  console.log('Goal completed:', event);
1295
1388
  const lesson = this.lesson();
1296
- const dummy = { id: lesson.id, goalCompleted: true, score: 100, status: 'finished', lastAccess: new Date() };
1297
- this.lessonService.saveTakenLesson(dummy);
1389
+ const takenLesson = { id: lesson.id, goalCompleted: true, score: 100, status: 'finished', lastAccess: new Date() };
1390
+ const res = await this.lessonsService.saveTakenLesson(takenLesson);
1391
+ if (res) {
1392
+ // this.lessonsMemStateService.updateUserState(res);
1393
+ }
1298
1394
  this.toastrService.success({ subtitle: '¡Has completado la lección! , pero puedes seguir conversando', title: '¡Muy bien, guardaremos tu progreso!' });
1299
1395
  }
1300
1396
  onChatMessage(event) {
@@ -1311,12 +1407,12 @@ class DCLessonRendererComponent {
1311
1407
  console.log('Unhandled chat event type:', event.type);
1312
1408
  }
1313
1409
  }
1314
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DCLessonRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1315
- 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 }, test: { classPropertyName: "test", publicName: "test", 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 [taskOnUserMessage]=\"evalAgentTask()\"\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", "taskOnUserMessage", "taskOnAssistantMessage", "parseDict"], outputs: ["sendMessage", "goalCompleted"] }, { kind: "ngmodule", type: DrawerModule }, { kind: "component", type: i2$4.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"] }] }); }
1410
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DCLessonRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1411
+ 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, 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(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]=\"conversationFlow()\"\n [conversationSettings]=\"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: "pipe", type: KeyValuePipe, name: "keyvalue" }] }); }
1316
1412
  }
1317
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DCLessonRendererComponent, decorators: [{
1413
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DCLessonRendererComponent, decorators: [{
1318
1414
  type: Component,
1319
- 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 [taskOnUserMessage]=\"evalAgentTask()\"\n [conversationSettings]=\"conversationSettings()\"\n (goalCompleted)=\"handleGoalCompleted($event)\"\n (sendMessage)=\"onChatMessage($event)\"></dc-chat>\n</p-drawer>\n}\n", styles: [".evaluate{float:right}\n"] }]
1415
+ 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(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]=\"conversationFlow()\"\n [conversationSettings]=\"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"] }]
1320
1416
  }], ctorParameters: () => [], propDecorators: { wordClicked: [{
1321
1417
  type: Output
1322
1418
  }], dynamicLesson: [{
@@ -1327,13 +1423,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImpor
1327
1423
  class LessonNotionService {
1328
1424
  constructor() {
1329
1425
  this.#notionService = inject(NOTION_SERVICE_TOKEN);
1330
- this.#lessonService = inject(LESSONS_TOKEN);
1426
+ this.lessonsService = inject(LESSONS_TOKEN, { optional: true }) ?? inject(DefaultLessonsService);
1331
1427
  this.#toastService = inject(TOAST_ALERTS_TOKEN);
1332
1428
  // Keep track of loading state specific to Notion operations
1333
- this.isLoading = signal(false);
1429
+ this.isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
1334
1430
  }
1335
1431
  #notionService;
1336
- #lessonService;
1337
1432
  #toastService;
1338
1433
  /**
1339
1434
  * Extracts the Notion Page ID from a URL.
@@ -1367,14 +1462,17 @@ class LessonNotionService {
1367
1462
  }
1368
1463
  const updatedLesson = {
1369
1464
  ...lesson,
1370
- extras: {
1371
- ...(lesson.extras || {}),
1372
- notionPageId: notionPageId,
1465
+ extensions: {
1466
+ ...(lesson.extensions || {}),
1467
+ extras: {
1468
+ ...(lesson.extensions?.['extras'] || {}),
1469
+ notionPageId: notionPageId,
1470
+ },
1373
1471
  },
1374
1472
  };
1375
1473
  this.isLoading.set(true);
1376
1474
  try {
1377
- const savedLesson = await this.#lessonService.postLesson(updatedLesson);
1475
+ const savedLesson = await this.lessonsService.postLesson(updatedLesson);
1378
1476
  this.#toastService.success({ title: 'Listo', subtitle: 'Se enlazó la lección con Notion.' });
1379
1477
  return savedLesson;
1380
1478
  }
@@ -1400,10 +1498,10 @@ class LessonNotionService {
1400
1498
  if (!currentLesson)
1401
1499
  return null;
1402
1500
  let notionPageId = null;
1403
- if (currentLesson.extras?.notionPageId) {
1404
- const useExisting = confirm(`Ya tenemos el id ${currentLesson.extras.notionPageId} ¿Quieres usar este id para importar?`);
1501
+ if (currentLesson.extensions?.['extras']?.['notionPageId']) {
1502
+ const useExisting = confirm(`Ya tenemos el id ${currentLesson.extensions?.['extras']?.['notionPageId']} ¿Quieres usar este id para importar?`);
1405
1503
  if (useExisting) {
1406
- notionPageId = currentLesson.extras.notionPageId;
1504
+ notionPageId = currentLesson.extensions?.['extras']?.['notionPageId'];
1407
1505
  }
1408
1506
  else {
1409
1507
  const inputUrl = prompt('Ingresa la NUEVA URL de Notion para importar (este ID NO se guardará automáticamente si la lección ya existe)');
@@ -1458,7 +1556,7 @@ class LessonNotionService {
1458
1556
  async improveLessonWithNotionAI(lesson) {
1459
1557
  if (!lesson)
1460
1558
  return;
1461
- const notionId = lesson.extras?.notionPageId;
1559
+ const notionId = lesson.extensions?.['extras']?.['notionPageId'];
1462
1560
  if (!notionId) {
1463
1561
  this.#toastService.warn({ title: 'Sin ID de Notion', subtitle: 'Enlaza la lección con Notion primero.' });
1464
1562
  return;
@@ -1482,22 +1580,21 @@ class LessonNotionService {
1482
1580
  this.isLoading.set(false);
1483
1581
  }
1484
1582
  }
1485
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: LessonNotionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1486
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: LessonNotionService }); }
1583
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: LessonNotionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1584
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: LessonNotionService }); }
1487
1585
  }
1488
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: LessonNotionService, decorators: [{
1586
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: LessonNotionService, decorators: [{
1489
1587
  type: Injectable
1490
1588
  }] });
1491
1589
 
1492
1590
  // import { UserDataExchangeService } from '@dataclouder/ngx-agent-cards';
1493
1591
  class LessonUtilsService {
1494
1592
  constructor() {
1495
- this.#lessonService = inject(LESSONS_TOKEN);
1593
+ this.lessonsService = inject(LESSONS_TOKEN, { optional: true }) ?? inject(DefaultLessonsService);
1496
1594
  this.#toastService = inject(TOAST_ALERTS_TOKEN);
1497
1595
  this.#agentService = inject(CONVERSATION_AI_TOKEN);
1498
1596
  this.loadingBarService = inject(LoadingBarService);
1499
1597
  }
1500
- #lessonService;
1501
1598
  #toastService;
1502
1599
  #agentService;
1503
1600
  /**
@@ -1522,10 +1619,11 @@ class LessonUtilsService {
1522
1619
  lessonSignal.update((currentLesson) => {
1523
1620
  if (!currentLesson)
1524
1621
  return undefined;
1525
- const updatedMetadata = { ...(currentLesson.metadata ?? {}), banner: imageUploaded };
1622
+ const assets = { ...(currentLesson.assets ?? {}) };
1623
+ assets.banner = imageUploaded;
1526
1624
  return {
1527
1625
  ...currentLesson,
1528
- metadata: updatedMetadata,
1626
+ assets,
1529
1627
  };
1530
1628
  });
1531
1629
  }
@@ -1543,9 +1641,9 @@ class LessonUtilsService {
1543
1641
  }
1544
1642
  // No need to save here, component should ensure it's saved before calling.
1545
1643
  try {
1546
- await this.#lessonService.postGenerateByAI(lessonId);
1644
+ await this.lessonsService.postGenerateByAI(lessonId);
1547
1645
  // Re-fetch the lesson data to get AI updates
1548
- const updatedLesson = await this.#lessonService.getLesson(lessonId);
1646
+ const updatedLesson = await this.lessonsService.getLesson(lessonId);
1549
1647
  if (updatedLesson) {
1550
1648
  this.#toastService.success({ title: 'IA completada', subtitle: 'Lección actualizada con IA.' });
1551
1649
  return updatedLesson;
@@ -1576,7 +1674,7 @@ class LessonUtilsService {
1576
1674
  }
1577
1675
  try {
1578
1676
  this.loadingBarService.showIndeterminate();
1579
- const textPrompt = this.#lessonService.getPrompts().content(lesson);
1677
+ const textPrompt = this.lessonsService.getPrompts().content(lesson);
1580
1678
  const messages = [{ content: textPrompt, role: ChatRole.User }];
1581
1679
  const response = await this.#agentService.callChatCompletion({ messages, model: { provider: 'google' } });
1582
1680
  let improvedMarkdown = response.content?.trim() ?? null;
@@ -1628,7 +1726,7 @@ class LessonUtilsService {
1628
1726
  this.#toastService.warn({ title: 'Texto Vacío', subtitle: 'No se pudo extraer texto útil del contenido de la lección.' });
1629
1727
  return null;
1630
1728
  }
1631
- const descriptionPrompt = this.#lessonService.getPrompts().description(lesson);
1729
+ const descriptionPrompt = this.lessonsService.getPrompts().description(lesson);
1632
1730
  const messages = [{ content: descriptionPrompt, role: ChatRole.User }];
1633
1731
  const response = await this.#agentService.callChatCompletion({ messages, model: { provider: 'google' } });
1634
1732
  let generatedDescription = response.content?.trim() ?? null;
@@ -1735,55 +1833,82 @@ class LessonUtilsService {
1735
1833
  dynamicComponents: cleanedDynamicComponents,
1736
1834
  };
1737
1835
  }
1738
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: LessonUtilsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1739
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: LessonUtilsService, providedIn: 'root' }); }
1836
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: LessonUtilsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1837
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: LessonUtilsService, providedIn: 'root' }); }
1740
1838
  }
1741
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: LessonUtilsService, decorators: [{
1839
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: LessonUtilsService, decorators: [{
1742
1840
  type: Injectable,
1743
1841
  args: [{
1744
1842
  providedIn: 'root', // Provide globally or in a specific module if preferred
1745
1843
  }]
1746
1844
  }] });
1747
1845
 
1846
+ class DynamicComponentsBuilderService {
1847
+ #dialogService = inject(DialogService);
1848
+ #toastService = inject(TOAST_ALERTS_TOKEN);
1849
+ #dynamicComponentsService = inject(DynamicComponentsService);
1850
+ openComponentBuilder(componentType, data = null) {
1851
+ const componentToBuild = this.#dynamicComponentsService.getDynamicComponentBuilders(componentType);
1852
+ if (!componentToBuild) {
1853
+ console.error(`No component builder found for type: ${componentType}`);
1854
+ this.#toastService.error({ title: 'Error', subtitle: `Componente desconocido: ${componentType}` });
1855
+ return undefined;
1856
+ }
1857
+ const dialogRef = this.#dialogService.open(componentToBuild, {
1858
+ inputValues: {
1859
+ // inputValues was removed in newer PrimeNG versions, use 'data'
1860
+ inputs: data.inputs,
1861
+ id: data.id,
1862
+ },
1863
+ width: '80vw',
1864
+ header: 'Agregar componente',
1865
+ closable: true,
1866
+ });
1867
+ return dialogRef;
1868
+ }
1869
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DynamicComponentsBuilderService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1870
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DynamicComponentsBuilderService, providedIn: 'root' }); }
1871
+ }
1872
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DynamicComponentsBuilderService, decorators: [{
1873
+ type: Injectable,
1874
+ args: [{
1875
+ providedIn: 'root',
1876
+ }]
1877
+ }] });
1878
+
1748
1879
  class DCLessonComponentAdderComponent {
1749
1880
  constructor() {
1750
1881
  // Services
1751
- this.#dialogService = inject(DialogService);
1752
- this.#toastService = inject(TOAST_ALERTS_TOKEN);
1882
+ this.#dynamicComponentsBuilderService = inject(DynamicComponentsBuilderService);
1753
1883
  this.componentAdded = new EventEmitter(); // Changed Output name and type
1754
1884
  // Expose enum to the template
1755
1885
  this.lessonComponentEnum = LessonComponentEnum;
1756
1886
  }
1757
1887
  // Services
1758
- #dialogService;
1759
- #toastService;
1760
- // Moved logic from DCLessonEditorComponent
1888
+ #dynamicComponentsBuilderService;
1889
+ // Logic to open component builder, now utilizing DynamicComponentsBuilderService
1761
1890
  openComponentBuilder(type) {
1762
- const componentToBuild = LessonComponentBuilders[type];
1763
- if (!componentToBuild) {
1764
- console.error(`No component builder found for type: ${type}`);
1765
- this.#toastService.error({ title: 'Error', subtitle: `Componente desconocido: ${type}` });
1766
- return;
1891
+ const dialogRef = this.#dynamicComponentsBuilderService.openComponentBuilder(type);
1892
+ if (dialogRef) {
1893
+ // Handle the result and emit the new event
1894
+ dialogRef.onClose.subscribe((result) => {
1895
+ if (result) {
1896
+ console.log('Component builder closed:', result);
1897
+ this.componentAdded.emit(result); // Emit the result when dialog closes successfully
1898
+ }
1899
+ });
1900
+ }
1901
+ else {
1902
+ // Optional: Log if the dialog couldn't be opened, though the service already logs an error.
1903
+ console.warn(`Dialog could not be opened for type via component: ${type}`);
1767
1904
  }
1768
- const dialogRef = this.#dialogService.open(componentToBuild, {
1769
- width: '80vw',
1770
- header: 'Agregar componente',
1771
- closable: true,
1772
- });
1773
- // Handle the result and emit the new event
1774
- dialogRef.onClose.subscribe((result) => {
1775
- if (result) {
1776
- console.log('Component builder closed:', result);
1777
- this.componentAdded.emit(result); // Emit the result when dialog closes successfully
1778
- }
1779
- });
1780
1905
  }
1781
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DCLessonComponentAdderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1782
- 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 <!-- 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: i2$5.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }] }); }
1906
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DCLessonComponentAdderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1907
+ 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: i2$3.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo"] }] }); }
1783
1908
  }
1784
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DCLessonComponentAdderComponent, decorators: [{
1909
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DCLessonComponentAdderComponent, decorators: [{
1785
1910
  type: Component,
1786
- 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 <!-- Add other buttons here if needed, following the same pattern -->\n</div>\n" }]
1911
+ 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" }]
1787
1912
  }], propDecorators: { componentAdded: [{
1788
1913
  type: Output
1789
1914
  }] } });
@@ -1791,8 +1916,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImpor
1791
1916
  class DCLessonMetadataEditorComponent {
1792
1917
  constructor() {
1793
1918
  // Use signal for input lesson data
1794
- this.lesson = signal(undefined); // The lesson data itself
1795
- this.isLoadingLesson = signal(false); // Shared loading state
1919
+ this.lesson = signal(undefined, ...(ngDevMode ? [{ debugName: "lesson" }] : [])); // The lesson data itself
1920
+ this.isLoadingLesson = signal(false, ...(ngDevMode ? [{ debugName: "isLoadingLesson" }] : [])); // Shared loading state
1796
1921
  // Outputs for actions
1797
1922
  this.saveRequest = new EventEmitter();
1798
1923
  this.importNotionRequest = new EventEmitter();
@@ -1803,7 +1928,7 @@ class DCLessonMetadataEditorComponent {
1803
1928
  // Injected Services
1804
1929
  this.#lessonUtilsService = inject(LessonUtilsService);
1805
1930
  this.#toastService = inject(TOAST_ALERTS_TOKEN);
1806
- this.#lessonService = inject(LESSONS_TOKEN);
1931
+ this.lessonsService = inject(LESSONS_TOKEN, { optional: true }) ?? inject(DefaultLessonsService);
1807
1932
  this.#turndownService = new TurndownService(); // Instantiate TurndownService
1808
1933
  }
1809
1934
  // Removed generateAIRequest Output as it's handled internally now
@@ -1812,7 +1937,6 @@ class DCLessonMetadataEditorComponent {
1812
1937
  // Injected Services
1813
1938
  #lessonUtilsService;
1814
1939
  #toastService;
1815
- #lessonService;
1816
1940
  #turndownService; // Instantiate TurndownService
1817
1941
  // Method to handle property changes for ROOT properties (e.g., level)
1818
1942
  onRootPropertyChange(property, value) {
@@ -1820,24 +1944,15 @@ class DCLessonMetadataEditorComponent {
1820
1944
  if (!current)
1821
1945
  return undefined;
1822
1946
  // Avoid updating metadata directly here
1823
- if (property === 'metadata') {
1824
- console.warn('Direct metadata updates should use onMetadataPropertyChange');
1825
- return current;
1826
- }
1947
+ // if (property === 'metadata') {
1948
+ // console.warn('Direct metadata updates should use onMetadataPropertyChange');
1949
+ // return current;
1950
+ // }
1827
1951
  return { ...current, [property]: value };
1828
1952
  });
1829
1953
  // Emit removed - signal is updated directly above.
1830
1954
  // this.propertyChange.emit({ propertyPath: property, value });
1831
1955
  }
1832
- // Method to handle property changes for METADATA properties
1833
- onMetadataPropertyChange(property, value) {
1834
- this.lesson.update((current) => {
1835
- if (!current)
1836
- return undefined;
1837
- const updatedMetadata = { ...(current.metadata ?? {}), [property]: value };
1838
- return { ...current, metadata: updatedMetadata };
1839
- });
1840
- }
1841
1956
  // Method to handle property changes for APP EXTENSION properties
1842
1957
  onAppExtensionPropChange(property, value) {
1843
1958
  this.lesson.update((current) => {
@@ -1846,8 +1961,24 @@ class DCLessonMetadataEditorComponent {
1846
1961
  // Ensure appExtension exists, initialize if not
1847
1962
  // Convert value to number specifically for 'level'
1848
1963
  const finalValue = property === 'level' ? Number(value) : value;
1849
- const updatedAppExtension = { ...(current.appExtension ?? {}), [property]: finalValue };
1850
- return { ...current, appExtension: updatedAppExtension };
1964
+ const updatedAppExtension = { ...(current.extensions ?? {}), [property]: finalValue };
1965
+ return { ...current, extensions: updatedAppExtension };
1966
+ });
1967
+ }
1968
+ onManageablePropertyChange(property, value) {
1969
+ this.lesson.update((current) => {
1970
+ if (!current)
1971
+ return undefined;
1972
+ const updatedManageable = { ...(current.manageable ?? {}), [property]: value };
1973
+ return { ...current, manageable: updatedManageable };
1974
+ });
1975
+ }
1976
+ onAuditablePropertyChange(property, value) {
1977
+ this.lesson.update((current) => {
1978
+ if (!current)
1979
+ return undefined;
1980
+ const updatedAuditable = { ...(current.auditable ?? {}), [property]: value };
1981
+ return { ...current, auditable: updatedAuditable };
1851
1982
  });
1852
1983
  }
1853
1984
  // Methods to emit action requests
@@ -1883,7 +2014,7 @@ class DCLessonMetadataEditorComponent {
1883
2014
  else {
1884
2015
  // Clean orphaned and Save before Improve
1885
2016
  const lessonToSave = this.#lessonUtilsService.cleanOrphanedComponents(currentLesson);
1886
- const savedLesson = await this.#lessonService.postLesson(lessonToSave);
2017
+ const savedLesson = await this.lessonsService.postLesson(lessonToSave);
1887
2018
  if (!savedLesson) {
1888
2019
  this.#toastService.error({ title: 'Error al guardar', subtitle: 'No se pudo guardar antes de generar con IA.' });
1889
2020
  throw new Error('Failed to save before AI generation');
@@ -1946,7 +2077,7 @@ class DCLessonMetadataEditorComponent {
1946
2077
  // Ensure lesson() is not undefined before saving
1947
2078
  const lessonToSave = this.lesson();
1948
2079
  if (lessonToSave) {
1949
- await this.#lessonService.postLesson(lessonToSave);
2080
+ await this.lessonsService.postLesson(lessonToSave);
1950
2081
  this.#toastService.success({ title: 'Contenido generado', subtitle: 'Se generó y guardó el contenido con IA.' });
1951
2082
  }
1952
2083
  else {
@@ -1976,32 +2107,35 @@ class DCLessonMetadataEditorComponent {
1976
2107
  }
1977
2108
  const generatedDescription = await this.#lessonUtilsService.generateDescriptionWithAI(currentLesson);
1978
2109
  if (generatedDescription) {
1979
- // Use the new method for metadata properties
1980
- this.onMetadataPropertyChange('description', generatedDescription);
2110
+ this.lessonForm.controls['description'].setValue(generatedDescription);
1981
2111
  }
1982
2112
  }
1983
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DCLessonMetadataEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1984
- 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: i4.InputText, selector: "[pInputText]", inputs: ["variant", "fluid", "pSize"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i2$5.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
2113
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DCLessonMetadataEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2114
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.6", type: DCLessonMetadataEditorComponent, isStandalone: true, selector: "dc-lesson-metadata-editor", inputs: { lesson: "lesson", lessonForm: "lessonForm", isLoadingLesson: "isLoadingLesson" }, outputs: { saveRequest: "saveRequest", importNotionRequest: "importNotionRequest", improveNotionRequest: "improveNotionRequest" }, ngImport: i0, template: "@if (lesson(); as currentLesson) {\n<div [formGroup]=\"lessonForm\">\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 pInputText style=\"width: 100%\" formControlName=\"title\" type=\"text\" placeholder=\"Agrega un t\u00EDtulo\" />\n </div>\n <div style=\"margin-top: 4px\">\n <p-inputgroup>\n <input pInputText style=\"width: 100%\" formControlName=\"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\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.auditable?.prompt\"\n (ngModelChange)=\"onAuditablePropertyChange('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.manageable?.status === 'published'\"\n (ngModelChange)=\"onManageablePropertyChange('status', $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.extensions?.['level']\"\n (ngModelChange)=\"onAppExtensionPropChange('level', $event)\"\n type=\"number\"\n placeholder=\"Nivel\"\n style=\"width: 80px\" />\n\n <!-- Access signal values -->\n @if (currentLesson.extensions) {\n <div>\n {{ currentLesson.extensions?.['baseLang'] | flagEmoji }} -> {{ currentLesson.extensions?.['targetLang'] | flagEmoji }} Lecci\u00F3n para hablantes de\n {{ currentLesson.extensions?.['baseLang'] | langDesc : 'es' }} que aprenden\n {{ currentLesson.extensions?.['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.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: 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.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: TooltipModule }, { kind: "directive", type: i2$3.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
2115
+ 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
1985
2116
  FlagLanguagePipe, name: "flagEmoji" }, { kind: "pipe", type: // Added Pipe
1986
- LangDescTranslationPipe, name: "langDesc" }, { kind: "ngmodule", type: // Added Pipe
1987
- InputGroupModule }, { kind: "component", type: i5$1.InputGroup, selector: "p-inputgroup, p-inputGroup, p-input-group", inputs: ["style", "styleClass"] }, { kind: "ngmodule", type: DividerModule }, { kind: "component", type: i6.Divider, selector: "p-divider", inputs: ["style", "styleClass", "layout", "type", "align"] }] }); }
2117
+ LangDescTranslationPipe, name: "langDesc" }] }); }
1988
2118
  }
1989
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DCLessonMetadataEditorComponent, decorators: [{
2119
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DCLessonMetadataEditorComponent, decorators: [{
1990
2120
  type: Component,
1991
2121
  args: [{ selector: 'dc-lesson-metadata-editor', standalone: true, imports: [
1992
2122
  CommonModule,
1993
2123
  FormsModule,
1994
2124
  ButtonModule,
1995
2125
  InputTextModule,
2126
+ ReactiveFormsModule,
1996
2127
  TooltipModule, // Added TooltipModule
1997
2128
  FlagLanguagePipe, // Added Pipe
1998
2129
  LangDescTranslationPipe, // Added Pipe
1999
2130
  InputGroupModule,
2000
2131
  DividerModule,
2001
- ], 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" }]
2132
+ ], template: "@if (lesson(); as currentLesson) {\n<div [formGroup]=\"lessonForm\">\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 pInputText style=\"width: 100%\" formControlName=\"title\" type=\"text\" placeholder=\"Agrega un t\u00EDtulo\" />\n </div>\n <div style=\"margin-top: 4px\">\n <p-inputgroup>\n <input pInputText style=\"width: 100%\" formControlName=\"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\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.auditable?.prompt\"\n (ngModelChange)=\"onAuditablePropertyChange('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.manageable?.status === 'published'\"\n (ngModelChange)=\"onManageablePropertyChange('status', $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.extensions?.['level']\"\n (ngModelChange)=\"onAppExtensionPropChange('level', $event)\"\n type=\"number\"\n placeholder=\"Nivel\"\n style=\"width: 80px\" />\n\n <!-- Access signal values -->\n @if (currentLesson.extensions) {\n <div>\n {{ currentLesson.extensions?.['baseLang'] | flagEmoji }} -> {{ currentLesson.extensions?.['targetLang'] | flagEmoji }} Lecci\u00F3n para hablantes de\n {{ currentLesson.extensions?.['baseLang'] | langDesc : 'es' }} que aprenden\n {{ currentLesson.extensions?.['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" }]
2002
2133
  }], propDecorators: { lesson: [{
2003
2134
  type: Input,
2004
2135
  args: [{ required: true }]
2136
+ }], lessonForm: [{
2137
+ type: Input,
2138
+ args: [{ required: true }]
2005
2139
  }], isLoadingLesson: [{
2006
2140
  type: Input,
2007
2141
  args: [{ required: true }]
@@ -2013,152 +2147,47 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImpor
2013
2147
  type: Output
2014
2148
  }] } });
2015
2149
 
2016
- // Define placeholder endpoints - these should be configured appropriately
2017
- const LESSONS_BASE_PATH = 'api/lesson'; // Example base path
2018
- class DefaultLessonsService {
2019
- constructor() {
2020
- this.httpCoreService = inject(HttpCoreService);
2021
- // --- Endpoint Definitions (Hardcoded as requested) ---
2022
- this.endpoints = {
2023
- queryLessons: `${LESSONS_BASE_PATH}/query`,
2024
- getLesson: (id) => `${LESSONS_BASE_PATH}/${id}`,
2025
- saveLesson: `api/user/saveLesson`,
2026
- updateLesson: (id) => `${LESSONS_BASE_PATH}/${id}`, // Assuming PUT to /lessons/:id
2027
- deleteLesson: (id) => `${LESSONS_BASE_PATH}/${id}`, // Assuming DELETE to /lessons/:id
2028
- generateLesson: `${LESSONS_BASE_PATH}/generate`, // Placeholder
2029
- generateByAI: `${LESSONS_BASE_PATH}/generate-ai`, // Placeholder
2030
- improveMDWithAI: `${LESSONS_BASE_PATH}/improve-markdown-ai`, // Placeholder
2031
- QueryLessons: 'api/lesson/query',
2032
- Lesson: 'api/lesson',
2033
- SaveLesson: 'api/lesson-polilan',
2034
- GetPublicLessons: 'api/lesson/publicLessons',
2035
- GetUnpublishedLessons: 'api/lesson/unpublished',
2036
- TakenLesson: 'api/lesson/taken',
2037
- DeleteLesson: 'api/lesson',
2038
- Base: 'api/lesson',
2039
- GenerateBanner: 'api/lesson/generate-banner',
2040
- };
2041
- }
2042
- saveTakenLesson(lesson) {
2043
- // Not sure how to implement this yet.
2044
- return this.httpCoreService.post(this.endpoints.saveLesson, lesson);
2045
- }
2046
- // --- Method Implementations ---
2047
- async getLessons(paginator) {
2048
- // Assuming paginator is the body for a POST request based on the example
2049
- return this.httpCoreService.post(this.endpoints.queryLessons, paginator || {});
2050
- }
2051
- async getLesson(id) {
2052
- return this.httpCoreService.get(this.endpoints.getLesson(id));
2053
- }
2054
- async postLesson(lesson) {
2055
- return this.httpCoreService.post(this.endpoints.saveLesson, lesson);
2056
- }
2057
- async updateLesson(lesson) {
2058
- if (!lesson._id) {
2059
- throw new Error('Lesson ID is required for update.');
2060
- }
2061
- // Assuming _id is the identifier
2062
- return this.httpCoreService.put(this.endpoints.updateLesson(lesson._id), lesson);
2063
- }
2064
- async deleteLesson(id) {
2065
- return this.httpCoreService.delete(this.endpoints.deleteLesson(id));
2066
- }
2067
- async generateLesson(lesson) {
2068
- // This endpoint might need specific data or structure
2069
- return this.httpCoreService.post(this.endpoints.generateLesson, lesson);
2070
- }
2071
- async postGenerateByAI(id) {
2072
- return this.httpCoreService.post(this.endpoints.generateByAI, { id });
2073
- }
2074
- async postImproveMDWithAI(lessonId, markdownText) {
2075
- return this.httpCoreService.post(this.endpoints.improveMDWithAI, { id: lessonId, markdown: markdownText });
2076
- }
2077
- extractTextFromHtml(html) {
2078
- // Copied from src/app/core/data-services/lessons.service.ts
2079
- const r1 = new RegExp('~(.+?)~', 'g');
2080
- const lessonHtml = html.replace(r1, (_matching, jsonCoded) => {
2081
- try {
2082
- const data = JSON.parse(jsonCoded);
2083
- return `<span>${data?.settings?.text || ''}</span>`; // Added default empty string
2084
- }
2085
- catch (e) {
2086
- console.error('Error parsing JSON in extractTextFromHtml:', jsonCoded, e);
2087
- return ''; // Return empty string on error
2088
- }
2089
- });
2090
- // Remove HTML tags
2091
- let text = lessonHtml.replace(/<[^>]*>/g, ' ');
2092
- // Remove style and script content
2093
- text = text.replace(/<style[^>]*>[\s\S]*?<\/style>/gi, ' ');
2094
- text = text.replace(/<script[^>]*>[\s\S]*?<\/script>/gi, ' ');
2095
- // Decode HTML entities
2096
- text = text.replace(/&nbsp;/g, ' ');
2097
- text = text.replace(/&/g, '&');
2098
- text = text.replace(/</g, '<');
2099
- text = text.replace(/>/g, '>');
2100
- // Remove extra whitespace
2101
- text = text.replace(/\s+/g, ' ').trim();
2102
- return text;
2103
- }
2104
- generateBanner(prompt, lessonId) {
2105
- return this.httpCoreService.post(this.endpoints.GenerateBanner, { prompt, lessonId });
2106
- }
2107
- getPrompts() {
2108
- return null;
2109
- }
2110
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DefaultLessonsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2111
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DefaultLessonsService, providedIn: 'root' }); }
2112
- }
2113
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DefaultLessonsService, decorators: [{
2114
- type: Injectable,
2115
- args: [{
2116
- providedIn: 'root',
2117
- }]
2118
- }] });
2119
-
2120
2150
  class DCLessonEditorComponent {
2121
2151
  // Services
2122
2152
  #activatedRoute; // Re-inject as it's needed for navigation
2123
2153
  #lessonNotionService;
2124
2154
  #lessonUtilsService;
2125
2155
  #router;
2126
- #lessonService;
2127
2156
  #toastService;
2128
2157
  #loadingBarService;
2158
+ #formBuilder;
2129
2159
  constructor() {
2130
2160
  // Services
2131
2161
  this.#activatedRoute = inject(ActivatedRoute); // Re-inject as it's needed for navigation
2132
2162
  this.#lessonNotionService = inject(LessonNotionService);
2133
2163
  this.#lessonUtilsService = inject(LessonUtilsService);
2134
2164
  this.#router = inject(Router);
2135
- this.#lessonService = inject(LESSONS_TOKEN);
2165
+ this.lessonsService = inject(LESSONS_TOKEN, { optional: true }) ?? inject(DefaultLessonsService);
2136
2166
  this.#toastService = inject(TOAST_ALERTS_TOKEN);
2137
2167
  this.#loadingBarService = inject(LoadingBarService);
2138
2168
  this.defaultLessonsService = inject(DefaultLessonsService);
2139
2169
  this.promptService = inject(PromptService);
2140
2170
  this.ngxVertexService = inject(NgxVertexService);
2141
2171
  this.cdr = inject(ChangeDetectorRef);
2172
+ this.dynamicComponentsBuilderService = inject(DynamicComponentsBuilderService);
2173
+ this.#formBuilder = inject(FormBuilder);
2142
2174
  // Signals States
2143
2175
  this.lessonId = toSignal(inject(ActivatedRoute).paramMap.pipe(map((params) => params.get('id'))));
2144
- this.lesson = signal(undefined); // Initialize as undefined
2145
- this.isLoadingLesson = signal(false);
2176
+ this.lesson = signal(undefined, ...(ngDevMode ? [{ debugName: "lesson" }] : []));
2177
+ this.isLoadingLesson = signal(false, ...(ngDevMode ? [{ debugName: "isLoadingLesson" }] : []));
2146
2178
  // Computed Signals
2147
2179
  this.coverImageUrl = computed(() => {
2148
2180
  // Priority Order 1 Metadata Banner, 2 Banner, 3 Media First Images, 4 Default Banner TODO: reveme banner after migration to Content
2149
2181
  const currentLesson = this.lesson();
2150
- if (currentLesson?.metadata?.banner?.url) {
2151
- return currentLesson.metadata.banner.url;
2152
- }
2153
- else if (currentLesson?.banner?.url) {
2154
- return currentLesson.banner.url;
2182
+ if (currentLesson?.assets?.banner?.url) {
2183
+ return currentLesson.assets.banner.url;
2155
2184
  }
2156
2185
  else if (currentLesson?.media?.images?.find((img) => img.type === 'cover')) {
2157
2186
  // 3 Media First Images
2158
2187
  return currentLesson.media.images.find((img) => img.type === 'cover')?.url;
2159
2188
  }
2160
- return '/assets/images/default_banner.webp';
2161
- });
2189
+ return '/assets/defaults/images/default_banner.webp';
2190
+ }, ...(ngDevMode ? [{ debugName: "coverImageUrl" }] : []));
2162
2191
  // Computed signal to get dynamic components as an array for easier iteration in the template
2163
2192
  this.dynamicComponentsArray = computed(() => {
2164
2193
  const currentLesson = this.lesson();
@@ -2166,7 +2195,7 @@ class DCLessonEditorComponent {
2166
2195
  return Object.values(currentLesson.dynamicComponents);
2167
2196
  }
2168
2197
  return []; // Return empty array if no lesson or no dynamic components
2169
- });
2198
+ }, ...(ngDevMode ? [{ debugName: "dynamicComponentsArray" }] : []));
2170
2199
  // States
2171
2200
  this.components = {}; // Current Dynamic components
2172
2201
  this.editor = BalloonEditor;
@@ -2177,6 +2206,10 @@ class DCLessonEditorComponent {
2177
2206
  cropSettings: { resizeToWidth: 850, aspectRatio: AspectType.RectangleLarge, resolutions: [ResolutionType.Medium] },
2178
2207
  };
2179
2208
  this.promptsVisible = false;
2209
+ this.lessonForm = this.#formBuilder.group({
2210
+ title: [''],
2211
+ description: [''],
2212
+ });
2180
2213
  // Effect to fetch lesson data when ID changes
2181
2214
  effect(async () => {
2182
2215
  const id = this.lessonId();
@@ -2184,9 +2217,10 @@ class DCLessonEditorComponent {
2184
2217
  if (id) {
2185
2218
  this.isLoadingLesson.set(true); // Start loading
2186
2219
  try {
2187
- const fetchedLesson = await this.#lessonService.getLesson(id);
2220
+ const fetchedLesson = await this.lessonsService.getLesson(id);
2188
2221
  if (fetchedLesson) {
2189
2222
  this.lesson.set(fetchedLesson);
2223
+ this.lessonForm.patchValue(fetchedLesson, { emitEvent: false });
2190
2224
  }
2191
2225
  else {
2192
2226
  this.lesson.set(undefined); // Reset if not found
@@ -2211,6 +2245,13 @@ class DCLessonEditorComponent {
2211
2245
  this.isLoadingLesson.set(false); // Ensure loading is off
2212
2246
  }
2213
2247
  });
2248
+ this.lessonForm.valueChanges.subscribe((value) => {
2249
+ this.lesson.update((current) => {
2250
+ if (!current)
2251
+ return undefined;
2252
+ return { ...current, ...value };
2253
+ });
2254
+ });
2214
2255
  }
2215
2256
  /**
2216
2257
  * Updates a specific property on the lesson signal.
@@ -2226,6 +2267,13 @@ class DCLessonEditorComponent {
2226
2267
  return { ...currentLesson, [property]: value };
2227
2268
  });
2228
2269
  }
2270
+ onAssetsChange(updatedAssets) {
2271
+ this.lesson.update((currentLesson) => {
2272
+ if (!currentLesson)
2273
+ return undefined;
2274
+ return { ...currentLesson, assets: updatedAssets };
2275
+ });
2276
+ }
2229
2277
  onTagRemove(tag) {
2230
2278
  this.lesson.update((currentLesson) => {
2231
2279
  if (!currentLesson)
@@ -2263,9 +2311,10 @@ class DCLessonEditorComponent {
2263
2311
  this.isLoadingLesson.set(true); // Indicate saving
2264
2312
  try {
2265
2313
  // Use the cleaned lesson object for saving
2266
- const savedLesson = await this.#lessonService.postLesson(lessonToSave);
2314
+ const savedLesson = await this.lessonsService.postLesson(lessonToSave);
2267
2315
  const currentId = this.lessonId();
2268
2316
  if (!currentId) {
2317
+ // No se como guardar los extras aunt
2269
2318
  // It was a new lesson, now it has an ID. Navigate.
2270
2319
  this.#toastService.success({ title: 'Se creó la lección', subtitle: 'Éxito' });
2271
2320
  // The effect should automatically fetch the lesson again after navigation due to paramMap change.
@@ -2361,7 +2410,7 @@ class DCLessonEditorComponent {
2361
2410
  }
2362
2411
  async generateBanner() {
2363
2412
  this.#toastService.info({ title: 'Generando prompt de sugerencia', subtitle: 'Por favor, espera' });
2364
- const prompt = this.#lessonService.getPrompts().banner(this.lesson());
2413
+ const prompt = this.lessonsService.getPrompts().banner(this.lesson());
2365
2414
  const geminiRes = await this.ngxVertexService.generateText([{ role: ChatRoleVertex.User, content: prompt }]);
2366
2415
  this.promptService
2367
2416
  .openPrompt({
@@ -2376,7 +2425,8 @@ class DCLessonEditorComponent {
2376
2425
  this.#loadingBarService.showIndeterminate();
2377
2426
  this.defaultLessonsService.generateBanner(promptResult, this.lessonId()).then((result) => {
2378
2427
  if (result) {
2379
- this.updateLessonProperty('banner', result.banner);
2428
+ alert('Revisar como actualizar el banner');
2429
+ // this.updateLessonProperty('banner', (result as any).banner);
2380
2430
  }
2381
2431
  this.#loadingBarService.successAndHide();
2382
2432
  });
@@ -2394,17 +2444,22 @@ class DCLessonEditorComponent {
2394
2444
  }
2395
2445
  showPrompts() {
2396
2446
  this.promptsVisible = true;
2397
- const promptsFn = this.#lessonService.getPrompts();
2447
+ const promptsFn = this.lessonsService.getPrompts();
2398
2448
  this.prompts = { banner: promptsFn.banner(this.lesson()), content: promptsFn.content(this.lesson()), description: promptsFn.description(this.lesson()) };
2399
2449
  console.log(this.prompts);
2400
2450
  this.cdr.markForCheck();
2401
2451
  }
2402
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DCLessonEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2403
- 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>ID: {{ comp.id }} - Tipo: {{ comp.component }}<button pButton icon=\"pi pi-info\" (click)=\"showComponentDetails(comp)\"></button></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()\" [test]=\"true\"></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<div>\n <h4>Aqui estan los prompts</h4>\n</div>\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$6.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: CropperComponentModal, selector: "dc-cropper-modal", inputs: ["imgStorageSettings", "buttonLabel", "currentStorage"], outputs: ["imageUploaded", "onImageCropped", "onFileSelected"] }, { kind: "component", type: DCLessonRendererComponent, selector: "dc-lesson-renderer", inputs: ["lessonInput", "lessonIdInput", "test"], 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$2.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: i2$5.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
2404
- DCLessonMetadataEditorComponent, selector: "dc-lesson-metadata-editor", inputs: ["lesson", "isLoadingLesson"], outputs: ["saveRequest", "importNotionRequest", "improveNotionRequest"] }, { kind: "ngmodule", type: // Add the metadata editor here
2405
- 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"] }] }); }
2452
+ editComponent(comp) {
2453
+ console.log('Edit component:', comp);
2454
+ this.dynamicComponentsBuilderService.openComponentBuilder(comp.component, comp).onClose.subscribe((result) => {
2455
+ this.onComponentAdded(result);
2456
+ });
2457
+ }
2458
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DCLessonEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2459
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.6", 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<div class=\"p-grid\">\n <div class=\"p-col-4\">\n <assets-loader [assets]=\"lesson()?.assets\" storagePath=\"lessons/{{ lesson()?.id }}\" (assetsChange)=\"onAssetsChange($event)\"></assets-loader>\n </div>\n <div class=\"p-col-4\">\n <h3>Learnable</h3>\n <dc-learnable-viewer [data]=\"lesson()?.learnable\"></dc-learnable-viewer>\n </div>\n <div class=\"p-col-4\">\n <h3>Auditable</h3>\n <dc-auditable-viewer [data]=\"lesson()?.auditable\"></dc-auditable-viewer>\n </div>\n <div class=\"p-col-4\">\n <h3>Manageable</h3>\n <dc-manageable-viewer [data]=\"lesson()?.manageable\"></dc-manageable-viewer>\n </div>\n <div class=\"p-col-4\">\n <h3>Reactions</h3>\n <dc-reactions-viewer [data]=\"lesson()?.reactions\"></dc-reactions-viewer>\n </div>\n\n <div class=\"p-col-4\">\n <h3>Extensions</h3>\n <dc-extensions-viewer [data]=\"lesson()?.extensions\"></dc-extensions-viewer>\n </div>\n</div>\n\n<!-- Lesson Metadata Editor -->\n<!-- <dc-lesson-metadata-editor\n [lesson]=\"lesson\"\n [lessonForm]=\"lessonForm\"\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", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i2$4.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: 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: ReactiveFormsModule }, { kind: "ngmodule", type: SplitterModule }, { kind: "component", type: i5$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: i2$3.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 metadata editor here
2460
+ DialogModule }, { kind: "component", type: i7.Dialog, selector: "p-dialog", inputs: ["header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { 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: DcManageableViewerComponent, selector: "dc-manageable-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"] }] }); }
2406
2461
  }
2407
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DCLessonEditorComponent, decorators: [{
2462
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DCLessonEditorComponent, decorators: [{
2408
2463
  type: Component,
2409
2464
  args: [{ selector: 'dc-lesson-editor', standalone: true, imports: [
2410
2465
  ButtonModule,
@@ -2413,12 +2468,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImpor
2413
2468
  DCLessonRendererComponent,
2414
2469
  FormsModule,
2415
2470
  InputTextModule,
2471
+ ReactiveFormsModule,
2416
2472
  SplitterModule,
2417
2473
  TooltipModule,
2418
2474
  DCLessonComponentAdderComponent, // Add the component adder here
2419
2475
  DCLessonMetadataEditorComponent, // Add the metadata editor here
2420
2476
  DialogModule,
2421
- ], 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>ID: {{ comp.id }} - Tipo: {{ comp.component }}<button pButton icon=\"pi pi-info\" (click)=\"showComponentDetails(comp)\"></button></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()\" [test]=\"true\"></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<div>\n <h4>Aqui estan los prompts</h4>\n</div>\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"] }]
2477
+ DcExtensionsViewerComponent,
2478
+ DcLearnableViewerComponent,
2479
+ DcAuditableViewerComponent,
2480
+ DcManageableViewerComponent,
2481
+ DcReactionsViewerComponent,
2482
+ AssetsLoaderComponent,
2483
+ ], 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<div class=\"p-grid\">\n <div class=\"p-col-4\">\n <assets-loader [assets]=\"lesson()?.assets\" storagePath=\"lessons/{{ lesson()?.id }}\" (assetsChange)=\"onAssetsChange($event)\"></assets-loader>\n </div>\n <div class=\"p-col-4\">\n <h3>Learnable</h3>\n <dc-learnable-viewer [data]=\"lesson()?.learnable\"></dc-learnable-viewer>\n </div>\n <div class=\"p-col-4\">\n <h3>Auditable</h3>\n <dc-auditable-viewer [data]=\"lesson()?.auditable\"></dc-auditable-viewer>\n </div>\n <div class=\"p-col-4\">\n <h3>Manageable</h3>\n <dc-manageable-viewer [data]=\"lesson()?.manageable\"></dc-manageable-viewer>\n </div>\n <div class=\"p-col-4\">\n <h3>Reactions</h3>\n <dc-reactions-viewer [data]=\"lesson()?.reactions\"></dc-reactions-viewer>\n </div>\n\n <div class=\"p-col-4\">\n <h3>Extensions</h3>\n <dc-extensions-viewer [data]=\"lesson()?.extensions\"></dc-extensions-viewer>\n </div>\n</div>\n\n<!-- Lesson Metadata Editor -->\n<!-- <dc-lesson-metadata-editor\n [lesson]=\"lesson\"\n [lessonForm]=\"lessonForm\"\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"] }]
2422
2484
  }], ctorParameters: () => [], propDecorators: { target: [{
2423
2485
  type: ViewChild,
2424
2486
  args: ['target', { read: ViewContainerRef }]
@@ -2432,10 +2494,10 @@ class LessonDynamicComponent {
2432
2494
  constructor() {
2433
2495
  this.settings = {};
2434
2496
  }
2435
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: LessonDynamicComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2436
- 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 }); }
2497
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: LessonDynamicComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2498
+ 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 }); }
2437
2499
  }
2438
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: LessonDynamicComponent, decorators: [{
2500
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: LessonDynamicComponent, decorators: [{
2439
2501
  type: Component,
2440
2502
  args: [{
2441
2503
  selector: 'app-lesson-component',
@@ -2446,6 +2508,269 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImpor
2446
2508
  type: Input
2447
2509
  }] } });
2448
2510
 
2511
+ const Endpoints = {
2512
+ courses: 'api/courses',
2513
+ };
2514
+ class CoursesService {
2515
+ constructor() {
2516
+ this.httpCoreService = inject(HttpCoreService);
2517
+ }
2518
+ // Not sure how to implement this yet.
2519
+ getCourses() {
2520
+ return this.httpCoreService.get(Endpoints.courses);
2521
+ }
2522
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: CoursesService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2523
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: CoursesService, providedIn: 'root' }); }
2524
+ }
2525
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: CoursesService, decorators: [{
2526
+ type: Injectable,
2527
+ args: [{
2528
+ providedIn: 'root',
2529
+ }]
2530
+ }] });
2531
+
2532
+ class CoursesAdminComponent {
2533
+ constructor() {
2534
+ this.httpCoreService = inject(HttpCoreService);
2535
+ }
2536
+ async ngOnInit() {
2537
+ const courses = await this.httpCoreService.get('courses');
2538
+ console.log(courses);
2539
+ }
2540
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: CoursesAdminComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2541
+ 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: [""] }); }
2542
+ }
2543
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: CoursesAdminComponent, decorators: [{
2544
+ type: Component,
2545
+ args: [{ selector: 'ngx-courses-admin', standalone: true, template: "<p>welcome to courses creation</p>\n" }]
2546
+ }] });
2547
+
2548
+ class CourseService extends EntityCommunicationService {
2549
+ constructor() {
2550
+ super('courses');
2551
+ }
2552
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: CourseService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2553
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: CourseService, providedIn: 'root' }); }
2554
+ }
2555
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: CourseService, decorators: [{
2556
+ type: Injectable,
2557
+ args: [{
2558
+ providedIn: 'root',
2559
+ }]
2560
+ }], ctorParameters: () => [] });
2561
+
2562
+ class CourseListComponent extends PaginationBase {
2563
+ constructor() {
2564
+ super(...arguments);
2565
+ // Services
2566
+ this.toastService = inject(TOAST_ALERTS_TOKEN);
2567
+ this.courseService = inject(CourseService);
2568
+ this.cdr = inject(ChangeDetectorRef);
2569
+ // Inputs
2570
+ this.viewType = 'card';
2571
+ this.onlyView = input(true, ...(ngDevMode ? [{ debugName: "onlyView" }] : []));
2572
+ this.onSelect = output();
2573
+ // States
2574
+ this.courses = signal([], ...(ngDevMode ? [{ debugName: "courses" }] : []));
2575
+ this.columns = ['name', 'description', 'updatedAt', 'image'];
2576
+ this.filterBarOptions = { showActions: true, showCreateButton: true, showViewButton: true };
2577
+ }
2578
+ getCustomButtons(item) {
2579
+ return [
2580
+ {
2581
+ tooltipOptions: { tooltipLabel: 'Ver detalles', tooltipPosition: 'bottom' },
2582
+ icon: 'pi pi-eye',
2583
+ command: () => this.doAction({ item, action: 'view' }),
2584
+ },
2585
+ {
2586
+ label: 'Editar',
2587
+ icon: 'pi pi-pencil',
2588
+ command: () => this.doAction({ item, action: 'edit' }),
2589
+ },
2590
+ {
2591
+ label: 'Eliminar',
2592
+ icon: 'pi pi-trash',
2593
+ command: () => this.doAction({ item, action: 'delete' }),
2594
+ },
2595
+ ];
2596
+ }
2597
+ async ngOnInit() {
2598
+ this.filterConfig.returnProps = { _id: 1, id: 1, name: 1, description: 1, updatedAt: 1, image: 1 };
2599
+ this.filterConfig.filters = { targetLang: 'de', baseLang: 'es' };
2600
+ const response = await this.courseService.query(this.filterConfig);
2601
+ this.courses.set(response.rows);
2602
+ this.cdr.detectChanges();
2603
+ console.log(this.courses(), this.viewType);
2604
+ this.cdr.detectChanges();
2605
+ }
2606
+ loadData() {
2607
+ throw new Error('Method not implemented.');
2608
+ }
2609
+ onNew() {
2610
+ console.log('onNew');
2611
+ this.router.navigate(['./edit'], { relativeTo: this.route });
2612
+ }
2613
+ toggleView() {
2614
+ this.viewType = this.viewType === 'card' ? 'table' : 'card';
2615
+ console.log(this.viewType, this.courses());
2616
+ this.cdr.detectChanges();
2617
+ }
2618
+ selectItem(course) {
2619
+ console.log('onSelect');
2620
+ this.onSelect.emit(course);
2621
+ }
2622
+ async doAction(actionEvent) {
2623
+ const { item, action } = actionEvent;
2624
+ if (action == 'changeView') {
2625
+ this.toggleView();
2626
+ }
2627
+ const id = item.id || item._id;
2628
+ switch (action) {
2629
+ case 'view':
2630
+ this.router.navigate(['./details', id], { relativeTo: this.route });
2631
+ break;
2632
+ case 'delete':
2633
+ const areYouSure = confirm('¿Estás seguro de querer eliminar este origen?');
2634
+ if (areYouSure) {
2635
+ await this.courseService.remove(id);
2636
+ this.courses.set(this.courses().filter((course) => course._id !== id));
2637
+ this.toastService.success({
2638
+ title: 'Origen eliminado',
2639
+ subtitle: 'El origen ha sido eliminado correctamente',
2640
+ });
2641
+ this.cdr.detectChanges();
2642
+ }
2643
+ break;
2644
+ case 'edit':
2645
+ this.router.navigate(['./edit', id], { relativeTo: this.route });
2646
+ break;
2647
+ }
2648
+ }
2649
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: CourseListComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
2650
+ 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\n />\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 [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", "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$2.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: "pipe", type: DatePipe, name: "date" }, { kind: "pipe", type: SlicePipe, name: "slice" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2651
+ }
2652
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: CourseListComponent, decorators: [{
2653
+ type: Component,
2654
+ args: [{ selector: 'app-course-list', imports: [
2655
+ CardModule,
2656
+ ButtonModule,
2657
+ DCFilterBarComponent,
2658
+ SpeedDialModule,
2659
+ DatePipe,
2660
+ SlicePipe,
2661
+ PaginatorModule,
2662
+ RouterModule,
2663
+ TableModule,
2664
+ QuickTableComponent,
2665
+ ], 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\n />\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 [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"] }]
2666
+ }], propDecorators: { viewType: [{
2667
+ type: Input
2668
+ }] } });
2669
+
2670
+ class CourseDetailComponent {
2671
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: CourseDetailComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2672
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.6", 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 }); }
2673
+ }
2674
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: CourseDetailComponent, decorators: [{
2675
+ type: Component,
2676
+ args: [{ selector: 'app-course-detail', imports: [], template: `<p>course-detail works!</p>`, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block}\n"] }]
2677
+ }] });
2678
+
2679
+ class CourseFormComponent extends EntityBaseFormComponent {
2680
+ constructor() {
2681
+ super(...arguments);
2682
+ this.entityCommunicationService = inject(CourseService);
2683
+ this.fb = inject(FormBuilder);
2684
+ this.languageOptions = getSupportedLanguageOptions('en');
2685
+ this.form = this.fb.group({
2686
+ name: ['', Validators.required],
2687
+ description: [''],
2688
+ image: [{}],
2689
+ targetLang: ['', Validators.required],
2690
+ baseLang: ['', Validators.required],
2691
+ });
2692
+ this.onSave = output();
2693
+ this.storageImgSettings = {
2694
+ path: `courses`,
2695
+ cropSettings: { aspectRatio: AspectType.Square, resolutions: [ResolutionType.MediumLarge], resizeToWidth: 700 },
2696
+ };
2697
+ this.extraFields = [
2698
+ { key: 'title', type: 'input', props: { label: 'Title', placeholder: 'Title', required: false } },
2699
+ { key: 'content', type: 'textarea', props: { label: 'Content', placeholder: 'Content', required: false } },
2700
+ ];
2701
+ }
2702
+ patchForm(entity) {
2703
+ this.form.patchValue(entity);
2704
+ }
2705
+ async save() {
2706
+ const result = await super.save();
2707
+ if (result) {
2708
+ this.onSave.emit(result);
2709
+ if (this.toastService) {
2710
+ this.toastService.success({ title: 'Course', subtitle: 'Data was saved' });
2711
+ }
2712
+ }
2713
+ return result;
2714
+ }
2715
+ handleImageUpload(event) {
2716
+ this.form.patchValue({ image: event });
2717
+ }
2718
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: CourseFormComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
2719
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.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 style=\"display: flex; justify-content: flex-end\">\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: i3$1.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: i2$3.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 }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2720
+ }
2721
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: CourseFormComponent, decorators: [{
2722
+ type: Component,
2723
+ args: [{ selector: 'app-source-form', imports: [
2724
+ ReactiveFormsModule,
2725
+ CardModule,
2726
+ TextareaModule,
2727
+ ButtonModule,
2728
+ SelectModule,
2729
+ InputTextModule,
2730
+ ChipModule,
2731
+ TooltipModule,
2732
+ CropperComponentModal,
2733
+ FormlyModule,
2734
+ DialogModule,
2735
+ CourseListComponent,
2736
+ ], 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 style=\"display: flex; justify-content: flex-end\">\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"] }]
2737
+ }] });
2738
+
2739
+ const COURSES_ROUTES = [
2740
+ {
2741
+ path: '',
2742
+ component: CoursesComponent,
2743
+ children: [
2744
+ {
2745
+ path: '',
2746
+ component: CourseListComponent,
2747
+ },
2748
+ {
2749
+ path: 'details/:id',
2750
+ component: CourseDetailComponent,
2751
+ },
2752
+ {
2753
+ path: 'edit',
2754
+ component: CourseFormComponent,
2755
+ },
2756
+ {
2757
+ path: 'edit/:id',
2758
+ component: CourseFormComponent,
2759
+ },
2760
+ ],
2761
+ },
2762
+ ];
2763
+
2764
+ class CoursesComponent {
2765
+ static { this.routes = COURSES_ROUTES; }
2766
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: CoursesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2767
+ 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$3.RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2768
+ }
2769
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: CoursesComponent, decorators: [{
2770
+ type: Component,
2771
+ args: [{ selector: 'app-courses', imports: [RouterModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<router-outlet />\n", styles: [":host{display:block;height:100%}\n"] }]
2772
+ }] });
2773
+
2449
2774
  /*
2450
2775
  * Public API Surface of lessons
2451
2776
  */
@@ -2454,5 +2779,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImpor
2454
2779
  * Generated bundle index. Do not edit.
2455
2780
  */
2456
2781
 
2457
- export { ComponentBuilder, ComponentWithForm, DCLessonEditorComponent, DCLessonFormComponent, DCLessonListComponent, DCLessonRendererComponent, DcLessonCardComponent, DefaultLessonsService, 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 };
2782
+ 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, NOTION_SERVICE_TOKEN, NotionAbstractService, NotionExportType, SelectorBuilderComponent, SelectorComponent, TextWriterBuiderComponent, TextWriterComponent, TranslationSwitcherBuilderComponent, TranslationSwitcherComponent, getLanguageSimpleAgent, getLessonComponentClass, provideLessonsService, provideNotionService };
2458
2783
  //# sourceMappingURL=dataclouder-ngx-lessons.mjs.map