@dataclouder/ngx-lessons 0.0.31 → 0.0.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +56 -10
- package/fesm2022/dataclouder-ngx-lessons.mjs +292 -81
- package/fesm2022/dataclouder-ngx-lessons.mjs.map +1 -1
- package/lib/components/dc-lessons/dc-lesson-editor/dc-lesson-editor.component.d.ts +9 -5
- package/lib/components/dc-lessons/dc-lesson-renderer/dc-lesson-renderer.component.d.ts +3 -1
- package/lib/components/lesson-mini-components/components/lessons.clases.d.ts +1 -0
- package/lib/models/simple-agents.d.ts +2 -0
- package/lib/services/lesson-ai.service.d.ts +15 -2
- package/lib/services/lesson-utils.service.d.ts +10 -1
- package/package.json +1 -1
- package/public-api.d.ts +1 -0
- package/src/lib/components/dc-lessons/dc-lesson-card/dc-lesson-card.component.html +0 -40
- package/src/lib/components/dc-lessons/dc-lesson-card/dc-lesson-card.component.scss +0 -120
- package/src/lib/components/dc-lessons/dc-lesson-card/dc-lesson-card.component.ts +0 -82
- package/src/lib/components/dc-lessons/dc-lesson-component-adder/dc-lesson-component-adder.component.css +0 -1
- package/src/lib/components/dc-lessons/dc-lesson-component-adder/dc-lesson-component-adder.component.html +0 -46
- package/src/lib/components/dc-lessons/dc-lesson-component-adder/dc-lesson-component-adder.component.ts +0 -52
- package/src/lib/components/dc-lessons/dc-lesson-editor/dc-lesson-editor.component.css +0 -90
- package/src/lib/components/dc-lessons/dc-lesson-editor/dc-lesson-editor.component.html +0 -67
- package/src/lib/components/dc-lessons/dc-lesson-editor/dc-lesson-editor.component.scss +0 -0
- package/src/lib/components/dc-lessons/dc-lesson-editor/dc-lesson-editor.component.ts +0 -356
- package/src/lib/components/dc-lessons/dc-lesson-metadata-editor/dc-lesson-metadata-editor.component.css +0 -1
- package/src/lib/components/dc-lessons/dc-lesson-metadata-editor/dc-lesson-metadata-editor.component.html +0 -72
- package/src/lib/components/dc-lessons/dc-lesson-metadata-editor/dc-lesson-metadata-editor.component.ts +0 -60
- package/src/lib/components/dc-lessons/dc-lesson-renderer/dc-lesson-renderer.component.html +0 -23
- package/src/lib/components/dc-lessons/dc-lesson-renderer/dc-lesson-renderer.component.scss +0 -3
- package/src/lib/components/dc-lessons/dc-lesson-renderer/dc-lesson-renderer.component.ts +0 -332
- package/src/lib/components/dc-lessons/lesson-form/lesson-form.component.html +0 -5
- package/src/lib/components/dc-lessons/lesson-form/lesson-form.component.scss +0 -3
- package/src/lib/components/dc-lessons/lesson-form/lesson-form.component.ts +0 -14
- package/src/lib/components/dc-lessons/lesson-list/dc-lesson-list.component.html +0 -30
- package/src/lib/components/dc-lessons/lesson-list/dc-lesson-list.component.scss +0 -17
- package/src/lib/components/dc-lessons/lesson-list/dc-lesson-list.component.ts +0 -170
- package/src/lib/components/dc-lessons/lessons.component.ts +0 -10
- package/src/lib/components/lesson-mini-components/components/ComponentBuilder.ts +0 -82
- package/src/lib/components/lesson-mini-components/components/ComponentWithForm.ts +0 -25
- package/src/lib/components/lesson-mini-components/components/lesson-dynamic.component.ts +0 -13
- package/src/lib/components/lesson-mini-components/components/lessons.clases.ts +0 -220
- package/src/lib/components/lesson-mini-components/components/selector/selector-builder/selector-builder.component.html +0 -62
- package/src/lib/components/lesson-mini-components/components/selector/selector-builder/selector-builder.component.scss +0 -15
- package/src/lib/components/lesson-mini-components/components/selector/selector-builder/selector-builder.component.ts +0 -70
- package/src/lib/components/lesson-mini-components/components/selector/selector.component.html +0 -1
- package/src/lib/components/lesson-mini-components/components/selector/selector.component.scss +0 -12
- package/src/lib/components/lesson-mini-components/components/selector/selector.component.spec.ts +0 -25
- package/src/lib/components/lesson-mini-components/components/selector/selector.component.ts +0 -47
- package/src/lib/components/lesson-mini-components/components/speaker/speaker-builder/speaker-builder.component.html +0 -13
- package/src/lib/components/lesson-mini-components/components/speaker/speaker-builder/speaker-builder.component.scss +0 -0
- package/src/lib/components/lesson-mini-components/components/speaker/speaker-builder/speaker-builder.component.ts +0 -40
- package/src/lib/components/lesson-mini-components/components/speaker/speaker.component.html +0 -9
- package/src/lib/components/lesson-mini-components/components/speaker/speaker.component.scss +0 -3
- package/src/lib/components/lesson-mini-components/components/speaker/speaker.component.ts +0 -33
- package/src/lib/components/lesson-mini-components/components/text-writer/text-writer-buider/text-writer-buider.component.html +0 -24
- package/src/lib/components/lesson-mini-components/components/text-writer/text-writer-buider/text-writer-buider.component.scss +0 -15
- package/src/lib/components/lesson-mini-components/components/text-writer/text-writer-buider/text-writer-buider.component.spec.ts +0 -25
- package/src/lib/components/lesson-mini-components/components/text-writer/text-writer-buider/text-writer-buider.component.ts +0 -29
- package/src/lib/components/lesson-mini-components/components/text-writer/text-writer.component.html +0 -4
- package/src/lib/components/lesson-mini-components/components/text-writer/text-writer.component.scss +0 -8
- package/src/lib/components/lesson-mini-components/components/text-writer/text-writer.component.spec.ts +0 -25
- package/src/lib/components/lesson-mini-components/components/text-writer/text-writer.component.ts +0 -61
- package/src/lib/components/lesson-mini-components/components/translationSwitcher/translationSwitcher.component.css +0 -3
- package/src/lib/components/lesson-mini-components/components/translationSwitcher/translationSwitcher.component.html +0 -9
- package/src/lib/components/lesson-mini-components/components/translationSwitcher/translationSwitcher.component.ts +0 -32
- package/src/lib/components/lesson-mini-components/components/translationSwitcher/translationSwitcherBuilder/translationSwitcherBuilder.component.css +0 -3
- package/src/lib/components/lesson-mini-components/components/translationSwitcher/translationSwitcherBuilder/translationSwitcherBuilder.component.html +0 -28
- package/src/lib/components/lesson-mini-components/components/translationSwitcher/translationSwitcherBuilder/translationSwitcherBuilder.component.ts +0 -30
- package/src/lib/components/lesson-mini-components/components/verb-summary/verb-summary-builder/verb-summary-builder.component.html +0 -18
- package/src/lib/components/lesson-mini-components/components/verb-summary/verb-summary-builder/verb-summary-builder.component.scss +0 -3
- package/src/lib/components/lesson-mini-components/components/verb-summary/verb-summary-builder/verb-summary-builder.component.spec.ts +0 -25
- package/src/lib/components/lesson-mini-components/components/verb-summary/verb-summary-builder/verb-summary-builder.component.ts +0 -25
- package/src/lib/components/lesson-mini-components/components/verb-summary/verb-summary.component.html +0 -15
- package/src/lib/components/lesson-mini-components/components/verb-summary/verb-summary.component.scss +0 -27
- package/src/lib/components/lesson-mini-components/components/verb-summary/verb-summary.component.spec.ts +0 -25
- package/src/lib/components/lesson-mini-components/components/verb-summary/verb-summary.component.ts +0 -46
- package/src/lib/components/lesson-mini-components/components/word-summary/word-summary-builder/word-summary-builder.component.html +0 -19
- package/src/lib/components/lesson-mini-components/components/word-summary/word-summary-builder/word-summary-builder.component.scss +0 -0
- package/src/lib/components/lesson-mini-components/components/word-summary/word-summary-builder/word-summary-builder.component.ts +0 -27
- package/src/lib/components/lesson-mini-components/components/word-summary/word-summary.component.html +0 -14
- package/src/lib/components/lesson-mini-components/components/word-summary/word-summary.component.scss +0 -22
- package/src/lib/components/lesson-mini-components/components/word-summary/word-summary.component.ts +0 -51
- package/src/lib/models/lessons.pipes.ts +0 -38
- package/src/lib/models/models.ts +0 -92
- package/src/lib/models/notion.models.ts +0 -43
- package/src/lib/services/lesson-ai.service.ts +0 -103
- package/src/lib/services/lesson-notion.service.ts +0 -161
- package/src/lib/services/lesson-utils.service.ts +0 -181
- package/src/public-api.ts +0 -25
|
@@ -1,356 +0,0 @@
|
|
|
1
|
-
import { Component, ComponentRef, ElementRef, computed, effect, inject, signal, ViewChild, ViewContainerRef } from '@angular/core';
|
|
2
|
-
import { ActivatedRoute, Router, ParamMap } from '@angular/router';
|
|
3
|
-
import { toSignal } from '@angular/core/rxjs-interop';
|
|
4
|
-
import { FormsModule } from '@angular/forms';
|
|
5
|
-
import { map } from 'rxjs';
|
|
6
|
-
|
|
7
|
-
import BalloonEditor from '@ckeditor/ckeditor5-build-balloon-block';
|
|
8
|
-
import { CKEditorModule } from '@ckeditor/ckeditor5-angular';
|
|
9
|
-
// PrimeNG
|
|
10
|
-
// Removed DialogService, DynamicDialogRef, SpeedDialModule, MenuItem
|
|
11
|
-
import { ButtonModule } from 'primeng/button';
|
|
12
|
-
import { InputTextModule } from 'primeng/inputtext';
|
|
13
|
-
import { SplitterModule } from 'primeng/splitter';
|
|
14
|
-
import { TooltipModule } from 'primeng/tooltip';
|
|
15
|
-
// Dataclouder
|
|
16
|
-
import { AspectType, CropperComponentModal, ResolutionType, StorageImageSettings } from '@dataclouder/ngx-cloud-storage';
|
|
17
|
-
import { TOAST_ALERTS_TOKEN, ToastAlertsAbstractService } from '@dataclouder/ngx-core';
|
|
18
|
-
|
|
19
|
-
import { DCLessonRendererComponent } from '../dc-lesson-renderer/dc-lesson-renderer.component';
|
|
20
|
-
// Added DynamicContentComponent to the import below
|
|
21
|
-
import {
|
|
22
|
-
LessonComponentEnum,
|
|
23
|
-
LessonImage,
|
|
24
|
-
ILesson,
|
|
25
|
-
LessonComponentInterface,
|
|
26
|
-
LESSONS_TOKEN,
|
|
27
|
-
DynamicContentComponent,
|
|
28
|
-
LessonComponentConfiguration,
|
|
29
|
-
} from '../../lesson-mini-components/components/lessons.clases';
|
|
30
|
-
import { LessonComponentBuilders } from '../../lesson-mini-components/components/lessons.clases';
|
|
31
|
-
import { FlagLanguagePipe, LangDescTranslationPipe } from '../../../models/lessons.pipes';
|
|
32
|
-
// Notion types might still be needed if passed/returned, but token injection removed
|
|
33
|
-
import { NotionExportType } from '../../../models/notion.models';
|
|
34
|
-
// Removed MenuItem import
|
|
35
|
-
import { LessonNotionService } from '../../../services/lesson-notion.service';
|
|
36
|
-
import { LessonUtilsService } from '../../../services/lesson-utils.service'; // Import the new utils service
|
|
37
|
-
import { DCLessonComponentAdderComponent } from '../dc-lesson-component-adder/dc-lesson-component-adder.component'; // Import the component adder
|
|
38
|
-
import { DCLessonMetadataEditorComponent } from '../dc-lesson-metadata-editor/dc-lesson-metadata-editor.component'; // Import the metadata editor
|
|
39
|
-
import { ComponentBuildData } from '../../lesson-mini-components/components/ComponentBuilder';
|
|
40
|
-
import { JsonPipe } from '@angular/common';
|
|
41
|
-
|
|
42
|
-
const GradientCss = 'linear-gradient(to bottom,var(--primary-color), rgba(213, 238, 239, 0.31))';
|
|
43
|
-
|
|
44
|
-
@Component({
|
|
45
|
-
selector: 'dc-lesson-editor',
|
|
46
|
-
templateUrl: './dc-lesson-editor.component.html',
|
|
47
|
-
styleUrls: ['./dc-lesson-editor.component.css'],
|
|
48
|
-
standalone: true,
|
|
49
|
-
imports: [
|
|
50
|
-
ButtonModule,
|
|
51
|
-
CKEditorModule,
|
|
52
|
-
CropperComponentModal,
|
|
53
|
-
DCLessonRendererComponent,
|
|
54
|
-
FormsModule,
|
|
55
|
-
InputTextModule,
|
|
56
|
-
SplitterModule,
|
|
57
|
-
TooltipModule,
|
|
58
|
-
// Removed SpeedDialModule
|
|
59
|
-
DCLessonComponentAdderComponent, // Add the component adder here
|
|
60
|
-
DCLessonMetadataEditorComponent, // Add the metadata editor here
|
|
61
|
-
JsonPipe,
|
|
62
|
-
],
|
|
63
|
-
providers: [LessonNotionService], // Provide the service here
|
|
64
|
-
})
|
|
65
|
-
export class DCLessonEditorComponent {
|
|
66
|
-
// Services
|
|
67
|
-
#activatedRoute = inject(ActivatedRoute); // Re-inject as it's needed for navigation
|
|
68
|
-
#lessonNotionService = inject(LessonNotionService);
|
|
69
|
-
#lessonUtilsService = inject(LessonUtilsService);
|
|
70
|
-
#router = inject(Router);
|
|
71
|
-
// Removed #dialogService injection
|
|
72
|
-
#lessonService = inject(LESSONS_TOKEN);
|
|
73
|
-
#toastService = inject(TOAST_ALERTS_TOKEN);
|
|
74
|
-
// ViewChild
|
|
75
|
-
@ViewChild('target', { read: ViewContainerRef }) target: ViewContainerRef;
|
|
76
|
-
@ViewChild('dhtml', { static: true }) dhtml: ElementRef;
|
|
77
|
-
// Signals States
|
|
78
|
-
readonly lessonId = toSignal(inject(ActivatedRoute).paramMap.pipe(map((params: ParamMap) => params.get('id'))));
|
|
79
|
-
lesson = signal<ILesson | undefined>(undefined); // Initialize as undefined
|
|
80
|
-
isCropperVisible = signal(false);
|
|
81
|
-
isLoadingLesson = signal(false);
|
|
82
|
-
// Removed items signal
|
|
83
|
-
// Computed Signals
|
|
84
|
-
coverBackground = computed(() => {
|
|
85
|
-
const currentLesson = this.lesson();
|
|
86
|
-
const coverImage = currentLesson?.media?.images?.find((img: any) => img.type === 'cover') as LessonImage | undefined;
|
|
87
|
-
const imageUrl = coverImage?.url || '/assets/images/default_banner.webp';
|
|
88
|
-
return `${GradientCss}, url("${imageUrl}")`;
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
// Computed signal to get dynamic components as an array for easier iteration in the template
|
|
92
|
-
readonly dynamicComponentsArray = computed(() => {
|
|
93
|
-
const currentLesson = this.lesson();
|
|
94
|
-
if (currentLesson?.dynamicComponents) {
|
|
95
|
-
return Object.values(currentLesson.dynamicComponents);
|
|
96
|
-
}
|
|
97
|
-
return []; // Return empty array if no lesson or no dynamic components
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
// States
|
|
101
|
-
public components: { [key: string]: ComponentRef<LessonComponentInterface> } = {}; // Current Dynamic components
|
|
102
|
-
public editor = BalloonEditor;
|
|
103
|
-
public lessonComponentEnum = LessonComponentEnum;
|
|
104
|
-
|
|
105
|
-
public coverStorageSettings: StorageImageSettings = {
|
|
106
|
-
path: 'lessons/covers',
|
|
107
|
-
fileName: 'cover',
|
|
108
|
-
cropSettings: { resizeToWidth: 850, aspectRatio: AspectType.RectangleLarge, resolutions: [ResolutionType.Medium] },
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
constructor() {
|
|
112
|
-
// Removed Speed Dial Items initialization
|
|
113
|
-
|
|
114
|
-
// Effect to fetch lesson data when ID changes
|
|
115
|
-
effect(async () => {
|
|
116
|
-
const id = this.lessonId();
|
|
117
|
-
console.log('Lesson ID Signal:', id);
|
|
118
|
-
if (id) {
|
|
119
|
-
this.isLoadingLesson.set(true); // Start loading
|
|
120
|
-
try {
|
|
121
|
-
const fetchedLesson = await this.#lessonService.getLesson(id);
|
|
122
|
-
if (fetchedLesson) {
|
|
123
|
-
this.lesson.set(fetchedLesson);
|
|
124
|
-
} else {
|
|
125
|
-
this.lesson.set(undefined); // Reset if not found
|
|
126
|
-
this.#toastService.warn({ title: 'No se encontró la lección', subtitle: 'Quizá el id es incorrecto' });
|
|
127
|
-
// Optional: Navigate away or show a specific "not found" state
|
|
128
|
-
// this.#router.navigate(['/path/to/lessons']);
|
|
129
|
-
}
|
|
130
|
-
} catch (error) {
|
|
131
|
-
console.error('Error fetching lesson:', error);
|
|
132
|
-
this.lesson.set(undefined); // Reset on error
|
|
133
|
-
this.#toastService.error({ title: 'Error al cargar la lección', subtitle: 'Intenta de nuevo más tarde' });
|
|
134
|
-
} finally {
|
|
135
|
-
this.isLoadingLesson.set(false); // Stop loading
|
|
136
|
-
}
|
|
137
|
-
} else {
|
|
138
|
-
// Handle case for new lesson (ID is null/undefined)
|
|
139
|
-
this.lesson.set({ textCoded: `<h1>Nueva lección </h1> <p> Texto aquí</p>`, tags: [] } as ILesson); // Set default new lesson structure
|
|
140
|
-
this.isLoadingLesson.set(false); // Ensure loading is off
|
|
141
|
-
}
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Updates a specific property on the lesson signal.
|
|
147
|
-
* Used for ngModelChange events to simulate two-way binding with signals.
|
|
148
|
-
* @param property The key of the ILesson property to update.
|
|
149
|
-
* @param value The new value for the property.
|
|
150
|
-
*/
|
|
151
|
-
public updateLessonProperty<K extends keyof ILesson>(property: K, value: ILesson[K]): void {
|
|
152
|
-
this.lesson.update((currentLesson) => {
|
|
153
|
-
if (!currentLesson) return undefined;
|
|
154
|
-
return { ...currentLesson, [property]: value };
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
public onTagRemove(tag: any): void {
|
|
159
|
-
this.lesson.update((currentLesson) => {
|
|
160
|
-
if (!currentLesson) return undefined;
|
|
161
|
-
const updatedTags = currentLesson.tags.filter((text: string) => text !== tag.text);
|
|
162
|
-
return { ...currentLesson, tags: updatedTags };
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
public onTagAdd(tag: { value: string; input: any }): void {
|
|
167
|
-
if (tag.value) {
|
|
168
|
-
this.lesson.update((currentLesson) => {
|
|
169
|
-
if (!currentLesson) return undefined;
|
|
170
|
-
// Avoid duplicate tags if necessary
|
|
171
|
-
if (currentLesson.tags.includes(tag.value)) {
|
|
172
|
-
return currentLesson;
|
|
173
|
-
}
|
|
174
|
-
const updatedTags = [...currentLesson.tags, tag.value];
|
|
175
|
-
return { ...currentLesson, tags: updatedTags };
|
|
176
|
-
});
|
|
177
|
-
}
|
|
178
|
-
tag.input.nativeElement.value = ''; // Clear input
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
public async saveLesson(event?: Event): Promise<ILesson | undefined> {
|
|
182
|
-
event?.preventDefault();
|
|
183
|
-
|
|
184
|
-
const currentLesson = this.lesson();
|
|
185
|
-
if (!currentLesson) {
|
|
186
|
-
this.#toastService.error({ title: 'Error', subtitle: 'No hay datos de lección para guardar' });
|
|
187
|
-
return undefined;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// Clean orphaned components before saving
|
|
191
|
-
const lessonToSave = this.#lessonUtilsService.cleanOrphanedComponents(currentLesson);
|
|
192
|
-
|
|
193
|
-
// TODO: Implement optimization for saving only changed data.
|
|
194
|
-
// This requires comparing lessonToSave with the initially fetched state.
|
|
195
|
-
this.isLoadingLesson.set(true); // Indicate saving
|
|
196
|
-
try {
|
|
197
|
-
// Use the cleaned lesson object for saving
|
|
198
|
-
const savedLesson = await this.#lessonService.postLesson(lessonToSave);
|
|
199
|
-
const currentId = this.lessonId();
|
|
200
|
-
|
|
201
|
-
if (!currentId) {
|
|
202
|
-
// It was a new lesson, now it has an ID. Navigate.
|
|
203
|
-
this.#toastService.success({ title: 'Se creó la lección', subtitle: 'Éxito' });
|
|
204
|
-
// The effect should automatically fetch the lesson again after navigation due to paramMap change.
|
|
205
|
-
this.#router.navigate(['../', savedLesson.id], { relativeTo: this.#activatedRoute });
|
|
206
|
-
} else {
|
|
207
|
-
// It was an existing lesson, update the signal with the potentially updated data from the backend.
|
|
208
|
-
this.lesson.set(savedLesson);
|
|
209
|
-
this.#toastService.info({ title: 'Se guardaron los cambios en la lección', subtitle: 'Guardado' });
|
|
210
|
-
// Call the service method for validation
|
|
211
|
-
this.#lessonUtilsService.validateAudios(this.lesson());
|
|
212
|
-
}
|
|
213
|
-
return savedLesson;
|
|
214
|
-
} catch (error: any) {
|
|
215
|
-
// Type error
|
|
216
|
-
console.error('Error saving lesson:', error);
|
|
217
|
-
this.#toastService.error({ title: 'Error al guardar', subtitle: 'No se pudieron guardar los cambios' });
|
|
218
|
-
return undefined;
|
|
219
|
-
} finally {
|
|
220
|
-
this.isLoadingLesson.set(false); // Finish saving indication
|
|
221
|
-
}
|
|
222
|
-
} // Add missing closing brace for saveLesson
|
|
223
|
-
|
|
224
|
-
// Removed openComponentBuilder method
|
|
225
|
-
|
|
226
|
-
/**
|
|
227
|
-
* Handles the event emitted when a component is added via the adder component.
|
|
228
|
-
* @param result The configuration data returned from the component builder dialog. Expected format: { obj: LessonComponentConfiguration }
|
|
229
|
-
*/
|
|
230
|
-
public onComponentAdded(result: ComponentBuildData): void {
|
|
231
|
-
debugger;
|
|
232
|
-
// Check if result and result.obj.id exist
|
|
233
|
-
const newComponent = result?.obj;
|
|
234
|
-
if (newComponent?.id) {
|
|
235
|
-
console.log('Component builder closed, result received in editor:', newComponent);
|
|
236
|
-
|
|
237
|
-
// // Transform LessonComponentConfiguration to DynamicContentComponent
|
|
238
|
-
// const dynamicComponentToAdd: DynamicContentComponent = {
|
|
239
|
-
// id: componentConfig.id,
|
|
240
|
-
// component: componentConfig.component,
|
|
241
|
-
// inputs: {
|
|
242
|
-
// config: componentConfig, // Pass the original config object as an input named 'config'
|
|
243
|
-
// // Add other potential inputs if needed based on component type later
|
|
244
|
-
// },
|
|
245
|
-
// };
|
|
246
|
-
|
|
247
|
-
// Update the lesson signal, adding the transformed component to the dynamicComponents object
|
|
248
|
-
this.lesson.update((currentLesson: any) => {
|
|
249
|
-
if (!currentLesson) return undefined;
|
|
250
|
-
|
|
251
|
-
// Ensure dynamicComponents object exists, initialize if not
|
|
252
|
-
const currentDynamicComponents = currentLesson.dynamicComponents || {};
|
|
253
|
-
|
|
254
|
-
// Create the updated dynamicComponents object
|
|
255
|
-
const updatedDynamicComponents: Record<string, LessonComponentConfiguration<any>> = {
|
|
256
|
-
...currentDynamicComponents,
|
|
257
|
-
[newComponent.id]: newComponent, // Use component's id as the key
|
|
258
|
-
};
|
|
259
|
-
|
|
260
|
-
// Return the updated lesson state
|
|
261
|
-
return { ...currentLesson, dynamicComponents: updatedDynamicComponents };
|
|
262
|
-
});
|
|
263
|
-
|
|
264
|
-
// Optionally save the lesson after adding the component
|
|
265
|
-
// this.saveLesson();
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
public openCropper(): void {
|
|
270
|
-
// Correctly define openCropper
|
|
271
|
-
this.isCropperVisible.set(true);
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
// isLoadingLesson signal is used directly
|
|
275
|
-
|
|
276
|
-
public async generateByAI(): Promise<void> {
|
|
277
|
-
const currentId = this.lessonId();
|
|
278
|
-
if (!currentId) {
|
|
279
|
-
this.#toastService.warn({ title: 'Guardar primero', subtitle: 'Guarda la lección antes de usar IA.' });
|
|
280
|
-
return;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
this.isLoadingLesson.set(true);
|
|
284
|
-
try {
|
|
285
|
-
// Ensure latest changes are saved before generating
|
|
286
|
-
const savedLesson = await this.saveLesson();
|
|
287
|
-
if (!savedLesson) {
|
|
288
|
-
// Handle save error - toast is shown in saveLesson
|
|
289
|
-
throw new Error('Failed to save before AI generation');
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
// Call the service method
|
|
293
|
-
const updatedLesson = await this.#lessonUtilsService.generateByAI(currentId);
|
|
294
|
-
|
|
295
|
-
if (updatedLesson) {
|
|
296
|
-
this.lesson.set(updatedLesson); // Update the signal with AI changes from service
|
|
297
|
-
// Toast success is handled by the service
|
|
298
|
-
} else {
|
|
299
|
-
// Toast error is handled by the service
|
|
300
|
-
throw new Error('AI generation failed or lesson fetch failed after generation.');
|
|
301
|
-
}
|
|
302
|
-
} catch (error: any) {
|
|
303
|
-
// Type error
|
|
304
|
-
console.error('Error during AI generation process in component:', error);
|
|
305
|
-
// Service handles specific AI error toasts, maybe add a general one here if needed
|
|
306
|
-
// this.#toastService.error({ title: 'Error General', subtitle: 'Ocurrió un problema durante el proceso de IA.' });
|
|
307
|
-
} finally {
|
|
308
|
-
this.isLoadingLesson.set(false); // Stop loading
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
/**
|
|
313
|
-
* Handles the image upload event, updates the lesson signal via the service, and saves.
|
|
314
|
-
* @param event The image upload event data.
|
|
315
|
-
*/
|
|
316
|
-
public async onImageUploaded(event: any): Promise<void> {
|
|
317
|
-
// Call the service to update the signal
|
|
318
|
-
this.#lessonUtilsService.uploadCover(this.lesson, event);
|
|
319
|
-
// The coverBackground computed signal will update automatically.
|
|
320
|
-
// Save the lesson after the signal has been updated
|
|
321
|
-
await this.saveLesson();
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
/**
|
|
325
|
-
* Imports lesson content from Notion using the LessonNotionService.
|
|
326
|
-
*/
|
|
327
|
-
public async importFromNotion(): Promise<void> {
|
|
328
|
-
// Use the service's loading state or manage locally
|
|
329
|
-
this.isLoadingLesson.set(true);
|
|
330
|
-
try {
|
|
331
|
-
const newContent = await this.#lessonNotionService.importAndLinkLessonFromNotion(this.lesson(), this.lessonId());
|
|
332
|
-
|
|
333
|
-
if (newContent !== null) {
|
|
334
|
-
// Update the lesson signal's textCoded property
|
|
335
|
-
this.updateLessonProperty('textCoded', newContent);
|
|
336
|
-
// Toast success is handled within the service now
|
|
337
|
-
}
|
|
338
|
-
// If newContent is null, the service handled errors/toasts
|
|
339
|
-
} finally {
|
|
340
|
-
// Ensure loading state is reset regardless of service outcome
|
|
341
|
-
// If observing service state: this.isLoadingLesson.set(this.#lessonNotionService.isLoading());
|
|
342
|
-
this.isLoadingLesson.set(false); // Keep local loading for now
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
/**
|
|
347
|
-
* Calls the LessonNotionService to improve the lesson using AI based on Notion content.
|
|
348
|
-
*/
|
|
349
|
-
public async improveNotionWithAI(): Promise<void> {
|
|
350
|
-
await this.#lessonNotionService.improveLessonWithNotionAI(this.lesson());
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
public showComponentDetails(data: any) {
|
|
354
|
-
alert('showComponentDetails' + JSON.stringify(data));
|
|
355
|
-
}
|
|
356
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
/* Add any specific styles for the metadata editor here if needed */
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
@if (lesson(); as currentLesson) {
|
|
2
|
-
<div>
|
|
3
|
-
<div>
|
|
4
|
-
<div style="display: flex; gap: 10px; padding: 10px">
|
|
5
|
-
<p-button label="Guardar" severity="primary" (click)="emitSaveRequest()" />
|
|
6
|
-
<p-button label="Importar de Notion" severity="help" (click)="emitImportNotionRequest()" />
|
|
7
|
-
<p-button label="Mejorar Notion con AI" severity="help" (click)="emitImproveNotionRequest()" />
|
|
8
|
-
</div>
|
|
9
|
-
|
|
10
|
-
<!-- Use one-way binding and ngModelChange for signals -->
|
|
11
|
-
<div>
|
|
12
|
-
<input
|
|
13
|
-
pInputText
|
|
14
|
-
style="width: 100%"
|
|
15
|
-
[ngModel]="currentLesson.title"
|
|
16
|
-
(ngModelChange)="onPropertyChange('title', $event)"
|
|
17
|
-
type="text"
|
|
18
|
-
placeholder="Agrega un título" />
|
|
19
|
-
</div>
|
|
20
|
-
<div style="margin-top: 4px">
|
|
21
|
-
<input
|
|
22
|
-
pInputText
|
|
23
|
-
style="width: 100%"
|
|
24
|
-
[ngModel]="currentLesson.description"
|
|
25
|
-
(ngModelChange)="onPropertyChange('description', $event)"
|
|
26
|
-
type="text"
|
|
27
|
-
placeholder="Agrega una descripción" />
|
|
28
|
-
</div>
|
|
29
|
-
|
|
30
|
-
<div style="display: flex; align-items: center; margin-top: 10px">
|
|
31
|
-
<input
|
|
32
|
-
pInputText
|
|
33
|
-
style="flex: auto; margin-right: 5px"
|
|
34
|
-
[ngModel]="currentLesson.prompt"
|
|
35
|
-
(ngModelChange)="onPropertyChange('prompt', $event)"
|
|
36
|
-
type="text"
|
|
37
|
-
placeholder="Prompt para IA (opcional)" />
|
|
38
|
-
<p-button severity="primary" [disabled]="isLoadingLesson()" (click)="emitGenerateAIRequest()"> Generar con IA </p-button>
|
|
39
|
-
</div>
|
|
40
|
-
|
|
41
|
-
<div style="margin-top: 10px">
|
|
42
|
-
<label class="checkbox-container" style="margin-right: 15px">
|
|
43
|
-
<input
|
|
44
|
-
type="checkbox"
|
|
45
|
-
[ngModel]="currentLesson.isPublished"
|
|
46
|
-
(ngModelChange)="onPropertyChange('isPublished', $event)"
|
|
47
|
-
title="Cuando termines la edición marca esta casilla" />
|
|
48
|
-
<span class="checkmark"></span>
|
|
49
|
-
Publicada
|
|
50
|
-
</label>
|
|
51
|
-
|
|
52
|
-
<input
|
|
53
|
-
pInputText
|
|
54
|
-
[ngModel]="currentLesson.level"
|
|
55
|
-
(ngModelChange)="onPropertyChange('level', $event)"
|
|
56
|
-
type="number"
|
|
57
|
-
placeholder="Nivel"
|
|
58
|
-
style="width: 80px" />
|
|
59
|
-
</div>
|
|
60
|
-
|
|
61
|
-
<!-- Access signal values -->
|
|
62
|
-
<div style="margin-top: 10px; font-size: 0.9em; color: var(--text-color-secondary)">
|
|
63
|
-
{{ currentLesson.baseLang | flagEmoji }} -> {{ currentLesson.targetLang | flagEmoji }} Lección para hablantes de
|
|
64
|
-
{{ currentLesson.baseLang | langDesc : 'es' }} que aprenden
|
|
65
|
-
{{ currentLesson.targetLang | langDesc : 'es' }}
|
|
66
|
-
</div>
|
|
67
|
-
</div>
|
|
68
|
-
</div>
|
|
69
|
-
} @else {
|
|
70
|
-
<!-- Optional: Show a loading state or placeholder if lesson is undefined -->
|
|
71
|
-
<p>Cargando datos de la lección...</p>
|
|
72
|
-
}
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { Component, EventEmitter, Input, Output, WritableSignal, signal } from '@angular/core';
|
|
2
|
-
import { CommonModule } from '@angular/common';
|
|
3
|
-
import { FormsModule } from '@angular/forms';
|
|
4
|
-
import { ButtonModule } from 'primeng/button';
|
|
5
|
-
import { InputTextModule } from 'primeng/inputtext';
|
|
6
|
-
import { TooltipModule } from 'primeng/tooltip'; // Added TooltipModule
|
|
7
|
-
import { ILesson } from '../../lesson-mini-components/components/lessons.clases';
|
|
8
|
-
import { FlagLanguagePipe, LangDescTranslationPipe } from '../../../models/lessons.pipes';
|
|
9
|
-
|
|
10
|
-
@Component({
|
|
11
|
-
selector: 'dc-lesson-metadata-editor',
|
|
12
|
-
standalone: true,
|
|
13
|
-
imports: [
|
|
14
|
-
CommonModule,
|
|
15
|
-
FormsModule,
|
|
16
|
-
ButtonModule,
|
|
17
|
-
InputTextModule,
|
|
18
|
-
TooltipModule, // Added TooltipModule
|
|
19
|
-
FlagLanguagePipe, // Added Pipe
|
|
20
|
-
LangDescTranslationPipe, // Added Pipe
|
|
21
|
-
],
|
|
22
|
-
templateUrl: './dc-lesson-metadata-editor.component.html',
|
|
23
|
-
styleUrls: ['./dc-lesson-metadata-editor.component.css'],
|
|
24
|
-
})
|
|
25
|
-
export class DCLessonMetadataEditorComponent {
|
|
26
|
-
// Use signal for input lesson data
|
|
27
|
-
@Input({ required: true }) lesson: WritableSignal<ILesson | undefined> = signal(undefined);
|
|
28
|
-
@Input({ required: true }) isLoadingLesson: WritableSignal<boolean> = signal(false);
|
|
29
|
-
|
|
30
|
-
// Outputs for actions
|
|
31
|
-
@Output() saveRequest = new EventEmitter<void>();
|
|
32
|
-
@Output() importNotionRequest = new EventEmitter<void>();
|
|
33
|
-
@Output() improveNotionRequest = new EventEmitter<void>();
|
|
34
|
-
@Output() generateAIRequest = new EventEmitter<void>();
|
|
35
|
-
|
|
36
|
-
// Output for property changes
|
|
37
|
-
@Output() propertyChange = new EventEmitter<{ property: keyof ILesson; value: any }>();
|
|
38
|
-
|
|
39
|
-
// Method to emit property changes, called by ngModelChange in the template
|
|
40
|
-
onPropertyChange<K extends keyof ILesson>(property: K, value: ILesson[K]): void {
|
|
41
|
-
this.propertyChange.emit({ property, value });
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Methods to emit action requests
|
|
45
|
-
emitSaveRequest(): void {
|
|
46
|
-
this.saveRequest.emit();
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
emitImportNotionRequest(): void {
|
|
50
|
-
this.importNotionRequest.emit();
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
emitImproveNotionRequest(): void {
|
|
54
|
-
this.improveNotionRequest.emit();
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
emitGenerateAIRequest(): void {
|
|
58
|
-
this.generateAIRequest.emit();
|
|
59
|
-
}
|
|
60
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
<div>
|
|
2
|
-
<div #dynamicLesson class="targetclass">
|
|
3
|
-
<ng-template #target></ng-template>
|
|
4
|
-
</div>
|
|
5
|
-
</div>
|
|
6
|
-
|
|
7
|
-
<br />
|
|
8
|
-
<div style="display: flex; gap: 10px">
|
|
9
|
-
@if ((mainForm.controls | keyvalue)?.length) {
|
|
10
|
-
<div>
|
|
11
|
-
<p-button label="Calificar Lección" icon="pi pi-check-circle" (click)="evaluateForms()" [rounded]="true"></p-button>
|
|
12
|
-
</div>
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
<p-button icon="pi pi-verified" [rounded]="true" (click)="startAI()" label="Repasar con IA" />
|
|
16
|
-
</div>
|
|
17
|
-
<br /><br />
|
|
18
|
-
|
|
19
|
-
@if(chatVisible()) {
|
|
20
|
-
<p-drawer header="Conversation" [visible]="chatVisible()" position="bottom" styleClass="app-bottom-overlay">
|
|
21
|
-
<dc-chat [agentCard]="agentMasterLesson()" [evaluatorAgentCard]="evaluatorAgentCard()"></dc-chat>
|
|
22
|
-
</p-drawer>
|
|
23
|
-
}
|