@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.
Files changed (86) hide show
  1. package/README.md +56 -10
  2. package/fesm2022/dataclouder-ngx-lessons.mjs +292 -81
  3. package/fesm2022/dataclouder-ngx-lessons.mjs.map +1 -1
  4. package/lib/components/dc-lessons/dc-lesson-editor/dc-lesson-editor.component.d.ts +9 -5
  5. package/lib/components/dc-lessons/dc-lesson-renderer/dc-lesson-renderer.component.d.ts +3 -1
  6. package/lib/components/lesson-mini-components/components/lessons.clases.d.ts +1 -0
  7. package/lib/models/simple-agents.d.ts +2 -0
  8. package/lib/services/lesson-ai.service.d.ts +15 -2
  9. package/lib/services/lesson-utils.service.d.ts +10 -1
  10. package/package.json +1 -1
  11. package/public-api.d.ts +1 -0
  12. package/src/lib/components/dc-lessons/dc-lesson-card/dc-lesson-card.component.html +0 -40
  13. package/src/lib/components/dc-lessons/dc-lesson-card/dc-lesson-card.component.scss +0 -120
  14. package/src/lib/components/dc-lessons/dc-lesson-card/dc-lesson-card.component.ts +0 -82
  15. package/src/lib/components/dc-lessons/dc-lesson-component-adder/dc-lesson-component-adder.component.css +0 -1
  16. package/src/lib/components/dc-lessons/dc-lesson-component-adder/dc-lesson-component-adder.component.html +0 -46
  17. package/src/lib/components/dc-lessons/dc-lesson-component-adder/dc-lesson-component-adder.component.ts +0 -52
  18. package/src/lib/components/dc-lessons/dc-lesson-editor/dc-lesson-editor.component.css +0 -90
  19. package/src/lib/components/dc-lessons/dc-lesson-editor/dc-lesson-editor.component.html +0 -67
  20. package/src/lib/components/dc-lessons/dc-lesson-editor/dc-lesson-editor.component.scss +0 -0
  21. package/src/lib/components/dc-lessons/dc-lesson-editor/dc-lesson-editor.component.ts +0 -356
  22. package/src/lib/components/dc-lessons/dc-lesson-metadata-editor/dc-lesson-metadata-editor.component.css +0 -1
  23. package/src/lib/components/dc-lessons/dc-lesson-metadata-editor/dc-lesson-metadata-editor.component.html +0 -72
  24. package/src/lib/components/dc-lessons/dc-lesson-metadata-editor/dc-lesson-metadata-editor.component.ts +0 -60
  25. package/src/lib/components/dc-lessons/dc-lesson-renderer/dc-lesson-renderer.component.html +0 -23
  26. package/src/lib/components/dc-lessons/dc-lesson-renderer/dc-lesson-renderer.component.scss +0 -3
  27. package/src/lib/components/dc-lessons/dc-lesson-renderer/dc-lesson-renderer.component.ts +0 -332
  28. package/src/lib/components/dc-lessons/lesson-form/lesson-form.component.html +0 -5
  29. package/src/lib/components/dc-lessons/lesson-form/lesson-form.component.scss +0 -3
  30. package/src/lib/components/dc-lessons/lesson-form/lesson-form.component.ts +0 -14
  31. package/src/lib/components/dc-lessons/lesson-list/dc-lesson-list.component.html +0 -30
  32. package/src/lib/components/dc-lessons/lesson-list/dc-lesson-list.component.scss +0 -17
  33. package/src/lib/components/dc-lessons/lesson-list/dc-lesson-list.component.ts +0 -170
  34. package/src/lib/components/dc-lessons/lessons.component.ts +0 -10
  35. package/src/lib/components/lesson-mini-components/components/ComponentBuilder.ts +0 -82
  36. package/src/lib/components/lesson-mini-components/components/ComponentWithForm.ts +0 -25
  37. package/src/lib/components/lesson-mini-components/components/lesson-dynamic.component.ts +0 -13
  38. package/src/lib/components/lesson-mini-components/components/lessons.clases.ts +0 -220
  39. package/src/lib/components/lesson-mini-components/components/selector/selector-builder/selector-builder.component.html +0 -62
  40. package/src/lib/components/lesson-mini-components/components/selector/selector-builder/selector-builder.component.scss +0 -15
  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 -1
  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 -13
  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.ts +0 -40
  49. package/src/lib/components/lesson-mini-components/components/speaker/speaker.component.html +0 -9
  50. package/src/lib/components/lesson-mini-components/components/speaker/speaker.component.scss +0 -3
  51. package/src/lib/components/lesson-mini-components/components/speaker/speaker.component.ts +0 -33
  52. package/src/lib/components/lesson-mini-components/components/text-writer/text-writer-buider/text-writer-buider.component.html +0 -24
  53. package/src/lib/components/lesson-mini-components/components/text-writer/text-writer-buider/text-writer-buider.component.scss +0 -15
  54. package/src/lib/components/lesson-mini-components/components/text-writer/text-writer-buider/text-writer-buider.component.spec.ts +0 -25
  55. package/src/lib/components/lesson-mini-components/components/text-writer/text-writer-buider/text-writer-buider.component.ts +0 -29
  56. package/src/lib/components/lesson-mini-components/components/text-writer/text-writer.component.html +0 -4
  57. package/src/lib/components/lesson-mini-components/components/text-writer/text-writer.component.scss +0 -8
  58. package/src/lib/components/lesson-mini-components/components/text-writer/text-writer.component.spec.ts +0 -25
  59. package/src/lib/components/lesson-mini-components/components/text-writer/text-writer.component.ts +0 -61
  60. package/src/lib/components/lesson-mini-components/components/translationSwitcher/translationSwitcher.component.css +0 -3
  61. package/src/lib/components/lesson-mini-components/components/translationSwitcher/translationSwitcher.component.html +0 -9
  62. package/src/lib/components/lesson-mini-components/components/translationSwitcher/translationSwitcher.component.ts +0 -32
  63. package/src/lib/components/lesson-mini-components/components/translationSwitcher/translationSwitcherBuilder/translationSwitcherBuilder.component.css +0 -3
  64. package/src/lib/components/lesson-mini-components/components/translationSwitcher/translationSwitcherBuilder/translationSwitcherBuilder.component.html +0 -28
  65. package/src/lib/components/lesson-mini-components/components/translationSwitcher/translationSwitcherBuilder/translationSwitcherBuilder.component.ts +0 -30
  66. package/src/lib/components/lesson-mini-components/components/verb-summary/verb-summary-builder/verb-summary-builder.component.html +0 -18
  67. package/src/lib/components/lesson-mini-components/components/verb-summary/verb-summary-builder/verb-summary-builder.component.scss +0 -3
  68. package/src/lib/components/lesson-mini-components/components/verb-summary/verb-summary-builder/verb-summary-builder.component.spec.ts +0 -25
  69. package/src/lib/components/lesson-mini-components/components/verb-summary/verb-summary-builder/verb-summary-builder.component.ts +0 -25
  70. package/src/lib/components/lesson-mini-components/components/verb-summary/verb-summary.component.html +0 -15
  71. package/src/lib/components/lesson-mini-components/components/verb-summary/verb-summary.component.scss +0 -27
  72. package/src/lib/components/lesson-mini-components/components/verb-summary/verb-summary.component.spec.ts +0 -25
  73. package/src/lib/components/lesson-mini-components/components/verb-summary/verb-summary.component.ts +0 -46
  74. package/src/lib/components/lesson-mini-components/components/word-summary/word-summary-builder/word-summary-builder.component.html +0 -19
  75. package/src/lib/components/lesson-mini-components/components/word-summary/word-summary-builder/word-summary-builder.component.scss +0 -0
  76. package/src/lib/components/lesson-mini-components/components/word-summary/word-summary-builder/word-summary-builder.component.ts +0 -27
  77. package/src/lib/components/lesson-mini-components/components/word-summary/word-summary.component.html +0 -14
  78. package/src/lib/components/lesson-mini-components/components/word-summary/word-summary.component.scss +0 -22
  79. package/src/lib/components/lesson-mini-components/components/word-summary/word-summary.component.ts +0 -51
  80. package/src/lib/models/lessons.pipes.ts +0 -38
  81. package/src/lib/models/models.ts +0 -92
  82. package/src/lib/models/notion.models.ts +0 -43
  83. package/src/lib/services/lesson-ai.service.ts +0 -103
  84. package/src/lib/services/lesson-notion.service.ts +0 -161
  85. package/src/lib/services/lesson-utils.service.ts +0 -181
  86. package/src/public-api.ts +0 -25
@@ -17,11 +17,11 @@ import { DropdownModule } from 'primeng/dropdown';
17
17
  import { NgxTtsComponent } from '@dataclouder/ngx-tts';
18
18
  import * as i2$3 from 'primeng/paginator';
19
19
  import { PaginatorModule } from 'primeng/paginator';
20
- import { DatePipe, NgComponentOutlet, KeyValuePipe, CommonModule, JsonPipe } from '@angular/common';
20
+ import { DatePipe, NgComponentOutlet, KeyValuePipe, CommonModule } from '@angular/common';
21
21
  import * as i1$2 from '@angular/router';
22
22
  import { RouterModule, ActivatedRoute, Router } from '@angular/router';
23
23
  import * as i4$1 from '@dataclouder/ngx-core';
24
- import { PaginationBase, TOAST_ALERTS_TOKEN, DCFilterBarComponent, QuickTableComponent } from '@dataclouder/ngx-core';
24
+ import { PaginationBase, TOAST_ALERTS_TOKEN, DCFilterBarComponent, QuickTableComponent, LoadingBarService } from '@dataclouder/ngx-core';
25
25
  import { PopoverModule } from 'primeng/popover';
