@dataclouder/ngx-lessons 0.0.30 → 0.0.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/fesm2022/dataclouder-ngx-lessons.mjs +1169 -449
  2. package/fesm2022/dataclouder-ngx-lessons.mjs.map +1 -1
  3. package/lib/components/dc-lessons/dc-lesson-card/dc-lesson-card.component.d.ts +2 -2
  4. package/lib/components/dc-lessons/dc-lesson-component-adder/dc-lesson-component-adder.component.d.ts +11 -0
  5. package/lib/components/dc-lessons/dc-lesson-editor/dc-lesson-editor.component.d.ts +39 -38
  6. package/lib/components/dc-lessons/dc-lesson-metadata-editor/dc-lesson-metadata-editor.component.d.ts +22 -0
  7. package/lib/components/dc-lessons/dc-lesson-renderer/dc-lesson-renderer.component.d.ts +32 -37
  8. package/lib/components/dc-lessons/lesson-list/dc-lesson-list.component.d.ts +2 -4
  9. package/lib/components/lesson-mini-components/components/ComponentBuilder.d.ts +7 -2
  10. package/lib/components/lesson-mini-components/components/lessons.clases.d.ts +17 -42
  11. package/lib/components/lesson-mini-components/components/speaker/speaker-builder/speaker-builder.component.d.ts +13 -0
  12. package/lib/components/lesson-mini-components/components/speaker/speaker.component.d.ts +12 -0
  13. package/lib/services/lesson-ai.service.d.ts +18 -0
  14. package/lib/services/lesson-notion.service.d.ts +35 -0
  15. package/lib/services/lesson-utils.service.d.ts +34 -0
  16. package/package.json +3 -2
  17. package/src/lib/components/dc-lessons/dc-lesson-card/dc-lesson-card.component.html +0 -35
  18. package/src/lib/components/dc-lessons/dc-lesson-card/dc-lesson-card.component.scss +0 -107
  19. package/src/lib/components/dc-lessons/dc-lesson-card/dc-lesson-card.component.ts +0 -82
  20. package/src/lib/components/dc-lessons/dc-lesson-editor/dc-lesson-editor.component.css +0 -90
  21. package/src/lib/components/dc-lessons/dc-lesson-editor/dc-lesson-editor.component.html +0 -105
  22. package/src/lib/components/dc-lessons/dc-lesson-editor/dc-lesson-editor.component.scss +0 -0
  23. package/src/lib/components/dc-lessons/dc-lesson-editor/dc-lesson-editor.component.ts +0 -318
  24. package/src/lib/components/dc-lessons/dc-lesson-renderer/dc-lesson-renderer.component.html +0 -27
  25. package/src/lib/components/dc-lessons/dc-lesson-renderer/dc-lesson-renderer.component.scss +0 -3
  26. package/src/lib/components/dc-lessons/dc-lesson-renderer/dc-lesson-renderer.component.ts +0 -271
  27. package/src/lib/components/dc-lessons/lesson-form/lesson-form.component.html +0 -5
  28. package/src/lib/components/dc-lessons/lesson-form/lesson-form.component.scss +0 -3
  29. package/src/lib/components/dc-lessons/lesson-form/lesson-form.component.ts +0 -14
  30. package/src/lib/components/dc-lessons/lesson-list/dc-lesson-list.component.html +0 -30
  31. package/src/lib/components/dc-lessons/lesson-list/dc-lesson-list.component.scss +0 -17
  32. package/src/lib/components/dc-lessons/lesson-list/dc-lesson-list.component.ts +0 -170
  33. package/src/lib/components/dc-lessons/lessons.component.ts +0 -10
  34. package/src/lib/components/lesson-mini-components/components/ComponentBuilder.ts +0 -74
  35. package/src/lib/components/lesson-mini-components/components/ComponentWithForm.ts +0 -25
  36. package/src/lib/components/lesson-mini-components/components/lesson-dynamic.component.ts +0 -13
  37. package/src/lib/components/lesson-mini-components/components/lessons.clases.ts +0 -254
  38. package/src/lib/components/lesson-mini-components/components/selector/selector-builder/selector-builder.component.html +0 -58
  39. package/src/lib/components/lesson-mini-components/components/selector/selector-builder/selector-builder.component.scss +0 -15
  40. package/src/lib/components/lesson-mini-components/components/selector/selector-builder/selector-builder.component.spec.ts +0 -25
  41. package/src/lib/components/lesson-mini-components/components/selector/selector-builder/selector-builder.component.ts +0 -70
  42. package/src/lib/components/lesson-mini-components/components/selector/selector.component.html +0 -2
  43. package/src/lib/components/lesson-mini-components/components/selector/selector.component.scss +0 -12
  44. package/src/lib/components/lesson-mini-components/components/selector/selector.component.spec.ts +0 -25
  45. package/src/lib/components/lesson-mini-components/components/selector/selector.component.ts +0 -47
  46. package/src/lib/components/lesson-mini-components/components/speaker/speaker-builder/speaker-builder.component.html +0 -35
  47. package/src/lib/components/lesson-mini-components/components/speaker/speaker-builder/speaker-builder.component.scss +0 -0
  48. package/src/lib/components/lesson-mini-components/components/speaker/speaker-builder/speaker-builder.component.spec.ts +0 -25
  49. package/src/lib/components/lesson-mini-components/components/speaker/speaker-builder/speaker-builder.component.ts +0 -27
  50. package/src/lib/components/lesson-mini-components/components/speaker/speaker.component.html +0 -7
  51. package/src/lib/components/lesson-mini-components/components/speaker/speaker.component.scss +0 -3
  52. package/src/lib/components/lesson-mini-components/components/speaker/speaker.component.spec.ts +0 -25
  53. package/src/lib/components/lesson-mini-components/components/speaker/speaker.component.ts +0 -29
  54. package/src/lib/components/lesson-mini-components/components/text-writer/text-writer-buider/text-writer-buider.component.html +0 -24
  55. package/src/lib/components/lesson-mini-components/components/text-writer/text-writer-buider/text-writer-buider.component.scss +0 -15
  56. package/src/lib/components/lesson-mini-components/components/text-writer/text-writer-buider/text-writer-buider.component.spec.ts +0 -25
  57. package/src/lib/components/lesson-mini-components/components/text-writer/text-writer-buider/text-writer-buider.component.ts +0 -29
  58. package/src/lib/components/lesson-mini-components/components/text-writer/text-writer.component.html +0 -4
  59. package/src/lib/components/lesson-mini-components/components/text-writer/text-writer.component.scss +0 -8
  60. package/src/lib/components/lesson-mini-components/components/text-writer/text-writer.component.spec.ts +0 -25
  61. package/src/lib/components/lesson-mini-components/components/text-writer/text-writer.component.ts +0 -61
  62. package/src/lib/components/lesson-mini-components/components/translationSwitcher/translationSwitcher.component.css +0 -3
  63. package/src/lib/components/lesson-mini-components/components/translationSwitcher/translationSwitcher.component.html +0 -9
  64. package/src/lib/components/lesson-mini-components/components/translationSwitcher/translationSwitcher.component.ts +0 -32
  65. package/src/lib/components/lesson-mini-components/components/translationSwitcher/translationSwitcherBuilder/translationSwitcherBuilder.component.css +0 -3
  66. package/src/lib/components/lesson-mini-components/components/translationSwitcher/translationSwitcherBuilder/translationSwitcherBuilder.component.html +0 -28
  67. package/src/lib/components/lesson-mini-components/components/translationSwitcher/translationSwitcherBuilder/translationSwitcherBuilder.component.ts +0 -30
  68. package/src/lib/components/lesson-mini-components/components/verb-summary/verb-summary-builder/verb-summary-builder.component.html +0 -18
  69. package/src/lib/components/lesson-mini-components/components/verb-summary/verb-summary-builder/verb-summary-builder.component.scss +0 -3
  70. package/src/lib/components/lesson-mini-components/components/verb-summary/verb-summary-builder/verb-summary-builder.component.spec.ts +0 -25
  71. package/src/lib/components/lesson-mini-components/components/verb-summary/verb-summary-builder/verb-summary-builder.component.ts +0 -25
  72. package/src/lib/components/lesson-mini-components/components/verb-summary/verb-summary.component.html +0 -15
  73. package/src/lib/components/lesson-mini-components/components/verb-summary/verb-summary.component.scss +0 -27
  74. package/src/lib/components/lesson-mini-components/components/verb-summary/verb-summary.component.spec.ts +0 -25
  75. package/src/lib/components/lesson-mini-components/components/verb-summary/verb-summary.component.ts +0 -46
  76. package/src/lib/components/lesson-mini-components/components/word-summary/word-summary-builder/word-summary-builder.component.html +0 -19
  77. package/src/lib/components/lesson-mini-components/components/word-summary/word-summary-builder/word-summary-builder.component.scss +0 -0
  78. package/src/lib/components/lesson-mini-components/components/word-summary/word-summary-builder/word-summary-builder.component.ts +0 -27
  79. package/src/lib/components/lesson-mini-components/components/word-summary/word-summary.component.html +0 -14
  80. package/src/lib/components/lesson-mini-components/components/word-summary/word-summary.component.scss +0 -22
  81. package/src/lib/components/lesson-mini-components/components/word-summary/word-summary.component.ts +0 -51
  82. package/src/lib/models/lessons.pipes.ts +0 -38
  83. package/src/lib/models/models.ts +0 -92
  84. package/src/lib/models/notion.models.ts +0 -43
  85. package/src/public-api.ts +0 -25
