@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.
- package/fesm2022/dataclouder-ngx-lessons.mjs +1131 -806
- package/fesm2022/dataclouder-ngx-lessons.mjs.map +1 -1
- package/index.d.ts +643 -5
- package/package.json +1 -1
- package/lib/components/dc-lessons/dc-lesson-card/dc-lesson-card.component.d.ts +0 -25
- package/lib/components/dc-lessons/dc-lesson-component-adder/dc-lesson-component-adder.component.d.ts +0 -11
- package/lib/components/dc-lessons/dc-lesson-editor/dc-lesson-editor.component.d.ts +0 -65
- package/lib/components/dc-lessons/dc-lesson-metadata-editor/dc-lesson-metadata-editor.component.d.ts +0 -43
- package/lib/components/dc-lessons/dc-lesson-renderer/dc-lesson-renderer.component.d.ts +0 -45
- package/lib/components/dc-lessons/dc-lesson-renderer/eval-agents-skills.d.ts +0 -1
- package/lib/components/dc-lessons/lesson-form/lesson-form.component.d.ts +0 -5
- package/lib/components/dc-lessons/lesson-list/dc-lesson-list.component.d.ts +0 -40
- package/lib/components/lesson-mini-components/components/ComponentBuilder.d.ts +0 -31
- package/lib/components/lesson-mini-components/components/ComponentWithForm.d.ts +0 -12
- package/lib/components/lesson-mini-components/components/lesson-dynamic.component.d.ts +0 -7
- package/lib/components/lesson-mini-components/components/lessons.clases.d.ts +0 -169
- package/lib/components/lesson-mini-components/components/selector/selector-builder/selector-builder.component.d.ts +0 -19
- package/lib/components/lesson-mini-components/components/selector/selector.component.d.ts +0 -12
- package/lib/components/lesson-mini-components/components/speaker/speaker-builder/speaker-builder.component.d.ts +0 -13
- package/lib/components/lesson-mini-components/components/speaker/speaker.component.d.ts +0 -12
- package/lib/components/lesson-mini-components/components/text-writer/text-writer-buider/text-writer-buider.component.d.ts +0 -14
- package/lib/components/lesson-mini-components/components/text-writer/text-writer.component.d.ts +0 -16
- package/lib/components/lesson-mini-components/components/translationSwitcher/translationSwitcher.component.d.ts +0 -11
- package/lib/components/lesson-mini-components/components/translationSwitcher/translationSwitcherBuilder/translationSwitcherBuilder.component.d.ts +0 -13
- package/lib/models/lessons.pipes.d.ts +0 -12
- package/lib/models/notion.models.d.ts +0 -41
- package/lib/models/simple-agents.d.ts +0 -2
- package/lib/services/default-lessons.service.d.ts +0 -20
- package/lib/services/lesson-ai.service.d.ts +0 -31
- package/lib/services/lesson-notion.service.d.ts +0 -35
- package/lib/services/lesson-utils.service.d.ts +0 -56
- package/public-api.d.ts +0 -19
|
@@ -1,68 +1,242 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import {
|
|
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,
|
|
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
|
|
10
|
-
import {
|
|
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/
|
|
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 {
|
|
17
|
-
import
|
|
18
|
-
import
|
|
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$
|
|
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$
|
|
32
|
+
import * as i3$2 from '@ckeditor/ckeditor5-angular';
|
|
36
33
|
import { CKEditorModule } from '@ckeditor/ckeditor5-angular';
|
|
37
|
-
import * as i5$
|
|
34
|
+
import * as i5$1 from 'primeng/splitter';
|
|
38
35
|
import { SplitterModule } from 'primeng/splitter';
|
|
39
|
-
import * as i2$
|
|
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$
|
|
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
|
|
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
|
|
54
|
-
import
|
|
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(
|
|
58
|
-
this.formBuilder =
|
|
59
|
-
this.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:
|
|
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.
|
|
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
|
-
|
|
101
|
-
|
|
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: "
|
|
111
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "
|
|
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: "
|
|
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
|
-
}],
|
|
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: "
|
|
135
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "
|
|
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: "
|
|
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: "
|
|
286
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "
|
|
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: "
|
|
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(
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
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: "
|
|
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
|
-
}]
|
|
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: "
|
|
330
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "
|
|
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: "
|
|
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.
|
|
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: "
|
|
364
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "
|
|
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: "
|
|
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,
|
|
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: "
|
|
389
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "
|
|
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: "
|
|
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
|
-
|
|
401
|
-
(
|
|
402
|
-
|
|
403
|
-
|
|
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
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
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
|
|
504
|
-
|
|
491
|
+
else {
|
|
492
|
+
result = this.control.value?.toLowerCase().trim() === this.config.settings.response.toLowerCase().trim();
|
|
505
493
|
}
|
|
506
|
-
|
|
507
|
-
|
|
494
|
+
if (result) {
|
|
495
|
+
this.status = 'success';
|
|
508
496
|
}
|
|
509
497
|
else {
|
|
510
|
-
|
|
498
|
+
this.status = 'danger';
|
|
511
499
|
}
|
|
500
|
+
this.isFilled = true;
|
|
501
|
+
return result;
|
|
512
502
|
}
|
|
513
|
-
|
|
514
|
-
|
|
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: "
|
|
517
|
-
type:
|
|
518
|
-
args: [{
|
|
519
|
-
|
|
520
|
-
|
|
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
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
646
|
-
|
|
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
|
-
|
|
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: "
|
|
689
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
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: "
|
|
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(/ /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
|
-
|
|
710
|
-
{
|
|
711
|
-
|
|
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
|
-
|
|
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
|
-
|
|
771
|
+
// Private properties
|
|
729
772
|
this.cardEventSubs = [];
|
|
730
|
-
this.
|
|
731
|
-
|
|
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
|
-
|
|
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
|
-
|
|
751
|
-
this.
|
|
752
|
-
this.cardEventSubs = [];
|
|
790
|
+
ngAfterViewInit() {
|
|
791
|
+
this.outlets.changes.subscribe(() => this.subscribeToCardEvents());
|
|
753
792
|
}
|
|
754
793
|
ngOnDestroy() {
|
|
755
|
-
this.
|
|
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
|
-
|
|
776
|
-
|
|
777
|
-
|
|
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
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
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
|
|
793
|
-
this.
|
|
811
|
+
if (filterEvent.action === 'changeView') {
|
|
812
|
+
this.toggleView();
|
|
794
813
|
return;
|
|
795
814
|
}
|
|
796
|
-
|
|
797
|
-
|
|
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
|
-
|
|
804
|
-
|
|
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
|
-
|
|
807
|
-
|
|
808
|
-
this.
|
|
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
|
-
|
|
811
|
-
|
|
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: "
|
|
815
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
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: "
|
|
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,
|
|
820
|
-
}], ctorParameters: () => [
|
|
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: "
|
|
841
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "
|
|
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: "
|
|
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.
|
|
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.
|
|
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
|
|
936
|
-
|
|
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
|
-
|
|
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: "
|
|
962
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
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: "
|
|
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
|
-
//
|
|
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.
|
|
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
|
-
// ---
|
|
1053
|
+
// --- Services ---
|
|
1007
1054
|
this.renderer = inject(Renderer2);
|
|
1008
1055
|
this.viewContainerRef = inject(ViewContainerRef);
|
|
1009
1056
|
this.toastrService = inject(TOAST_ALERTS_TOKEN);
|
|
1010
|
-
this.
|
|
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
|
-
|
|
1060
|
+
this.dynamicComponentsService = inject(DynamicComponentsService);
|
|
1061
|
+
this.uiStateService = inject(UiStateService);
|
|
1014
1062
|
// --- State Signals ---
|
|
1015
|
-
this.lesson = signal(undefined); // Internal lesson state signal
|
|
1016
|
-
|
|
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.
|
|
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 =
|
|
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.
|
|
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.
|
|
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
|
|
1297
|
-
this.
|
|
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: "
|
|
1315
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
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: "
|
|
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(
|
|
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
|
|
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
|
-
|
|
1371
|
-
...(lesson.
|
|
1372
|
-
|
|
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
|
|
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
|
|
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
|
|
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: "
|
|
1486
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
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: "
|
|
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
|
|
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
|
|
1622
|
+
const assets = { ...(currentLesson.assets ?? {}) };
|
|
1623
|
+
assets.banner = imageUploaded;
|
|
1526
1624
|
return {
|
|
1527
1625
|
...currentLesson,
|
|
1528
|
-
|
|
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
|
|
1644
|
+
await this.lessonsService.postGenerateByAI(lessonId);
|
|
1547
1645
|
// Re-fetch the lesson data to get AI updates
|
|
1548
|
-
const updatedLesson = await this
|
|
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
|
|
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
|
|
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: "
|
|
1739
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
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: "
|
|
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.#
|
|
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
|
-
#
|
|
1759
|
-
|
|
1760
|
-
// Moved logic from DCLessonEditorComponent
|
|
1888
|
+
#dynamicComponentsBuilderService;
|
|
1889
|
+
// Logic to open component builder, now utilizing DynamicComponentsBuilderService
|
|
1761
1890
|
openComponentBuilder(type) {
|
|
1762
|
-
const
|
|
1763
|
-
if (
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
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: "
|
|
1782
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "
|
|
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: "
|
|
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
|
|
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
|
-
|
|
1825
|
-
|
|
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.
|
|
1850
|
-
return { ...current,
|
|
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
|
|
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
|
|
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
|
-
|
|
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: "
|
|
1984
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
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" }
|
|
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: "
|
|
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
|
|
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(/ /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
|
|
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
|
|
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?.
|
|
2151
|
-
return currentLesson.
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
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: "
|
|
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
|
-
|
|
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: "
|
|
2436
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "
|
|
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: "
|
|
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,
|
|
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
|