26
26
  import * as i2$2 from 'primeng/speeddial';
27
27
  import { SpeedDialModule } from 'primeng/speeddial';
@@ -37,9 +37,11 @@ import { SplitterModule } from 'primeng/splitter';
37
37
  import * as i2$5 from 'primeng/tooltip';
38
38
  import { TooltipModule } from 'primeng/tooltip';
39
39
  import { ResolutionType, AspectType, CropperComponentModal } from '@dataclouder/ngx-cloud-storage';
40
- import { TextEngines, ConversationType, DCChatComponent } from '@dataclouder/ngx-agent-cards';
40
+ import { TextEngines, ConversationType, USER_DATA_EXCHANGE, ChatRole, DCChatComponent, CONVERSATION_AI_TOKEN } from '@dataclouder/ngx-agent-cards';
41
41
  import * as i2$4 from 'primeng/drawer';
42
42
  import { DrawerModule } from 'primeng/drawer';
43
+ import TurndownService from 'turndown';
44
+ import { marked } from 'marked';
43
45
  import * as i2$6 from 'primeng/api';
44
46
 
45
47
  class ComponentBuilder {
@@ -535,6 +537,89 @@ var NotionExportType;
535
537
  NotionExportType["SIMPLE_BLOCKS"] = "simple_blocks";
536
538
  })(NotionExportType || (NotionExportType = {}));
537
539
 
540
+ const MarkdownWriterSkill = `
541
+ You are an Expert Markdown Writer with the following qualities:
542
+ 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.
543
+ Your Core Skills 📝
544
+
545
+ You transform complex information into beautifully structured Markdown documents
546
+ You strategically use headings, lists, and formatting to create clear visual hierarchies
547
+ You incorporate helpful emojis to enhance readability and engagement
548
+ You write in a clear, concise style that's accessible to general audiences
549
+
550
+ Your Process Approach 🔄
551
+
552
+ You always begin with a logical document structure before adding content
553
+ You organize information into clearly defined sections with descriptive headings
554
+ You balance visual elements with textual content for optimal readability
555
+ You maintain consistent formatting patterns throughout documents
556
+
557
+ Your Writing Style ✨
558
+
559
+ You use simple, direct language that's easy for everyone to understand
560
+ You explain technical concepts using everyday examples and analogies
561
+ You create a friendly, conversational tone while maintaining professionalism
562
+ You break down complex ideas into manageable segments
563
+
564
+ Your Special Touches 🎯
565
+
566
+ You know exactly when and where to add emojis for maximum impact
567
+ You create custom tables to present comparative information effectively
568
+ You use blockquotes to highlight important takeaways
569
+ You incorporate visual dividers to separate major content sections
570
+
571
+ 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.
572
+ `;
573
+ const EnglishLessonSkill = `
574
+
575
+ You are also an English lesson professor, you write lessons for Spanish learners.
576
+ explain the best you can will all your experience teaching.
577
+
578
+ You can infer the level of the lesson from the content or user request, so can increase difficulty
579
+
580
+ For Basic Level: generate an English lesson for Spanish learners at a basic level (A1-A2).
581
+
582
+ Include:
583
+
584
+ - Simple dialogues or short texts.
585
+ - Key vocabulary with simple definitions or Spanish translations.
586
+ - Basic grammar points explained simply (e.g., "to be" verb, simple present).
587
+ - Practice exercises (e.g., fill-in-the-blanks, simple questions).
588
+
589
+ For Intermediate Level: generate an English lesson for Spanish learners at a medium level (B1-B2).
590
+
591
+ Include:
592
+
593
+ - Texts or dialogues of moderate length and complexity.
594
+ - New vocabulary and common phrasal verbs with context.
595
+ - Explanation and practice of intermediate grammar points (e.g., past simple vs. present perfect, conditionals).
596
+ - Exercises that require more detailed responses or understanding.
597
+ - The content should be engaging and cover topics relevant to daily life, work, or hobbies.
598
+
599
+ For Advanced Level: generate an English lesson for Spanish learners at an advanced level (C1-C2).
600
+
601
+ Include:
602
+
603
+ - Challenging texts or discussions.
604
+ - Advanced vocabulary, idioms, and nuanced expressions.
605
+ - Exploration of complex grammar or stylistic points.
606
+ - Exercises that encourage critical thinking, debate, or detailed writing.
607
+ - The content should be stimulating and cover a wide range of topics, including academic or professional contexts.
608
+
609
+ `;
610
+ const UserRequirements = `
611
+ User also can provide additional instructions or requirements for the lesson or current lesson to improve it.
612
+ `;
613
+ const BasicAgentCard$1 = {
614
+ systemPrompt: `
615
+ ${MarkdownWriterSkill}
616
+ ${EnglishLessonSkill}
617
+ ${UserRequirements}
618
+
619
+ `,
620
+ model: { id: 'gemini-2.5-flash-preview-04-17', provider: 'google' },
621
+ };
622
+
538
623
  var EventCard;