@@ -1,107 +0,0 @@
1
- .card-container {
2
- position: relative;
3
- margin-bottom: 20px;
4
- margin-left: 10px;
5
- }
6
-
7
- .dial-button {
8
- position: absolute;
9
- top: 10px;
10
- right: 20px;
11
- z-index: 10;
12
- }
13
-
14
- .lesson-card {
15
- // position: relative;
16
- border-radius: 0.5rem;
17
- height: 100%;
18
- }
19
-
20
- .lesson-card .photo {
21
- position: absolute;
22
- top: 0;
23
- left: 0;
24
- right: 0;
25
- bottom: 0;
26
- z-index: 1;
27
-
28
- img {
29
- width: 100%;
30
- height: 100%;
31
- object-fit: cover;
32
- object-position: center;
33
- }
34
- }
35
-
36
- .description {
37
- position: relative;
38
- z-index: 2;
39
- padding: 1.5rem;
40
- color: white;
41
- background: linear-gradient(to bottom, rgba(0, 0, 0, 0.4) 0%, rgba(0, 0, 0, 0.8) 100%);
42
- height: 100%;
43
- display: flex;
44
- flex-direction: column;
45
-
46
- h1 {
47
- margin-top: 0;
48
- margin-bottom: 0.5rem;
49
- font-size: 1.5rem;
50
- }
51
-
52
- p {
53
- margin-bottom: 1rem;
54
- flex-grow: 1;
55
- }
56
- }
57
-
58
- .date {
59
- position: absolute;
60
- top: 1rem;
61
- left: 1rem;
62
- z-index: 3;
63
- background-color: rgba(0, 0, 0, 0.7);
64
- color: white;
65
- padding: 0.3rem 0.6rem;
66
- border-radius: 0.25rem;
67
- font-size: 0.8rem;
68
- }
69
-
70
- .card-footer {
71
- display: flex;
72
- justify-content: space-between;
73
- align-items: center;
74
- margin-top: auto;
75
- }
76
-
77
- .status-tags {
78
- display: flex;
79
- gap: 0.5rem;
80
-
81
- .level-tag,
82
- .status-tag {
83
- padding: 0.3rem 0.6rem;
84
- border-radius: 0.25rem;
85
- font-size: 0.8rem;
86
- }
87
-
88
- .level-tag {
89
- background-color: rgba(255, 255, 255, 0.2);
90
- }
91
-
92
- .status-tag {
93
- &.success {
94
- background-color: rgba(40, 167, 69, 0.7);
95
- }
96
-
97
- &.danger {
98
- background-color: rgba(220, 53, 69, 0.7);
99
- }
100
- }
101
- }
102
-
103
- .actions {
104
- ::ng-deep .p-button {
105
- font-size: 0.9rem;
106
- }
107
- }
@@ -1,82 +0,0 @@
1
- import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
2
- import { NgFor, NgIf, DatePipe } from '@angular/common';
3
-
4
- import { ButtonModule } from 'primeng/button';
5
- import { PopoverModule } from 'primeng/popover';
6
-
7
- import { SpeedDialModule } from 'primeng/speeddial';
8
- import { MenuItem } from 'primeng/api';
9
- import { CardModule } from 'primeng/card';
10
-
11
- import { ILesson, ILessonWithTaken } from '../../lesson-mini-components/components/lessons.clases';
12
- import { OnActionEvent } from '@dataclouder/ngx-core';
13
-
14
- enum EventCard {
15
- Edit = 'edit',
16
- Delete = 'delete',
17
- Select = 'select',
18
- Qr = 'qr',
19
- }
20
- @Component({
21
- selector: 'dc-lesson-card',
22
- templateUrl: './dc-lesson-card.component.html',
23
- styleUrls: ['./dc-lesson-card.component.scss'],
24
- standalone: true,
25
- imports: [NgFor, NgIf, DatePipe, ButtonModule, PopoverModule, SpeedDialModule, CardModule],
26
- })
27
- export class DcLessonCardComponent implements OnInit {
28
- @Input() lesson: ILessonWithTaken | ILesson | any;
29
- @Input() isAdmin: boolean = true;
30
-
31
- @Output() onAction: EventEmitter<OnActionEvent> = new EventEmitter();
32
-
33
- public coverUrl: string = 'assets/background/default-background.webp';
34
- public eventType = EventCard;
35
-
36
- public items: MenuItem[] = [
37
- {
38
- label: 'Editar',
39
- icon: 'pi pi-pencil',
40
- command: () => {
41
- this.eventCard(EventCard.Edit);
42
- },
43
- },
44
- {
45
- label: 'Eliminar',
46
- icon: 'pi pi-trash',
47
- command: () => {
48
- this.eventCard(EventCard.Delete);
49
- },
50
- },
51
- {
52
- label: 'Tomar lección',
53
- icon: 'pi pi-play',
54
- command: () => {
55
- this.eventCard(EventCard.Select);
56
- },
57
- },
58
- ];
59
-
60
- ngOnInit() {
61
- if (this.lesson?.media?.images![0]?.url) {
62
- this.coverUrl = this.lesson.media.images[0].url;
63
- }
64
- }
65
-
66
- public eventCard(eventType: EventCard) {
67
- switch (eventType) {
68
- case EventCard.Edit:
69
- this.onAction.emit({ action: 'edit', item: this.lesson });
70
- break;
71
- case EventCard.Delete:
72
- this.onAction.emit({ action: 'delete', item: this.lesson });
73
- break;
74
- case EventCard.Select:
75
- this.onAction.emit({ action: 'select', item: this.lesson });
76
- break;
77
- case EventCard.Qr:
78
- this.onAction.emit({ action: 'qr', item: this.lesson });
79
- break;
80
- }
81
- }
82
- }
@@ -1,90 +0,0 @@
1
- .btn {
2
- padding: 0.5rem 1rem;
3
- border-radius: 4px;
4
- border: 1px solid transparent;
5
- cursor: pointer;
6
- }
7
-
8
- .btn-primary {
9
- background-color: #007bff;
10
- color: white;
11
- }
12
-
13
- .btn-outline-primary {
14
- border-color: #007bff;
15
- color: #007bff;
16
- }
17
-
18
- .btn-secondary {
19
- background-color: #6c757d;
20
- color: white;
21
- }
22
-
23
- .btn-outline-secondary {
24
- border-color: #6c757d;
25
- color: #6c757d;
26
- }
27
-
28
- .btn-rounded {
29
- border-radius: 50%;
30
- }
31
-
32
- .form-control {
33
- padding: 0.375rem 0.75rem;
34
- border: 1px solid #ced4da;
35
- border-radius: 0.25rem;
36
- }
37
-
38
- .splitter {
39
- display: flex;
40
- gap: 1rem;
41
- }
42
-
43
- .splitter-panel {
44
- flex: 1;
45
- }
46
-
47
- .checkbox-container {
48
- display: inline-flex;
49
- align-items: center;
50
- gap: 0.5rem;
51
- cursor: pointer;
52
- }
53
-
54
- .mr-2 {
55
- margin-right: 0.5rem;
56
- }
57
-
58
- .header-cover {
59
- width: 100%;
60
- height: 250px;
61
- background-position: center;
62
- background-repeat: no-repeat;
63
- background-size: cover;
64
- position: relative;
65
- }
66
-
67
- .float-button {
68
- position: fixed;
69
- bottom: 3.5rem;
70
- right: 2rem;
71
- z-index: 1000;
72
- display: flex;
73
- gap: 1px;
74
- :host ::ng-deep .p-button {
75
- width: 4rem;
76
- height: 4rem;
77
- border-radius: 50%;
78
- }
79
- }
80
-
81
- .text-editor {
82
- width: -webkit-fill-available;
83
- overflow-y: auto;
84
- }
85
-
86
-
87
- :host ::ng-deep .p-inputtext{
88
- background: rgba(255, 255, 255, 0.2);
89
-
90
- }
@@ -1,105 +0,0 @@
1
- <div style="position: relative; margin-bottom: 20px">
2
- <div class="header-cover" [style.background-image]="cover"></div>
3
-
4
- <dc-cropper-modal
5
- style="position: absolute; top: 10px; left: 20px"
6
- [buttonLabel]="'Carga una portada'"
7
- [imgStorageSettings]="coverStorageSettings"
8
- (imageUploaded)="onImageUploaded($event)"></dc-cropper-modal>
9
- </div>
10
-
11
- <br />
12
-
13
- <div>
14
- <div>
15
- <div>
16
- <div style="display: flex; gap: 10px; padding: 10px">
17
- <p-button label="Guardar" severity="primary" (click)="saveLesson()" />
18
-
19
- <p-button label="Previsualizar" severity="secondary" (click)="togleRender()" />
20
- <p-button label="Importar de Notion" severity="help" (click)="importFromNotion()" />
21
- <p-button label="Mejorar Notion con AI" severity="help" (click)="improveNotionWithAI()" />
22
- </div>
23
-
24
- <div>
25
- <input pInputText style="width: 100%" [(ngModel)]="lesson.title" type="text" placeholder="Agrega un título" />
26
- </div>
27
- <div style="margin-top: 4px">
28
- <input pInputText style="width: 100%" [(ngModel)]="lesson.description" type="text" placeholder="Agrega una descripción" />
29
- </div>
30
-
31
- <div style="display: flex; align-items: center">
32
- <br />
33
- <br />
34
- <input pInputText style="flex: auto" [(ngModel)]="lesson.prompt" type="text" placeholder="Prompt" />
35
- <p-button severity="primary" [disabled]="isLoadingLesson" (click)="generateByAI()"> Generar </p-button>
36
- </div>
37
-
38
- <div>
39
- <label class="checkbox-container">
40
- <input type="checkbox" [(ngModel)]="lesson.isPublished" title="Cuando termines la edición marca esta casilla" />
41
- <span class="checkmark"></span>
42
- Lección publicada
43
- </label>
44
- <br />
45
-
46
- <input pInputText [(ngModel)]="lesson.level" type="number" placeholder="Level" />
47
- </div>
48
-
49
- <div>
50
- {{ lesson.baseLang | flagEmoji }} -> {{ lesson.targetLang | flagEmoji }} Lección para hablantes de {{ lesson.baseLang | langDesc : 'es' }} que aprenden
51
- {{ lesson.targetLang | langDesc : 'es' }}
52
- </div>
53
- </div>
54
- </div>
55
-
56
- <hr />
57
- <span>Componentes: </span>
58
- <div style="display: flex; gap: 10px">
59
- <p-button severity="info" (click)="openComponentBuilder(lessonComponentEnum.Selector)" pTooltip="Agrega un selector con multiples opciones">
60
- Selector
61
- </p-button>
62
- <p-button severity="info" (click)="openComponentBuilder(lessonComponentEnum.Speaker)" pTooltip="Para que una palabra o frase sea reproducible">
63
- Speaker
64
- </p-button>
65
- <p-button severity="info" (click)="openComponentBuilder(lessonComponentEnum.TextWriter)" pTooltip="Escribe una respuesta en un cuadro de texto">
66
- Text
67
- </p-button>
68
- <p-button severity="info" (click)="openComponentBuilder(lessonComponentEnum.VerbSummary)" pTooltip="Muestra la información de un verbo"> Text </p-button>
69
- <p-button severity="info" (click)="openComponentBuilder(lessonComponentEnum.VerbSummary)" pTooltip="Muestra la información de un verbo"> Verb </p-button>
70
- <p-button severity="info" (click)="openComponentBuilder(lessonComponentEnum.WordSummary)" pTooltip="Muestra la información de una palabra">
71
- Palabra
72
- </p-button>
73
- <p-button severity="info" (click)="openComponentBuilder(lessonComponentEnum.TranslationSwitcher)" pTooltip="Muestra el texto pero al pica cambia de idioma">
74
- Traducción
75
- </p-button>
76
- </div>
77
-
78
- <hr />
79
-
80
- <p-splitter [style]="{ height: '80vh' }" styleClass="mb-8">
81
- <ng-template pTemplate>
82
- <ckeditor
83
- (keydown.control.s)="saveLesson($event)"
84
- (keydown.control.space)="togleRender($event)"
85
- class="text-editor"
86
- [editor]="editor"
87
- [(ngModel)]="lesson.textCoded">
88
- </ckeditor>
89
- </ng-template>
90
-
91
- <ng-template pTemplate>
92
- @if (isRendered) {
93
- <dc-lesson-renderer class="text-editor" [lesson]="lesson" [test]="true"></dc-lesson-renderer>
94
- }
95
- </ng-template>
96
- </p-splitter>
97
-
98
- <div class="float-button">
99
- <p-speeddial [model]="items" [radius]="120" type="quarter-circle" direction="up-left" />
100
-
101
- <p-button icon="pi pi-save" (click)="saveLesson()" severity="primary" [rounded]="true" [raised]="true" pTooltip="Guardar (Ctrl + S)"> </p-button>
102
- </div>
103
-
104
- <hr />
105
- </div>
@@ -1,318 +0,0 @@
1
- import { ChangeDetectorRef, Component, ComponentRef, ElementRef, Inject, OnInit, TemplateRef, ViewChild, ViewContainerRef } from '@angular/core';
2
- import { ActivatedRoute, Router } from '@angular/router';
3
- import { FormsModule } from '@angular/forms';
4
- import { Observable } from 'rxjs';
5
-
6
- import BalloonEditor from '@ckeditor/ckeditor5-build-balloon-block';
7
- import { CKEditorModule } from '@ckeditor/ckeditor5-angular';
8
- // PrimeNG
9
- import { DialogService } from 'primeng/dynamicdialog';
10
- import { SpeedDialModule } from 'primeng/speeddial';
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, CropImageSettings, 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
- import {
21
- LessonComponentEnum,
22
- LessonImage,
23
- ILesson,
24
- LessonComponentInterface,
25
- LESSONS_TOKEN,
26
- LessonsAbstractService,
27
- } from '../../lesson-mini-components/components/lessons.clases';
28
- import { LessonComponentBuilders } from '../../lesson-mini-components/components/lessons.clases';
29
- import { FlagLanguagePipe, LangDescTranslationPipe } from '../../../models/lessons.pipes';
30
- import { NOTION_SERVICE_TOKEN, NotionAbstractService, NotionExportType } from '../../../models/notion.models';
31
- import { MenuItem } from 'primeng/api';
32
-
33
- const GradientCss = 'linear-gradient(to bottom,var(--primary-color), rgba(213, 238, 239, 0.31))';
34
-
35
- @Component({
36
- selector: 'dc-lesson-editor',
37
- templateUrl: './dc-lesson-editor.component.html',
38
- styleUrls: ['./dc-lesson-editor.component.css'],
39
- standalone: true,
40
- imports: [
41
- FormsModule,
42
- CKEditorModule,
43
- CropperComponentModal,
44
- ButtonModule,
45
- InputTextModule,
46
- SplitterModule,
47
- DCLessonRendererComponent,
48
- LangDescTranslationPipe,
49
- FlagLanguagePipe,
50
- TooltipModule,
51
- SpeedDialModule,
52
- ],
53
- })
54
- export class DCLessonEditorComponent implements OnInit {
55
- // public get activatedRoute(): ActivatedRoute {
56
- // return this._activatedRoute;
57
- // }
58
- // public set activatedRoute(value: ActivatedRoute) {
59
- // this._activatedRoute = value;
60
- // }
61
- @ViewChild('target', { read: ViewContainerRef }) target: ViewContainerRef;
62
- @ViewChild('dhtml', { static: true }) dhtml: ElementRef;
63
-
64
- public editor = BalloonEditor;
65
- public coverStorageSettings: StorageImageSettings = {
66
- path: 'lessons/covers',
67
- fileName: 'cover',
68
- cropSettings: { resizeToWidth: 850, aspectRatio: AspectType.RectangleLarge, resolutions: [ResolutionType.Medium] },
69
- };
70
-
71
- public lessonComponentEnum = LessonComponentEnum;
72
- public lessonId: string = this._activatedRoute.snapshot.paramMap.get('id');
73
- public lesson: any = { textCoded: `<h1>Nueva lección </h1> <p> Texto aquí</p>`, tags: [] };
74
- public components: { [key: string]: ComponentRef<LessonComponentInterface> } = {};
75
- public isRendered: boolean = false;
76
- public cover: string = '';
77
- public isCropperVisible = false;
78
- public items: MenuItem[];
79
-
80
- constructor(
81
- @Inject(LESSONS_TOKEN) private lessonService: LessonsAbstractService,
82
- @Inject(TOAST_ALERTS_TOKEN) private toastService: ToastAlertsAbstractService,
83
- @Inject(NOTION_SERVICE_TOKEN) private notionService: NotionAbstractService,
84
- private _activatedRoute: ActivatedRoute,
85
- private router: Router,
86
- private cdr: ChangeDetectorRef,
87
- private dialogService: DialogService,
88
- ) {}
89
-
90
- ngOnInit(): void {
91
- this.getLessonIfId();
92
-
93
- this.items = [
94
- {
95
- tooltipOptions: { tooltipLabel: 'Reparar con IA: Repara la lección con IA', tooltipPosition: 'bottom' },
96
- icon: 'pi pi-magic',
97
- command: () => this.generateByAI(),
98
- },
99
- {
100
- tooltipOptions: { tooltipLabel: 'Selector: Agrega un selector con multiples opciones', tooltipPosition: 'bottom' },
101
- icon: 'pi pi-caret-down',
102
- command: () => this.openComponentBuilder('selector'),
103
- },
104
- {
105
- tooltipOptions: { tooltipLabel: 'Hablar: Para que una palabra o frase sea reproducible', tooltipPosition: 'bottom' },
106
- icon: 'pi pi-megaphone',
107
- command: () => this.openComponentBuilder('speaker'),
108
- },
109
- {
110
- tooltipOptions: {
111
- tooltipLabel: 'Entrada de texto: Escribe una respuesta en un cuadro de texto',
112
- tooltipPosition: 'bottom',
113
- },
114
- icon: 'pi pi-pencil',
115
- command: () => this.openComponentBuilder('textWriter'),
116
- },
117
- {
118
- tooltipOptions: { tooltipLabel: 'Verbo: Para ver datos de un verbo', tooltipPosition: 'bottom' },
119
- icon: 'pi pi-eye',
120
- command: () => this.openComponentBuilder('verbSummary'),
121
- },
122
- {
123
- tooltipOptions: { tooltipLabel: 'Palabra: Para ver datos de una palabra', tooltipPosition: 'bottom' },
124
- icon: 'pi pi-file-word',
125
- command: () => this.openComponentBuilder('wordSummary'),
126
- },
127
- ];
128
- }
129
-
130
- public async getLessonIfId(): Promise<void> {
131
- if (!this.lessonId) {
132
- this.cover = `${GradientCss}, url("/assets/images/default_banner.webp")`;
133
- return;
134
- }
135
- this.lesson = await this.lessonService.getLesson(this.lessonId);
136
- console.log('lesson', this.lesson);
137
- if (!this.lesson) {
138
- this.toastService.warn({ title: 'No se encontró la lección', subtitle: 'Quiza el id es incorrecto' });
139
- }
140
- this.togleRender();
141
- this.updateCover();
142
- }
143
-
144
- public updateCover(): void {
145
- const cover: LessonImage = this.lesson.media?.images?.find((img) => img.type === 'cover');
146
- if (cover) {
147
- this.cover = `${GradientCss}, url('${cover.url}')`;
148
- } else {
149
- this.cover = `${GradientCss}, url("/assets/images/default_banner.webp")`;
150
- }
151
- this.cdr.detectChanges();
152
- }
153
-
154
- public onTagRemove(tag: any): void {
155
- this.lesson.tags = this.lesson.tags.filter((text) => text !== tag.text);
156
- }
157
-
158
- public onTagAdd(tag: { value: string; input: any }): void {
159
- if (tag.value) {
160
- this.lesson.tags.push(tag.value);
161
- }
162
- tag.input.nativeElement.value = '';
163
- }
164
-
165
- public async saveLesson(event: Event = null): Promise<ILesson> {
166
- if (event) {
167
- event.preventDefault();
168
- }
169
- // TODO: Optimización importante, guardar una lección guarda todos los datos de nuevo, y no solo los que se modificaron, encontrar una forma de optimizar.
170
- const lesson = await this.lessonService.postLesson(this.lesson);
171
- if (!this.lessonId) {
172
- this.toastService.success({ title: 'Se creó la lección', subtitle: 'Éxito' });
173
- this.router.navigate([lesson.id], { relativeTo: this._activatedRoute });
174
- } else {
175
- this.toastService.info({ title: 'Se guadarón los cambios en la lección', subtitle: 'Guardado' });
176
- this.lesson = lesson;
177
- this.validateAudios();
178
- }
179
-
180
- this.togleRender();
181
- return lesson;
182
- }
183
-
184
- public async validateAudios() {
185
- if (!this.lesson.components) {
186
- return;
187
- }
188
- // al menos un audio sin generar.
189
- // agregar más condigciones después
190
- // this.lesson.components.forEach((component: SpeakerCompConfiguration) => {
191
- // if (component.component === 'speaker') {
192
- // if (component.settings.voice && !component.audio) {
193
- // // this.toastrService.warn('Se encontraron audios por generar', 'Será rápido');
194
- // // TODO call backend.
195
- // this.lessonService.generateAudiosForLesson(this.lesson.id).then((res) => {
196
- // // this.toastrService.success('Se generaron los audios', 'Listo');
197
- // console.log(res);
198
- // });
199
- // return;
200
- // }
201
- // }
202
- // });
203
- }
204
-
205
- public togleRender(_event: any = null): void {
206
- this.isRendered = false;
207
- setTimeout(() => {
208
- this.isRendered = true;
209
- this.cdr.detectChanges();
210
- }, 400);
211
- this.cdr.detectChanges();
212
- }
213
-
214
- public openComponentBuilder(type: string): Observable<any> {
215
- return this.dialogService.open(LessonComponentBuilders[type], { width: '550px', header: 'Agregar componente', closable: true }).onClose.pipe();
216
- }
217
-
218
- public uploadCover(imageUploaded: any) {
219
- const image = { type: 'cover', ...imageUploaded };
220
-
221
- if (!this.lesson.media) {
222
- // puede que no exista media
223
- this.lesson.media = {};
224
- this.lesson.media.images = [image];
225
- } else {
226
- // solo sustituir el cover si ya existe, como siempre utilizo el mismo nombre, no tengo que eliminar la anterior si actualizo.
227
- // const currentCover = this.lesson.media.images.find((img) => img.type === 'cover');
228
-
229
- this.lesson.media.images = this.lesson.media.images.filter((img) => img.type !== 'cover');
230
- this.lesson.media.images.push(image);
231
- }
232
- this.updateCover();
233
- this.saveLesson();
234
- }
235
-
236
- openCropper() {
237
- this.isCropperVisible = true;
238
- }
239
-
240
- isLoadingLesson = false;
241
- public async generateByAI() {
242
- this.isLoadingLesson = true;
243
- try {
244
- await this.saveLesson();
245
- await this.lessonService.postGenerateByAI(this.lesson.id);
246
- await this.getLessonIfId();
247
- } finally {
248
- this.isLoadingLesson = false;
249
- }
250
- }
251
-
252
- public onImageSelected(event: any) {
253
- console.log(event);
254
- }
255
-
256
- public async onImageUploaded(event: any) {
257
- this.uploadCover(event);
258
- this.cdr.detectChanges();
259
- }
260
-
261
- public async importFromNotion() {
262
- let notionPageId: string;
263
- if (this.lesson?.extras?.notionPageId) {
264
- const response = confirm(`Ya tenemos el id ${this.lesson.extras?.notionPageId} ¿Quieres usar este id?`);
265
- if (!response) {
266
- return;
267
- }
268
- notionPageId = this.lesson.extras?.notionPageId;
269
- } else {
270
- const response = prompt('Ingresa el url de notion para importar la lección, se guardará este id');
271
- if (!response) {
272
- return;
273
- }
274
- notionPageId = this.extractNotionPageId(response);
275
- if (!notionPageId) return;
276
- this.linkWithNotion(notionPageId);
277
- }
278
-
279
- this.toastService.info({ title: 'Importando lección...', subtitle: 'Espera unos segundos' });
280
-
281
- const md = await this.notionService.getPageInSpecificFormat(notionPageId, NotionExportType.HTML);
282
- console.log(md);
283
- this.lesson.textCoded = md.content;
284
- this.togleRender();
285
- this.toastService.success({ title: 'Listo', subtitle: 'La lección se importó correctamente' });
286
- }
287
-
288
- extractNotionPageId(url: string) {
289
- const notionIdRegex = /[a-f0-9]{32}(?=\?|$)/;
290
- const match = url.match(notionIdRegex);
291
- const notionId = match ? match[0] : null;
292
- if (!notionId) {
293
- this.toastService.error({
294
- title: 'URL inválido',
295
- subtitle: 'Por favor ingresa una URL válida de Notion',
296
- });
297
- }
298
- return notionId;
299
- }
300
-
301
- public async linkWithNotion(notionPageId: string) {
302
- const extra = this.lesson.extras || {};
303
- extra.notionPageId = notionPageId;
304
-
305
- await this.lessonService.postLesson({ ...this.lesson, extras: extra });
306
- this.toastService.success({ title: 'Listo', subtitle: 'Se enlazó la lección con Notion' });
307
- }
308
-
309
- public async improveNotionWithAI() {
310
- const md = await this.notionService.getPageInSpecificFormat(this.lesson.extras.notionPageId, NotionExportType.HTML);
311
- console.log(md);
312
-
313
- // this.lesson.textCoded = md.content;
314
-
315
- // this.togleRender();
316
- // this.toastService.success({ title: 'Listo', subtitle: 'La lección se mejoró con AI' });
317
- }
318
- }