539
624
  (function (EventCard) {
540
625
  EventCard["Edit"] = "edit";
@@ -630,7 +715,6 @@ class DCLessonListComponent extends PaginationBase {
630
715
  this.showOptions = true;
631
716
  this.customFilters = [];
632
717
  this.viewType = 'cards';
633
- // readonly actions = input<MenuItem[]>(TableViewActions);
634
718
  this.columns = tableViewColumns;
635
719
  this.cardComponent = null;
636
720
  this.cardEventSubs = [];
@@ -769,6 +853,18 @@ const DEFAULT_LESSON_AGENT_CARD = {
769
853
  },
770
854
  model: { provider: 'google' },
771
855
  };
856
+ const AppRolePlaySkill = `
857
+ 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.
858
+ Ask friendly questions throughout the conversation and help them learn English.
859
+ `;
860
+ const EngagementSkill = `
861
+ 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.
862
+ that makes sense for the lesson.
863
+ `;
864
+ const BasicAgentCard = {
865
+ systemPrompt: 'You are a helpful assistant.',
866
+ model: { provider: 'openai', id: 'gpt-4o' },
867
+ };
772
868
  function getDefaultLessonEvaluatorAgentCard(lessonText) {
773
869
  return {
774
870
  expectedResponseType: `interface EvalResult {
@@ -784,10 +880,25 @@ function getDefaultLessonEvaluatorAgentCard(lessonText) {
784
880
  };
785
881
  }
786
882
  class LessonAIService {
787
- // TODO: Inject the application-level UserService
788
- // private readonly userService = inject(UserService);
789
883
  constructor() {
790
884
  this.lessonService = inject(LESSONS_TOKEN);
885
+ // TODO: Inject the application-level UserService
886
+ this.userService = inject(USER_DATA_EXCHANGE);
887
+ }
888
+ /**
889
+ * Builds the scenario prompt string based on lesson content and user info.
890
+ * @param lessonText The extracted text content of the lesson.
891
+ * @param userInformationPrompt The formatted string containing user details.
892
+ * @returns The complete scenario prompt string.
893
+ */
894
+ _buildScenarioPrompt(lessonText, userInformationPrompt) {
895
+ return `
896
+ ${AppRolePlaySkill}
897
+ <Lesson Text>
898
+ ${lessonText}
899
+ ${EngagementSkill}
900
+ <User Information>
901
+ ${userInformationPrompt}`;
791
902
  }
792
903
  /**
793
904
  * Generates the necessary agent cards for a lesson chat session.
@@ -795,43 +906,48 @@ class LessonAIService {
795
906
  * @returns An object containing the master agent card and the evaluator agent card.
796
907
  */
797
908
  async generateAgentCards(lesson) {
798
- // TODO: Implement the logic moved from DCLessonRendererComponent.startAI here
799
- // 1. Get user data using the injected UserService
800
- // 2. Extract lesson text using lessonService
801
- // 3. Build prompts (scenario, userInformationPrompt)
802
- // 4. Configure and return the agent cards
803
- alert('AI User data fetching needs refactoring into this service.');
804
- // Placeholder for user data - replace with actual service call
909
+ const lessonText = this.lessonService.extractTextFromHtml(lesson.textCoded);
910
+ const userInformationPrompt = this.userService.getUserDataInformation();
911
+ const scenario = this._buildScenarioPrompt(lessonText, userInformationPrompt);
912
+ // Create a deep copy of the default card to avoid modifying the constant
913
+ const masterAgent = JSON.parse(JSON.stringify(DEFAULT_LESSON_AGENT_CARD));
914
+ masterAgent.characterCard.data.scenario = scenario;
915
+ masterAgent.characterCard.data.post_history_instructions += `\n${userInformationPrompt}`;
916
+ const evaluatorAgent = getDefaultLessonEvaluatorAgentCard(lessonText);
917
+ return { masterAgent, evaluatorAgent };
918
+ }
919
+ /**
920
+ * Generates conversation settings for a lesson, using the lesson scenario as the initial prompt.
921
+ * @param lesson The lesson data.
922
+ * @returns An IConversationSettings object configured for the lesson scenario.
923
+ */
924
+ async generateConversationSettingsForLesson(lesson) {
925
+ // TODO: Consolidate user fetching logic if possible, or ensure consistency
805
926
  const user = {
806
927
  personalData: { firstname: 'Test', lastname: 'User' },
807
928
  settings: { targetLanguage: 'en', baseLanguage: 'es' },
808
929
  languageProgress: { en: { level: '1' } },
809
930
  }; // Replace 'any' with your actual User type/interface
810
931
  if (!user) {
811
- console.error('User data not available to generate agent cards.');
812
- // Handle error appropriately - maybe return null or throw?
932
+ console.error('User data not available to generate conversation settings.');
813
933
  return null;
814
934
  }
815
935
  const lessonText = this.lessonService.extractTextFromHtml(lesson.textCoded);
816
- const scenario = `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.
817
- Ask friendly questions throughout the conversation and help them learn English. Here is the lesson text the user just read:
818
- ${lessonText}
819
- In your next reply, start by greeting the user, asking something about the lesson, and then continue the conversation.`;
820
- const targetLevel = parseInt(user.languageProgress[user.settings.targetLanguage]?.level ?? '1');
821
- const langTargetDesc = LangCodeDescription[user.settings.targetLanguage] ?? user.settings.targetLanguage;
822
- const langBaseDesc = LangCodeDescription[user.settings.baseLanguage] ?? user.settings.baseLanguage;
823
- let userInformationPrompt = `
824
- User information: user name is ${user.personalData.firstname} ${user.personalData.lastname}, their native language is ${langBaseDesc},
825
- and right now is learning ${langTargetDesc}, their current level is ${targetLevel} out of 5.`;
826
- if (targetLevel <= 2) {
827
- userInformationPrompt += `\nUser is a beginner in ${langTargetDesc}, always reply mainly in ${langBaseDesc}, but during the conversation use simple words and phrases in ${langTargetDesc} to help them learn.`;
828
- }
829
- // Create a deep copy of the default card to avoid modifying the constant
830
- const masterAgent = JSON.parse(JSON.stringify(DEFAULT_LESSON_AGENT_CARD));
831
- masterAgent.characterCard.data.scenario = scenario;
832
- masterAgent.characterCard.data.post_history_instructions += `\n${userInformationPrompt}`;
833
- const evaluatorAgent = getDefaultLessonEvaluatorAgentCard(lessonText);
834
- return { masterAgent, evaluatorAgent };
936
+ const userInformationPrompt = this.userService.getUserDataInformation();
937
+ const scenario = this._buildScenarioPrompt(lessonText, userInformationPrompt);
938
+ const initialMessage = {
939
+ role: ChatRole.System,
940
+ content: scenario,
941
+ };
942
+ // Use defaults similar to DEFAULT_LESSON_AGENT_CARD but adjust for prompt-based start
943
+ const conversationSettings = {
944
+ conversationType: ConversationType.General,
945
+ textEngine: TextEngines.SimpleText,
946
+ autoStart: true,
947
+ messages: [initialMessage],
948
+ model: { provider: 'google' },
949
+ };
950
+ return conversationSettings;
835
951
  }
836
952
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: LessonAIService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
837
953
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: LessonAIService, providedIn: 'root' }); }
@@ -841,7 +957,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImpor
841
957
  args: [{
842
958
  providedIn: 'root', // Or provide appropriately if it's library-specific
843
959
  }]
844
- }], ctorParameters: () => [] });
960
+ }] });
845
961
 
846
962
  class DCLessonRendererComponent {
847
963
  constructor() {
@@ -860,11 +976,13 @@ class DCLessonRendererComponent {
860
976
  this.chatVisible = signal(false); // Signal for chat visibility
861
977
  this.agentMasterLesson = signal(undefined); // Signal for agent card
862
978
  this.evaluatorAgentCard = signal(undefined); // Signal for evaluator card
979
+ this.conversationSettings = signal(undefined);
863
980
  // --- Computed Signals ---
864
981
  this.imageCover = computed(() => this.lesson()?.media?.images?.find((img) => img.type === 'cover')?.url); // Computed signal for imageCover
865
982
  // --- Properties ---
866
983
  this.components = {};
867
984
  this.mainForm = new FormGroup({});
985
+ this.previousTextCoded = undefined; // Store previous value
868
986
  // Effect to fetch lesson data if ID is provided and lesson object isn't
869
987
  effect(async () => {
870
988
  const lessonInput = this.lessonInput();
@@ -874,7 +992,7 @@ class DCLessonRendererComponent {
874
992
  }
875
993
  else if (lessonId && !this.lesson()) {
876
994
  // Fetch only if ID exists and internal lesson is not set
877
- console.log(`Fetching lesson with ID: ${lessonId}`);
995
+ console.log(`[Renderer] Effect 1: Fetching lesson ${lessonId}`);
878
996
  try {
879
997
  // Consider adding a loading state signal here
880
998
  const fetchedLesson = await this.lessonService.getLesson(lessonId);
@@ -895,15 +1013,23 @@ class DCLessonRendererComponent {
895
1013
  this.lesson.set(undefined);
896
1014
  }
897
1015
  }, { allowSignalWrites: true }); // Allow signal writes inside effect
898
- // Effect to render the lesson whenever the lesson signal changes
1016
+ // Effect to render the lesson only when textCoded value actually changes
899
1017
  effect(() => {
900
- const currentLesson = this.lesson();
901
- if (currentLesson) {
902
- this._renderLesson(currentLesson);
1018
+ const currentLesson = this.lesson(); // Read the lesson signal
1019
+ const newTextCoded = currentLesson?.textCoded; // Get the current textCoded value
1020
+ // Quick fix to only render on changes textCode not all the lesson
1021
+ if (newTextCoded !== this.previousTextCoded) {
1022
+ if (newTextCoded !== undefined && newTextCoded !== null && currentLesson) {
1023
+ this._renderLesson(currentLesson);
1024
+ }
1025
+ else {
1026
+ this._clearLessonRendering();
1027
+ }
1028
+ // Update the stored previous value *after* comparison and action
1029
+ this.previousTextCoded = newTextCoded;
903
1030
  }
904
1031
  else {
905
- // Clear previous rendering if lesson becomes undefined
906
- this._clearLessonRendering();
1032
+ console.log('[Renderer] textCoded has NOT changed. Skipping render/clear.');
907
1033
  }
908
1034
  });
909
1035
  }
@@ -936,6 +1062,7 @@ class DCLessonRendererComponent {
936
1062
  _parseAndCreateComponents(lessonData) {
937
1063
  const r1 = new RegExp('~(.+?)~', 'g');
938
1064
  let count = 0;
1065
+ //
939
1066
  const createdComponents = {};
940
1067
  const htmlContent = lessonData.textCoded.replace(r1, (_matching, jsonCoded) => {
941
1068
  const componentName = `dynamicComp${count}`;
@@ -979,7 +1106,7 @@ class DCLessonRendererComponent {
979
1106
  _createComponentReferenceWithJson(json, currentLesson) {
980
1107
  try {
981
1108
  let lessonCodedConfig = JSON.parse(json);
982
- debugger;
1109
+ //
983
1110
  // Attempt to find pre-configured component data in the lesson object by ID
984
1111
  if (lessonCodedConfig.id && currentLesson?.dynamicComponents[lessonCodedConfig.id]) {
985
1112
  const foundConfig = currentLesson.dynamicComponents[lessonCodedConfig.id];
@@ -1095,10 +1222,11 @@ class DCLessonRendererComponent {
1095
1222
  console.log('Requesting agent cards from LessonAIService...');
1096
1223
  try {
1097
1224
  // Call the service to get the agent cards
1098
- const agentCards = await this.lessonAIService.generateAgentCards(currentLesson);
1099
- if (agentCards) {
1100
- this.agentMasterLesson.set(agentCards.masterAgent);
1101
- this.evaluatorAgentCard.set(agentCards.evaluatorAgent);
1225
+ const conversationSettings = await this.lessonAIService.generateConversationSettingsForLesson(currentLesson);
1226
+ if (conversationSettings) {
1227
+ // this.agentMasterLesson.set(agentCards);
1228
+ // this.evaluatorAgentCard.set(agentCards.evaluatorAgent);
1229
+ this.conversationSettings.set(conversationSettings);
1102
1230
  this.chatVisible.set(true);
1103
1231
  console.log('Agent cards received and set.');
1104
1232
  }
@@ -1113,11 +1241,11 @@ class DCLessonRendererComponent {
1113
1241
  }
1114
1242
  }
1115
1243
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DCLessonRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1116
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.4", type: DCLessonRendererComponent, isStandalone: true, selector: "dc-lesson-renderer", inputs: { lessonInput: { classPropertyName: "lessonInput", publicName: "lessonInput", isSignal: true, isRequired: false, transformFunction: null }, lessonIdInput: { classPropertyName: "lessonIdInput", publicName: "lessonIdInput", isSignal: true, isRequired: false, transformFunction: null }, test: { classPropertyName: "test", publicName: "test", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "dynamicLesson", first: true, predicate: ["dynamicLesson"], descendants: true, static: true }], ngImport: i0, template: "<div>\n <div #dynamicLesson class=\"targetclass\">\n <ng-template #target></ng-template>\n </div>\n</div>\n\n<br />\n<div style=\"display: flex; gap: 10px\">\n @if ((mainForm.controls | keyvalue)?.length) {\n <div>\n <p-button label=\"Calificar Lecci\u00F3n\" icon=\"pi pi-check-circle\" (click)=\"evaluateForms()\" [rounded]=\"true\"></p-button>\n </div>\n }\n\n <p-button icon=\"pi pi-verified\" [rounded]=\"true\" (click)=\"startAI()\" label=\"Repasar con IA\" />\n</div>\n<br /><br />\n\n@if(chatVisible()) {\n<p-drawer header=\"Conversation\" [visible]=\"chatVisible()\" position=\"bottom\" styleClass=\"app-bottom-overlay\">\n <dc-chat [agentCard]=\"agentMasterLesson()\" [evaluatorAgentCard]=\"evaluatorAgentCard()\"></dc-chat>\n</p-drawer>\n}\n", styles: [".evaluate{float:right}\n"], dependencies: [{ kind: "pipe", type: KeyValuePipe, name: "keyvalue" }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: DCChatComponent, selector: "dc-chat", inputs: ["chatUserSettings", "conversationSettings", "agentCard", "evaluatorAgentCard", "parseDict"], outputs: ["sendMessage", "goalCompleted"] }, { kind: "ngmodule", type: DrawerModule }, { kind: "component", type: i2$4.Drawer, selector: "p-drawer", inputs: ["appendTo", "blockScroll", "style", "styleClass", "ariaCloseLabel", "autoZIndex", "baseZIndex", "modal", "closeButtonProps", "dismissible", "showCloseIcon", "closeOnEscape", "transitionOptions", "visible", "position", "fullScreen", "header", "maskStyle", "closable"], outputs: ["onShow", "onHide", "visibleChange"] }] }); }
1244
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.4", type: DCLessonRendererComponent, isStandalone: true, selector: "dc-lesson-renderer", inputs: { lessonInput: { classPropertyName: "lessonInput", publicName: "lessonInput", isSignal: true, isRequired: false, transformFunction: null }, lessonIdInput: { classPropertyName: "lessonIdInput", publicName: "lessonIdInput", isSignal: true, isRequired: false, transformFunction: null }, test: { classPropertyName: "test", publicName: "test", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "dynamicLesson", first: true, predicate: ["dynamicLesson"], descendants: true, static: true }], ngImport: i0, template: "<div>\n <div #dynamicLesson class=\"targetclass\">\n <ng-template #target></ng-template>\n </div>\n</div>\n\n<br />\n<div style=\"display: flex; gap: 10px\">\n @if ((mainForm.controls | keyvalue)?.length) {\n <div>\n <p-button label=\"Calificar Lecci\u00F3n\" icon=\"pi pi-check-circle\" (click)=\"evaluateForms()\" [rounded]=\"true\"></p-button>\n </div>\n }\n\n <p-button icon=\"pi pi-verified\" [rounded]=\"true\" (click)=\"startAI()\" label=\"Repasar con IA\" />\n</div>\n<br /><br />\n\n@if(chatVisible()) {\n<p-drawer header=\"Conversation\" [visible]=\"chatVisible()\" position=\"bottom\" styleClass=\"app-bottom-overlay\">\n <dc-chat [conversationSettings]=\"conversationSettings()\"></dc-chat>\n</p-drawer>\n}\n", styles: [".evaluate{float:right}\n"], dependencies: [{ kind: "pipe", type: KeyValuePipe, name: "keyvalue" }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: DCChatComponent, selector: "dc-chat", inputs: ["chatUserSettings", "conversationSettings", "agentCard", "evaluatorAgentCard", "parseDict"], outputs: ["sendMessage", "goalCompleted"] }, { kind: "ngmodule", type: DrawerModule }, { kind: "component", type: i2$4.Drawer, selector: "p-drawer", inputs: ["appendTo", "blockScroll", "style", "styleClass", "ariaCloseLabel", "autoZIndex", "baseZIndex", "modal", "closeButtonProps", "dismissible", "showCloseIcon", "closeOnEscape", "transitionOptions", "visible", "position", "fullScreen", "header", "maskStyle", "closable"], outputs: ["onShow", "onHide", "visibleChange"] }] }); }
1117
1245
  }
1118
1246
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DCLessonRendererComponent, decorators: [{
1119
1247
  type: Component,
1120
- args: [{ selector: 'dc-lesson-renderer', standalone: true, imports: [KeyValuePipe, ButtonModule, DCChatComponent, DrawerModule], template: "<div>\n <div #dynamicLesson class=\"targetclass\">\n <ng-template #target></ng-template>\n </div>\n</div>\n\n<br />\n<div style=\"display: flex; gap: 10px\">\n @if ((mainForm.controls | keyvalue)?.length) {\n <div>\n <p-button label=\"Calificar Lecci\u00F3n\" icon=\"pi pi-check-circle\" (click)=\"evaluateForms()\" [rounded]=\"true\"></p-button>\n </div>\n }\n\n <p-button icon=\"pi pi-verified\" [rounded]=\"true\" (click)=\"startAI()\" label=\"Repasar con IA\" />\n</div>\n<br /><br />\n\n@if(chatVisible()) {\n<p-drawer header=\"Conversation\" [visible]=\"chatVisible()\" position=\"bottom\" styleClass=\"app-bottom-overlay\">\n <dc-chat [agentCard]=\"agentMasterLesson()\" [evaluatorAgentCard]=\"evaluatorAgentCard()\"></dc-chat>\n</p-drawer>\n}\n", styles: [".evaluate{float:right}\n"] }]
1248
+ args: [{ selector: 'dc-lesson-renderer', standalone: true, imports: [KeyValuePipe, ButtonModule, DCChatComponent, DrawerModule], template: "<div>\n <div #dynamicLesson class=\"targetclass\">\n <ng-template #target></ng-template>\n </div>\n</div>\n\n<br />\n<div style=\"display: flex; gap: 10px\">\n @if ((mainForm.controls | keyvalue)?.length) {\n <div>\n <p-button label=\"Calificar Lecci\u00F3n\" icon=\"pi pi-check-circle\" (click)=\"evaluateForms()\" [rounded]=\"true\"></p-button>\n </div>\n }\n\n <p-button icon=\"pi pi-verified\" [rounded]=\"true\" (click)=\"startAI()\" label=\"Repasar con IA\" />\n</div>\n<br /><br />\n\n@if(chatVisible()) {\n<p-drawer header=\"Conversation\" [visible]=\"chatVisible()\" position=\"bottom\" styleClass=\"app-bottom-overlay\">\n <dc-chat [conversationSettings]=\"conversationSettings()\"></dc-chat>\n</p-drawer>\n}\n", styles: [".evaluate{float:right}\n"] }]
1121
1249
  }], ctorParameters: () => [], propDecorators: { dynamicLesson: [{
1122
1250
  type: ViewChild,
1123
1251
  args: ['dynamicLesson', { static: true }]
@@ -1289,9 +1417,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImpor
1289
1417
  }] });
1290
1418
 
1291
1419
  class LessonUtilsService {
1292
- #lessonService = inject(LESSONS_TOKEN);
1293
- #toastService = inject(TOAST_ALERTS_TOKEN);
1294
- constructor() { }
1420
+ constructor() {
1421
+ this.#lessonService = inject(LESSONS_TOKEN);
1422
+ this.#toastService = inject(TOAST_ALERTS_TOKEN);
1423
+ this.#agentService = inject(CONVERSATION_AI_TOKEN);
1424
+ this.loadingBarService = inject(LoadingBarService);
1425
+ }
1426
+ #lessonService;
1427
+ #toastService;
1428
+ #agentService;
1295
1429
  /**
1296
1430
  * Validates if audios need generation for the given lesson.
1297
1431
  * Currently logs a placeholder message.
@@ -1393,6 +1527,63 @@ class LessonUtilsService {
1393
1527
  }
1394
1528
  // Loading state should be managed by the component calling this service.
1395
1529
  }
1530
+ /**
1531
+ * Improves the provided Markdown text using AI and updates the lesson.
1532
+ * Assumes the lesson is already saved before calling this.
1533
+ * @param lessonId The ID of the lesson to update.
1534
+ * @param markdownText The Markdown text generated from the lesson's HTML content.
1535
+ * @returns The updated lesson object after AI improvement, or null on failure.
1536
+ */
1537
+ async improveMDWithAI(lesson, markdownText) {
1538
+ if (!markdownText) {
1539
+ this.#toastService.warn({ title: 'Texto Requerido', subtitle: 'Se necesita texto Markdown para mejorar con IA.' });
1540
+ return null;
1541
+ }
1542
+ try {
1543
+ this.loadingBarService.showIndeterminate();
1544
+ const agentCard = BasicAgentCard$1;
1545
+ let task = `Improve the following lesson return only the lesson markdown: ${markdownText}`;
1546
+ if (lesson.prompt) {
1547
+ task = `${task} Also consider the original prompt: ${lesson.prompt} when improving the lesson.`;
1548
+ }
1549
+ const appTask = { task: task };
1550
+ const messages = [
1551
+ { content: agentCard.systemPrompt, role: ChatRole.System },
1552
+ { content: appTask.task, role: ChatRole.User },
1553
+ ];
1554
+ const response = await this.#agentService.callChatCompletion({ messages, model: agentCard.model });
1555
+ let improvedMarkdown = response.content;
1556
+ // Remove potential markdown fences
1557
+ const markdownFenceStart = '```markdown\n';
1558
+ const markdownFenceEnd = '\n```';
1559
+ if (improvedMarkdown.startsWith(markdownFenceStart) && improvedMarkdown.endsWith(markdownFenceEnd)) {
1560
+ improvedMarkdown = improvedMarkdown.slice(markdownFenceStart.length, -markdownFenceEnd.length);
1561
+ }
1562
+ else {
1563
+ // Also handle cases where it might just be ``` at the start/end
1564
+ const simpleFence = '```';
1565
+ if (improvedMarkdown.startsWith(simpleFence)) {
1566
+ improvedMarkdown = improvedMarkdown.slice(simpleFence.length);
1567
+ }
1568
+ if (improvedMarkdown.endsWith(simpleFence)) {
1569
+ improvedMarkdown = improvedMarkdown.slice(0, -simpleFence.length);
1570
+ }
1571
+ }
1572
+ // Trim any leading/trailing whitespace that might remain after removing fences
1573
+ improvedMarkdown = improvedMarkdown.trim();
1574
+ console.log('Improved Markdown:', improvedMarkdown);
1575
+ return improvedMarkdown;
1576
+ }
1577
+ catch (error) {
1578
+ console.error('Error during AI Markdown improvement in service:', error);
1579
+ this.#toastService.error({ title: 'Error de IA', subtitle: 'No se pudo mejorar la lección con IA.' });
1580
+ return null; // Return null in catch block
1581
+ }
1582
+ finally {
1583
+ this.loadingBarService.successAndHide();
1584
+ }
1585
+ // Loading state should be managed by the component calling this service.
1586
+ }
1396
1587
  /**
1397
1588
  * Cleans orphaned components from the lesson's dynamicComponents.
1398
1589
  * An orphaned component is one present in dynamicComponents but its ID is not found in the textCoded HTML.
@@ -1455,7 +1646,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImpor
1455
1646
  args: [{
1456
1647
  providedIn: 'root', // Provide globally or in a specific module if preferred
1457
1648
  }]
1458
- }], ctorParameters: () => [] });
1649
+ }] });
1459
1650
 
1460
1651
  class DCLessonComponentAdderComponent {
1461
1652
  constructor() {
@@ -1531,7 +1722,7 @@ class DCLessonMetadataEditorComponent {
1531
1722
  this.generateAIRequest.emit();
1532
1723
  }
1533
1724
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DCLessonMetadataEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1534
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.4", type: DCLessonMetadataEditorComponent, isStandalone: true, selector: "dc-lesson-metadata-editor", inputs: { lesson: "lesson", isLoadingLesson: "isLoadingLesson" }, outputs: { saveRequest: "saveRequest", importNotionRequest: "importNotionRequest", improveNotionRequest: "improveNotionRequest", generateAIRequest: "generateAIRequest", propertyChange: "propertyChange" }, ngImport: i0, template: "@if (lesson(); as currentLesson) {\n<div>\n <div>\n <div style=\"display: flex; gap: 10px; padding: 10px\">\n <p-button label=\"Guardar\" severity=\"primary\" (click)=\"emitSaveRequest()\" />\n <p-button label=\"Importar de Notion\" severity=\"help\" (click)=\"emitImportNotionRequest()\" />\n <p-button label=\"Mejorar Notion con AI\" severity=\"help\" (click)=\"emitImproveNotionRequest()\" />\n </div>\n\n <!-- Use one-way binding and ngModelChange for signals -->\n <div>\n <input\n pInputText\n style=\"width: 100%\"\n [ngModel]=\"currentLesson.title\"\n (ngModelChange)=\"onPropertyChange('title', $event)\"\n type=\"text\"\n placeholder=\"Agrega un t\u00EDtulo\" />\n </div>\n <div style=\"margin-top: 4px\">\n <input\n pInputText\n style=\"width: 100%\"\n [ngModel]=\"currentLesson.description\"\n (ngModelChange)=\"onPropertyChange('description', $event)\"\n type=\"text\"\n placeholder=\"Agrega una descripci\u00F3n\" />\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.prompt\"\n (ngModelChange)=\"onPropertyChange('prompt', $event)\"\n type=\"text\"\n placeholder=\"Prompt para IA (opcional)\" />\n <p-button severity=\"primary\" [disabled]=\"isLoadingLesson()\" (click)=\"emitGenerateAIRequest()\"> Generar con IA </p-button>\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.isPublished\"\n (ngModelChange)=\"onPropertyChange('isPublished', $event)\"\n title=\"Cuando termines la edici\u00F3n marca esta casilla\" />\n <span class=\"checkmark\"></span>\n Publicada\n </label>\n\n <input\n pInputText\n [ngModel]=\"currentLesson.level\"\n (ngModelChange)=\"onPropertyChange('level', $event)\"\n type=\"number\"\n placeholder=\"Nivel\"\n style=\"width: 80px\" />\n </div>\n\n <!-- Access signal values -->\n <div style=\"margin-top: 10px; font-size: 0.9em; color: var(--text-color-secondary)\">\n {{ currentLesson.baseLang | flagEmoji }} -> {{ currentLesson.targetLang | flagEmoji }} Lecci\u00F3n para hablantes de\n {{ currentLesson.baseLang | langDesc : 'es' }} que aprenden\n {{ currentLesson.targetLang | langDesc : 'es' }}\n </div>\n </div>\n</div>\n} @else {\n<!-- Optional: Show a loading state or placeholder if lesson is undefined -->\n<p>Cargando datos de la lecci\u00F3n...</p>\n}\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i4.InputText, selector: "[pInputText]", inputs: ["variant", "fluid", "pSize"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "pipe", type: // Added TooltipModule
1725
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.4", type: DCLessonMetadataEditorComponent, isStandalone: true, selector: "dc-lesson-metadata-editor", inputs: { lesson: "lesson", isLoadingLesson: "isLoadingLesson" }, outputs: { saveRequest: "saveRequest", importNotionRequest: "importNotionRequest", improveNotionRequest: "improveNotionRequest", generateAIRequest: "generateAIRequest", propertyChange: "propertyChange" }, ngImport: i0, template: "@if (lesson(); as currentLesson) {\n<div>\n <div>\n <div style=\"display: flex; gap: 10px; padding: 10px\">\n <p-button label=\"Guardar\" severity=\"primary\" (click)=\"emitSaveRequest()\" />\n <p-button label=\"Importar de Notion\" severity=\"help\" (click)=\"emitImportNotionRequest()\" />\n <p-button label=\"Mejorar Notion con AI\" severity=\"help\" (click)=\"emitImproveNotionRequest()\" />\n </div>\n\n <!-- Use one-way binding and ngModelChange for signals -->\n <div>\n <input\n pInputText\n style=\"width: 100%\"\n [ngModel]=\"currentLesson.title\"\n (ngModelChange)=\"onPropertyChange('title', $event)\"\n type=\"text\"\n placeholder=\"Agrega un t\u00EDtulo\" />\n </div>\n <div style=\"margin-top: 4px\">\n <input\n pInputText\n style=\"width: 100%\"\n [ngModel]=\"currentLesson.description\"\n (ngModelChange)=\"onPropertyChange('description', $event)\"\n type=\"text\"\n placeholder=\"Agrega una descripci\u00F3n\" />\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.prompt\"\n (ngModelChange)=\"onPropertyChange('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)=\"emitGenerateAIRequest()\" />\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.isPublished\"\n (ngModelChange)=\"onPropertyChange('isPublished', $event)\"\n title=\"Cuando termines la edici\u00F3n marca esta casilla\" />\n <span class=\"checkmark\"></span>\n Publicada\n </label>\n\n <input\n pInputText\n [ngModel]=\"currentLesson.level\"\n (ngModelChange)=\"onPropertyChange('level', $event)\"\n type=\"number\"\n placeholder=\"Nivel\"\n style=\"width: 80px\" />\n </div>\n\n <!-- Access signal values -->\n <div style=\"margin-top: 10px; font-size: 0.9em; color: var(--text-color-secondary)\">\n {{ currentLesson.baseLang | flagEmoji }} -> {{ currentLesson.targetLang | flagEmoji }} Lecci\u00F3n para hablantes de\n {{ currentLesson.baseLang | langDesc : 'es' }} que aprenden\n {{ currentLesson.targetLang | langDesc : 'es' }}\n </div>\n </div>\n</div>\n} @else {\n<!-- Optional: Show a loading state or placeholder if lesson is undefined -->\n<p>Cargando datos de la lecci\u00F3n...</p>\n}\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i4.InputText, selector: "[pInputText]", inputs: ["variant", "fluid", "pSize"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "pipe", type: // Added TooltipModule
1535
1726
  FlagLanguagePipe, name: "flagEmoji" }, { kind: "pipe", type: // Added Pipe
1536
1727
  LangDescTranslationPipe, name: "langDesc" }] }); }
1537
1728
  }
@@ -1545,7 +1736,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImpor
1545
1736
  TooltipModule, // Added TooltipModule
1546
1737
  FlagLanguagePipe, // Added Pipe
1547
1738
  LangDescTranslationPipe, // Added Pipe
1548
- ], template: "@if (lesson(); as currentLesson) {\n<div>\n <div>\n <div style=\"display: flex; gap: 10px; padding: 10px\">\n <p-button label=\"Guardar\" severity=\"primary\" (click)=\"emitSaveRequest()\" />\n <p-button label=\"Importar de Notion\" severity=\"help\" (click)=\"emitImportNotionRequest()\" />\n <p-button label=\"Mejorar Notion con AI\" severity=\"help\" (click)=\"emitImproveNotionRequest()\" />\n </div>\n\n <!-- Use one-way binding and ngModelChange for signals -->\n <div>\n <input\n pInputText\n style=\"width: 100%\"\n [ngModel]=\"currentLesson.title\"\n (ngModelChange)=\"onPropertyChange('title', $event)\"\n type=\"text\"\n placeholder=\"Agrega un t\u00EDtulo\" />\n </div>\n <div style=\"margin-top: 4px\">\n <input\n pInputText\n style=\"width: 100%\"\n [ngModel]=\"currentLesson.description\"\n (ngModelChange)=\"onPropertyChange('description', $event)\"\n type=\"text\"\n placeholder=\"Agrega una descripci\u00F3n\" />\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.prompt\"\n (ngModelChange)=\"onPropertyChange('prompt', $event)\"\n type=\"text\"\n placeholder=\"Prompt para IA (opcional)\" />\n <p-button severity=\"primary\" [disabled]=\"isLoadingLesson()\" (click)=\"emitGenerateAIRequest()\"> Generar con IA </p-button>\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.isPublished\"\n (ngModelChange)=\"onPropertyChange('isPublished', $event)\"\n title=\"Cuando termines la edici\u00F3n marca esta casilla\" />\n <span class=\"checkmark\"></span>\n Publicada\n </label>\n\n <input\n pInputText\n [ngModel]=\"currentLesson.level\"\n (ngModelChange)=\"onPropertyChange('level', $event)\"\n type=\"number\"\n placeholder=\"Nivel\"\n style=\"width: 80px\" />\n </div>\n\n <!-- Access signal values -->\n <div style=\"margin-top: 10px; font-size: 0.9em; color: var(--text-color-secondary)\">\n {{ currentLesson.baseLang | flagEmoji }} -> {{ currentLesson.targetLang | flagEmoji }} Lecci\u00F3n para hablantes de\n {{ currentLesson.baseLang | langDesc : 'es' }} que aprenden\n {{ currentLesson.targetLang | langDesc : 'es' }}\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" }]
1739
+ ], template: "@if (lesson(); as currentLesson) {\n<div>\n <div>\n <div style=\"display: flex; gap: 10px; padding: 10px\">\n <p-button label=\"Guardar\" severity=\"primary\" (click)=\"emitSaveRequest()\" />\n <p-button label=\"Importar de Notion\" severity=\"help\" (click)=\"emitImportNotionRequest()\" />\n <p-button label=\"Mejorar Notion con AI\" severity=\"help\" (click)=\"emitImproveNotionRequest()\" />\n </div>\n\n <!-- Use one-way binding and ngModelChange for signals -->\n <div>\n <input\n pInputText\n style=\"width: 100%\"\n [ngModel]=\"currentLesson.title\"\n (ngModelChange)=\"onPropertyChange('title', $event)\"\n type=\"text\"\n placeholder=\"Agrega un t\u00EDtulo\" />\n </div>\n <div style=\"margin-top: 4px\">\n <input\n pInputText\n style=\"width: 100%\"\n [ngModel]=\"currentLesson.description\"\n (ngModelChange)=\"onPropertyChange('description', $event)\"\n type=\"text\"\n placeholder=\"Agrega una descripci\u00F3n\" />\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.prompt\"\n (ngModelChange)=\"onPropertyChange('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)=\"emitGenerateAIRequest()\" />\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.isPublished\"\n (ngModelChange)=\"onPropertyChange('isPublished', $event)\"\n title=\"Cuando termines la edici\u00F3n marca esta casilla\" />\n <span class=\"checkmark\"></span>\n Publicada\n </label>\n\n <input\n pInputText\n [ngModel]=\"currentLesson.level\"\n (ngModelChange)=\"onPropertyChange('level', $event)\"\n type=\"number\"\n placeholder=\"Nivel\"\n style=\"width: 80px\" />\n </div>\n\n <!-- Access signal values -->\n <div style=\"margin-top: 10px; font-size: 0.9em; color: var(--text-color-secondary)\">\n {{ currentLesson.baseLang | flagEmoji }} -> {{ currentLesson.targetLang | flagEmoji }} Lecci\u00F3n para hablantes de\n {{ currentLesson.baseLang | langDesc : 'es' }} que aprenden\n {{ currentLesson.targetLang | langDesc : 'es' }}\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" }]
1549
1740
  }], propDecorators: { lesson: [{
1550
1741
  type: Input,
1551
1742
  args: [{ required: true }]
@@ -1564,38 +1755,31 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImpor
1564
1755
  type: Output
1565
1756
  }] } });
1566
1757
 
1567
- const GradientCss = 'linear-gradient(to bottom,var(--primary-color), rgba(213, 238, 239, 0.31))';
1568
1758
  class DCLessonEditorComponent {
1569
1759
  // Services
1570
1760
  #activatedRoute; // Re-inject as it's needed for navigation
1571
1761
  #lessonNotionService;
1572
1762
  #lessonUtilsService;
1573
1763
  #router;
1574
- // Removed #dialogService injection
1575
1764
  #lessonService;
1576
1765
  #toastService;
1577
1766
  constructor() {
1578
- // Removed Speed Dial Items initialization
1579
1767
  // Services
1580
1768
  this.#activatedRoute = inject(ActivatedRoute); // Re-inject as it's needed for navigation
1581
1769
  this.#lessonNotionService = inject(LessonNotionService);
1582
1770
  this.#lessonUtilsService = inject(LessonUtilsService);
1583
1771
  this.#router = inject(Router);
1584
- // Removed #dialogService injection
1585
1772
  this.#lessonService = inject(LESSONS_TOKEN);
1586
1773
  this.#toastService = inject(TOAST_ALERTS_TOKEN);
1587
1774
  // Signals States
1588
1775
  this.lessonId = toSignal(inject(ActivatedRoute).paramMap.pipe(map((params) => params.get('id'))));
1589
1776
  this.lesson = signal(undefined); // Initialize as undefined
1590
- this.isCropperVisible = signal(false);
1591
1777
  this.isLoadingLesson = signal(false);
1592
- // Removed items signal
1593
1778
  // Computed Signals
1594
- this.coverBackground = computed(() => {
1779
+ this.coverImageUrl = computed(() => {
1595
1780
  const currentLesson = this.lesson();
1596
1781
  const coverImage = currentLesson?.media?.images?.find((img) => img.type === 'cover');
1597
- const imageUrl = coverImage?.url || '/assets/images/default_banner.webp';
1598
- return `${GradientCss}, url("${imageUrl}")`;
1782
+ return coverImage?.url || '/assets/images/default_banner.webp';
1599
1783
  });
1600
1784
  // Computed signal to get dynamic components as an array for easier iteration in the template
1601
1785
  this.dynamicComponentsArray = computed(() => {
@@ -1644,6 +1828,7 @@ class DCLessonEditorComponent {
1644
1828
  else {
1645
1829
  // Handle case for new lesson (ID is null/undefined)
1646
1830
  this.lesson.set({ textCoded: `<h1>Nueva lección </h1> <p> Texto aquí</p>`, tags: [] }); // Set default new lesson structure
1831
+ this.saveLesson();
1647
1832
  this.isLoadingLesson.set(false); // Ensure loading is off
1648
1833
  }
1649
1834
  });
@@ -1655,6 +1840,7 @@ class DCLessonEditorComponent {
1655
1840
  * @param value The new value for the property.
1656
1841
  */
1657
1842
  updateLessonProperty(property, value) {
1843
+ console.log('Updating property:', property, value);
1658
1844
  this.lesson.update((currentLesson) => {
1659
1845
  if (!currentLesson)
1660
1846
  return undefined;
@@ -1704,7 +1890,7 @@ class DCLessonEditorComponent {
1704
1890
  // It was a new lesson, now it has an ID. Navigate.
1705
1891
  this.#toastService.success({ title: 'Se creó la lección', subtitle: 'Éxito' });
1706
1892
  // The effect should automatically fetch the lesson again after navigation due to paramMap change.
1707
- this.#router.navigate(['../', savedLesson.id], { relativeTo: this.#activatedRoute });
1893
+ this.#router.navigate(['./', savedLesson.id], { relativeTo: this.#activatedRoute });
1708
1894
  }
1709
1895
  else {
1710
1896
  // It was an existing lesson, update the signal with the potentially updated data from the backend.
@@ -1731,7 +1917,6 @@ class DCLessonEditorComponent {
1731
1917
  * @param result The configuration data returned from the component builder dialog. Expected format: { obj: LessonComponentConfiguration }
1732
1918
  */
1733
1919
  onComponentAdded(result) {
1734
- debugger;
1735
1920
  // Check if result and result.obj.id exist
1736
1921
  const newComponent = result?.obj;
1737
1922
  if (newComponent?.id) {
@@ -1763,10 +1948,6 @@ class DCLessonEditorComponent {
1763
1948
  // this.saveLesson();
1764
1949
  }
1765
1950
  }
1766
- openCropper() {
1767
- // Correctly define openCropper
1768
- this.isCropperVisible.set(true);
1769
- }
1770
1951
  // isLoadingLesson signal is used directly
1771
1952
  async generateByAI() {
1772
1953
  const currentId = this.lessonId();
@@ -1782,10 +1963,23 @@ class DCLessonEditorComponent {
1782
1963
  // Handle save error - toast is shown in saveLesson
1783
1964
  throw new Error('Failed to save before AI generation');
1784
1965
  }
1785
- // Call the service method
1786
- const updatedLesson = await this.#lessonUtilsService.generateByAI(currentId);
1787
- if (updatedLesson) {
1788
- this.lesson.set(updatedLesson); // Update the signal with AI changes from service
1966
+ // // Removed debugger
1967
+ const rawHtmlContent = this.lesson()?.textCoded || '';
1968
+ if (!rawHtmlContent) {
1969
+ console.warn('No HTML content found in lesson to process.');
1970
+ this.isLoadingLesson.set(false);
1971
+ return; // Exit if no content
1972
+ }
1973
+ // Replace encoded JSON with actual text before Markdown conversion
1974
+ const processedHtmlContent = this._extractTextFromEncodedJson(rawHtmlContent);
1975
+ const turndownService = new TurndownService();
1976
+ // Convert the processed HTML (with text instead of JSON) to Markdown
1977
+ const markdownText = turndownService.turndown(processedHtmlContent);
1978
+ const improvedMarkdown = await this.#lessonUtilsService.improveMDWithAI(this.lesson(), markdownText);
1979
+ if (improvedMarkdown) {
1980
+ // Convert the improved Markdown back to HTML before setting it
1981
+ const improvedHtml = marked(improvedMarkdown);
1982
+ this.lesson.set({ ...this.lesson(), textCoded: improvedHtml }); // Update the signal with the converted HTML
1789
1983
  // Toast success is handled by the service
1790
1984
  }
1791
1985
  else {
@@ -1803,6 +1997,27 @@ class DCLessonEditorComponent {
1803
1997
  this.isLoadingLesson.set(false); // Stop loading
1804
1998
  }
1805
1999
  }
2000
+ /**
2001
+ * Replaces encoded JSON blocks (~...~) in HTML with their 'settings.text' value.
2002
+ * @param htmlInput The HTML string containing encoded JSON.
2003
+ * @returns The processed HTML string with text replacements.
2004
+ */
2005
+ _extractTextFromEncodedJson(htmlInput) {
2006
+ const jsonRegex = /~(.+?)~/g; // Global flag to replace all occurrences
2007
+ return htmlInput.replace(jsonRegex, (match, jsonCoded) => {
2008
+ try {
2009
+ // Attempt to decode HTML entities that might be present in the JSON string
2010
+ const decodedJson = jsonCoded.replace(/"/g, '"').replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
2011
+ const data = JSON.parse(decodedJson);
2012
+ // Return the text if available, otherwise keep the original match (or an error placeholder)
2013
+ return data?.settings?.text || match;
2014
+ }
2015
+ catch (error) {
2016
+ console.error('Failed to parse JSON inside HTML:', jsonCoded, error);
2017
+ return '<!-- invalid component data -->'; // Placeholder for parsing errors
2018
+ }
2019
+ });
2020
+ }
1806
2021
  /**
1807
2022
  * Handles the image upload event, updates the lesson signal via the service, and saves.
1808
2023
  * @param event The image upload event data.
@@ -1845,9 +2060,7 @@ class DCLessonEditorComponent {
1845
2060
  alert('showComponentDetails' + JSON.stringify(data));
1846
2061
  }
1847
2062
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DCLessonEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1848
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.4", type: DCLessonEditorComponent, isStandalone: true, selector: "dc-lesson-editor", providers: [LessonNotionService], viewQueries: [{ propertyName: "target", first: true, predicate: ["target"], descendants: true, read: ViewContainerRef }, { propertyName: "dhtml", first: true, predicate: ["dhtml"], descendants: true, static: true }], ngImport: i0, template: "<div style=\"position: relative; margin-bottom: 20px\">\n <div class=\"header-cover\" [style.background-image]=\"coverBackground()\"></div>\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</div>\n\n<br />\n\n<!-- Lesson Metadata Editor -->\n<dc-lesson-metadata-editor\n [lesson]=\"lesson\"\n [isLoadingLesson]=\"isLoadingLesson\"\n (saveRequest)=\"saveLesson()\"\n (importNotionRequest)=\"importFromNotion()\"\n (improveNotionRequest)=\"improveNotionWithAI()\"\n (generateAIRequest)=\"generateByAI()\"\n (propertyChange)=\"updateLessonProperty($event.property, $event.value)\">\n</dc-lesson-metadata-editor>\n\n<hr />\n\n<!-- Component Adder -->\n<dc-lesson-component-adder (componentAdded)=\"onComponentAdded($event)\"></dc-lesson-component-adder>\n\n<!-- Display Added Components -->\n<div class=\"added-components-list\" style=\"margin-top: 15px; margin-bottom: 15px\">\n <h4>Componentes Agregados:</h4>\n @if (dynamicComponentsArray().length > 0) {\n <ul>\n @for (comp of dynamicComponentsArray(); track comp.id) {\n <li>ID: {{ comp.id }} - Tipo: {{ comp.component }}<button pButton icon=\"pi pi-info\" (click)=\"showComponentDetails(comp)\"></button></li>\n }\n </ul>\n } @else {\n <p>A\u00FAn no se han agregado componentes.</p>\n }\n</div>\n\n<hr />\n\n<!-- Text Editor and Renderer -->\n<p-splitter [style]=\"{ height: '80vh' }\" styleClass=\"mb-8\">\n <ng-template pTemplate>\n <ckeditor\n (keydown.control.s)=\"saveLesson($event)\"\n class=\"text-editor\"\n [editor]=\"editor\"\n [ngModel]=\"lesson()?.textCoded\"\n (ngModelChange)=\"updateLessonProperty('textCoded', $event)\">\n </ckeditor>\n </ng-template>\n\n <ng-template pTemplate>\n <dc-lesson-renderer class=\"text-editor\" [lessonInput]=\"lesson()\" [test]=\"true\"></dc-lesson-renderer>\n </ng-template>\n</p-splitter>\n\n<div class=\"float-button\">\n <!-- Removed p-speeddial -->\n <p-button icon=\"pi pi-save\" (click)=\"saveLesson()\" severity=\"primary\" [rounded]=\"true\" [raised]=\"true\" pTooltip=\"Guardar (Ctrl + S)\"> </p-button>\n</div>\n\n<hr />\n", styles: [".btn{padding:.5rem 1rem;border-radius:4px;border:1px solid transparent;cursor:pointer}.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;background-position:center;background-repeat:no-repeat;background-size:cover;position:relative}.float-button{position:fixed;bottom:3.5rem;right:2rem;z-index:1000;display:flex;gap:1px}.float-button :host ::ng-deep .p-button{width:4rem;height:4rem;border-radius:50%}.text-editor{width:-webkit-fill-available;overflow-y:auto}:host ::ng-deep .p-inputtext{background:#fff3}\n"], dependencies: [{ kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i1$1.ButtonDirective, selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "fluid", "label", "icon", "buttonProps"] }, { kind: "component", type: i1$1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i2$6.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: CKEditorModule }, { kind: "component", type: i3$1.CKEditorComponent, selector: "ckeditor", inputs: ["editor", "config", "data", "tagName", "watchdog", "editorWatchdogConfig", "disableTwoWayDataBinding", "disabled"], outputs: ["ready", "change", "blur", "focus", "error"] }, { kind: "component", type: CropperComponentModal, selector: "dc-cropper-modal", inputs: ["imgStorageSettings", "buttonLabel", "currentStorage"], outputs: ["imageUploaded", "onImageCropped", "onFileSelected"] }, { kind: "component", type: DCLessonRendererComponent, selector: "dc-lesson-renderer", inputs: ["lessonInput", "lessonIdInput", "test"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "ngmodule", type: SplitterModule }, { kind: "component", type: i5$1.Splitter, selector: "p-splitter", inputs: ["styleClass", "panelStyleClass", "style", "panelStyle", "stateStorage", "stateKey", "layout", "gutterSize", "step", "minSizes", "panelSizes"], outputs: ["onResizeEnd", "onResizeStart"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i2$5.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }, { kind: "component", type:
1849
- // Removed SpeedDialModule
1850
- DCLessonComponentAdderComponent, selector: "dc-lesson-component-adder", outputs: ["componentAdded"] }, { kind: "component", type: // Add the component adder here
2063
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.4", type: DCLessonEditorComponent, isStandalone: true, selector: "dc-lesson-editor", providers: [LessonNotionService], viewQueries: [{ propertyName: "target", first: true, predicate: ["target"], descendants: true, read: ViewContainerRef }, { propertyName: "dhtml", first: true, predicate: ["dhtml"], descendants: true, static: true }], ngImport: i0, template: "<div style=\"position: relative; margin-bottom: 20px\">\n <img class=\"header-cover\" [src]=\"coverImageUrl()\" alt=\"Lesson Cover Image\" />\n\n <dc-cropper-modal\n style=\"position: absolute; top: 10px; left: 20px\"\n [buttonLabel]=\"'Carga una portada'\"\n [imgStorageSettings]=\"coverStorageSettings\"\n (imageUploaded)=\"onImageUploaded($event)\"></dc-cropper-modal>\n</div>\n\n<br />\n\n<!-- Lesson Metadata Editor -->\n<dc-lesson-metadata-editor\n [lesson]=\"lesson\"\n [isLoadingLesson]=\"isLoadingLesson\"\n (saveRequest)=\"saveLesson()\"\n (importNotionRequest)=\"importFromNotion()\"\n (improveNotionRequest)=\"improveNotionWithAI()\"\n (generateAIRequest)=\"generateByAI()\"\n (propertyChange)=\"updateLessonProperty($event.property, $event.value)\">\n</dc-lesson-metadata-editor>\n\n<hr />\n\n<!-- Component Adder -->\n<dc-lesson-component-adder (componentAdded)=\"onComponentAdded($event)\"></dc-lesson-component-adder>\n\n<!-- Display Added Components -->\n<div class=\"added-components-list\" style=\"margin-top: 15px; margin-bottom: 15px\">\n <h4>Componentes Agregados:</h4>\n @if (dynamicComponentsArray().length > 0) {\n <ul>\n @for (comp of dynamicComponentsArray(); track comp.id) {\n <li>ID: {{ comp.id }} - Tipo: {{ comp.component }}<button pButton icon=\"pi pi-info\" (click)=\"showComponentDetails(comp)\"></button></li>\n }\n </ul>\n } @else {\n <p>A\u00FAn no se han agregado componentes.</p>\n }\n</div>\n\n<hr />\n\n<!-- Text Editor and Renderer -->\n<p-splitter [style]=\"{ height: '80vh' }\">\n <ng-template pTemplate>\n <ckeditor\n (keydown.control.s)=\"saveLesson($event)\"\n class=\"text-editor\"\n [editor]=\"editor\"\n [ngModel]=\"lesson()?.textCoded\"\n (ngModelChange)=\"updateLessonProperty('textCoded', $event)\">\n </ckeditor>\n </ng-template>\n\n <ng-template pTemplate>\n <dc-lesson-renderer class=\"text-editor\" [lessonInput]=\"lesson()\" [test]=\"true\"></dc-lesson-renderer>\n </ng-template>\n</p-splitter>\n\n<div class=\"float-button\">\n <!-- Removed p-speeddial -->\n <p-button icon=\"pi pi-save\" (click)=\"saveLesson()\" severity=\"primary\" [rounded]=\"true\" [raised]=\"true\" pTooltip=\"Guardar (Ctrl + S)\"> </p-button>\n</div>\n\n<hr />\n", styles: [".btn{padding:.5rem 1rem;border-radius:4px;border:1px solid transparent;cursor:pointer}.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;background-position:center;background-repeat:no-repeat;background-size:cover;position:relative}.float-button{position:fixed;bottom:3.5rem;right:2rem;z-index:1000;display:flex;gap:1px}.float-button :host ::ng-deep .p-button{width:4rem;height:4rem;border-radius:50%}.text-editor{width:-webkit-fill-available;overflow-y:auto}:host ::ng-deep .p-inputtext{background:#fff3}\n"], dependencies: [{ kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i1$1.ButtonDirective, selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "fluid", "label", "icon", "buttonProps"] }, { kind: "component", type: i1$1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i2$6.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: CKEditorModule }, { kind: "component", type: i3$1.CKEditorComponent, selector: "ckeditor", inputs: ["editor", "config", "data", "tagName", "watchdog", "editorWatchdogConfig", "disableTwoWayDataBinding", "disabled"], outputs: ["ready", "change", "blur", "focus", "error"] }, { kind: "component", type: CropperComponentModal, selector: "dc-cropper-modal", inputs: ["imgStorageSettings", "buttonLabel", "currentStorage"], outputs: ["imageUploaded", "onImageCropped", "onFileSelected"] }, { kind: "component", type: DCLessonRendererComponent, selector: "dc-lesson-renderer", inputs: ["lessonInput", "lessonIdInput", "test"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "ngmodule", type: SplitterModule }, { kind: "component", type: i5$1.Splitter, selector: "p-splitter", inputs: ["styleClass", "panelStyleClass", "style", "panelStyle", "stateStorage", "stateKey", "layout", "gutterSize", "step", "minSizes", "panelSizes"], outputs: ["onResizeEnd", "onResizeStart"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i2$5.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }, { kind: "component", type: DCLessonComponentAdderComponent, selector: "dc-lesson-component-adder", outputs: ["componentAdded"] }, { kind: "component", type: // Add the component adder here
1851
2064
  DCLessonMetadataEditorComponent, selector: "dc-lesson-metadata-editor", inputs: ["lesson", "isLoadingLesson"], outputs: ["saveRequest", "importNotionRequest", "improveNotionRequest", "generateAIRequest", "propertyChange"] }] }); }
1852
2065
  }
1853
2066
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DCLessonEditorComponent, decorators: [{
@@ -1861,11 +2074,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImpor
1861
2074
  InputTextModule,
1862
2075
  SplitterModule,
1863
2076
  TooltipModule,
1864
- // Removed SpeedDialModule
1865
2077
  DCLessonComponentAdderComponent, // Add the component adder here
1866
2078
  DCLessonMetadataEditorComponent, // Add the metadata editor here
1867
- JsonPipe,
1868
- ], providers: [LessonNotionService], template: "<div style=\"position: relative; margin-bottom: 20px\">\n <div class=\"header-cover\" [style.background-image]=\"coverBackground()\"></div>\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</div>\n\n<br />\n\n<!-- Lesson Metadata Editor -->\n<dc-lesson-metadata-editor\n [lesson]=\"lesson\"\n [isLoadingLesson]=\"isLoadingLesson\"\n (saveRequest)=\"saveLesson()\"\n (importNotionRequest)=\"importFromNotion()\"\n (improveNotionRequest)=\"improveNotionWithAI()\"\n (generateAIRequest)=\"generateByAI()\"\n (propertyChange)=\"updateLessonProperty($event.property, $event.value)\">\n</dc-lesson-metadata-editor>\n\n<hr />\n\n<!-- Component Adder -->\n<dc-lesson-component-adder (componentAdded)=\"onComponentAdded($event)\"></dc-lesson-component-adder>\n\n<!-- Display Added Components -->\n<div class=\"added-components-list\" style=\"margin-top: 15px; margin-bottom: 15px\">\n <h4>Componentes Agregados:</h4>\n @if (dynamicComponentsArray().length > 0) {\n <ul>\n @for (comp of dynamicComponentsArray(); track comp.id) {\n <li>ID: {{ comp.id }} - Tipo: {{ comp.component }}<button pButton icon=\"pi pi-info\" (click)=\"showComponentDetails(comp)\"></button></li>\n }\n </ul>\n } @else {\n <p>A\u00FAn no se han agregado componentes.</p>\n }\n</div>\n\n<hr />\n\n<!-- Text Editor and Renderer -->\n<p-splitter [style]=\"{ height: '80vh' }\" styleClass=\"mb-8\">\n <ng-template pTemplate>\n <ckeditor\n (keydown.control.s)=\"saveLesson($event)\"\n class=\"text-editor\"\n [editor]=\"editor\"\n [ngModel]=\"lesson()?.textCoded\"\n (ngModelChange)=\"updateLessonProperty('textCoded', $event)\">\n </ckeditor>\n </ng-template>\n\n <ng-template pTemplate>\n <dc-lesson-renderer class=\"text-editor\" [lessonInput]=\"lesson()\" [test]=\"true\"></dc-lesson-renderer>\n </ng-template>\n</p-splitter>\n\n<div class=\"float-button\">\n <!-- Removed p-speeddial -->\n <p-button icon=\"pi pi-save\" (click)=\"saveLesson()\" severity=\"primary\" [rounded]=\"true\" [raised]=\"true\" pTooltip=\"Guardar (Ctrl + S)\"> </p-button>\n</div>\n\n<hr />\n", styles: [".btn{padding:.5rem 1rem;border-radius:4px;border:1px solid transparent;cursor:pointer}.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;background-position:center;background-repeat:no-repeat;background-size:cover;position:relative}.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"] }]
2079
+ ], 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</div>\n\n<br />\n\n<!-- Lesson Metadata Editor -->\n<dc-lesson-metadata-editor\n [lesson]=\"lesson\"\n [isLoadingLesson]=\"isLoadingLesson\"\n (saveRequest)=\"saveLesson()\"\n (importNotionRequest)=\"importFromNotion()\"\n (improveNotionRequest)=\"improveNotionWithAI()\"\n (generateAIRequest)=\"generateByAI()\"\n (propertyChange)=\"updateLessonProperty($event.property, $event.value)\">\n</dc-lesson-metadata-editor>\n\n<hr />\n\n<!-- Component Adder -->\n<dc-lesson-component-adder (componentAdded)=\"onComponentAdded($event)\"></dc-lesson-component-adder>\n\n<!-- Display Added Components -->\n<div class=\"added-components-list\" style=\"margin-top: 15px; margin-bottom: 15px\">\n <h4>Componentes Agregados:</h4>\n @if (dynamicComponentsArray().length > 0) {\n <ul>\n @for (comp of dynamicComponentsArray(); track comp.id) {\n <li>ID: {{ comp.id }} - Tipo: {{ comp.component }}<button pButton icon=\"pi pi-info\" (click)=\"showComponentDetails(comp)\"></button></li>\n }\n </ul>\n } @else {\n <p>A\u00FAn no se han agregado componentes.</p>\n }\n</div>\n\n<hr />\n\n<!-- Text Editor and Renderer -->\n<p-splitter [style]=\"{ height: '80vh' }\">\n <ng-template pTemplate>\n <ckeditor\n (keydown.control.s)=\"saveLesson($event)\"\n class=\"text-editor\"\n [editor]=\"editor\"\n [ngModel]=\"lesson()?.textCoded\"\n (ngModelChange)=\"updateLessonProperty('textCoded', $event)\">\n </ckeditor>\n </ng-template>\n\n <ng-template pTemplate>\n <dc-lesson-renderer class=\"text-editor\" [lessonInput]=\"lesson()\" [test]=\"true\"></dc-lesson-renderer>\n </ng-template>\n</p-splitter>\n\n<div class=\"float-button\">\n <!-- Removed p-speeddial -->\n <p-button icon=\"pi pi-save\" (click)=\"saveLesson()\" severity=\"primary\" [rounded]=\"true\" [raised]=\"true\" pTooltip=\"Guardar (Ctrl + S)\"> </p-button>\n</div>\n\n<hr />\n", styles: [".btn{padding:.5rem 1rem;border-radius:4px;border:1px solid transparent;cursor:pointer}.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;background-position:center;background-repeat:no-repeat;background-size:cover;position:relative}.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"] }]
1869
2080
  }], ctorParameters: () => [], propDecorators: { target: [{
1870
2081
  type: ViewChild,
1871
2082
  args: ['target', { read: ViewContainerRef }]
@@ -1901,5 +2112,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImpor
1901
2112
  * Generated bundle index. Do not edit.
1902
2113
  */
1903
2114
 
1904
- export { ComponentBuilder, ComponentWithForm, DCLessonEditorComponent, DCLessonFormComponent, DCLessonListComponent, DCLessonRendererComponent, DcLessonCardComponent, FlagLanguagePipe, LESSONS_TOKEN, LangCodeDescription, LangCodeDescriptionEs, LangDescTranslationPipe, LessonComponentBuilders, LessonComponentEnum, LessonComponents, LessonDynamicComponent, LessonsAbstractService, NOTION_SERVICE_TOKEN, NotionAbstractService, NotionExportType, SelectorBuilderComponent, SelectorComponent, TextWriterBuiderComponent, TextWriterComponent, TranslationSwitcherBuilderComponent, TranslationSwitcherComponent, getLessonComponentClass, provideLessonsService, provideNotionService };
2115
+ export { BasicAgentCard$1 as BasicAgentCard, ComponentBuilder, ComponentWithForm, DCLessonEditorComponent, DCLessonFormComponent, DCLessonListComponent, DCLessonRendererComponent, DcLessonCardComponent, FlagLanguagePipe, LESSONS_TOKEN, LangCodeDescription, LangCodeDescriptionEs, LangDescTranslationPipe, LessonComponentBuilders, LessonComponentEnum, LessonComponents, LessonDynamicComponent, LessonsAbstractService, NOTION_SERVICE_TOKEN, NotionAbstractService, NotionExportType, SelectorBuilderComponent, SelectorComponent, TextWriterBuiderComponent, TextWriterComponent, TranslationSwitcherBuilderComponent, TranslationSwitcherComponent, getLessonComponentClass, provideLessonsService, provideNotionService };
1905
2116
  //# sourceMappingURL=dataclouder-ngx-lessons.mjs.map