From 35f7fa8a9b38c88dccb841fbf023aabfd668e249 Mon Sep 17 00:00:00 2001 From: alizarazot Date: Sun, 26 May 2024 20:18:15 -0500 Subject: [PATCH 1/4] Example shape of new lesson format --- public/lesson/diagnostic-test/index.json | 76 ++++++++++-------------- 1 file changed, 33 insertions(+), 43 deletions(-) diff --git a/public/lesson/diagnostic-test/index.json b/public/lesson/diagnostic-test/index.json index 6885ac9..a386d54 100644 --- a/public/lesson/diagnostic-test/index.json +++ b/public/lesson/diagnostic-test/index.json @@ -2,54 +2,44 @@ "title": "Prueba de conocimientos", "description": "¡Pon a prueba tus conocimientos de Lengua de Señas Colombiana!", "summary": "Esta prueba nos permitirá conocer su nivel de conocimiento actual de la Lengua de Señas Colombiana.", - "content": [ - { - "type": "title", - "content": "Prueba diagnóstica de Lengua de Señas Colombiana (LSC)" - }, - { - "type": "image", - "content": "s/hola.png" - }, - { - "type": "paragraph", - "content": "La prueba diagnóstica de Lengua de Señas Colombiana (LSC) se utiliza para evaluar el nivel de competencia y fluidez en la Lengua de Señas Colombiana. Esta prueba es crucial para determinar el grado de habilidad y comprensión en la comunicación a través de la LSC." - } - ], - "questions": [ - { + "questions": { + "q-1": { + "lesson": [ + { + "type": "title", + "content": "Prueba diagnóstica de Lengua de Señas Colombiana (LSC)" + }, + { + "type": "image", + "content": "s/hola.png" + }, + { + "type": "paragraph", + "content": "La prueba diagnóstica de Lengua de Señas Colombiana (LSC) se utiliza para evaluar el nivel de competencia y fluidez en la Lengua de Señas Colombiana. Esta prueba es crucial para determinar el grado de habilidad y comprensión en la comunicación a través de la LSC." + } + ], "question": "¿Qué parte del cuerpo se utiliza principalmente para expresar emociones en Lengua de Señas Colombiana?", - "type": "single-choice", "answers": ["Manos", "Pies", "Brazos", "Rostro"], "correct": 3 }, - { - "question": "¿Qué significa cuando se agita la mano de un lado a otro en Lengua de Señas Colombiana?", - "type": "single-choice", - "answers": ["Saludo", "Aprobación", "Negación", "Agradecimiento"], - "correct": 2 - }, - { - "question": "¿Cuál es la importancia de las expresiones faciales en la Lengua de Señas Colombiana?", - "type": "single-choice", - "answers": [ - "No tienen importancia", - "Solo se utilizan para enfatizar", - "Son fundamentales para transmitir significado", - "Son opcionales" - ], - "correct": 2 - }, - { - "question": "¿Cómo se expresan los números del 1 al 5 en Lengua de Señas Colombiana?", - "type": "single-choice", - "answers": [ - "Con movimientos de los labios", - "Con gestos faciales", - "Con una sola mano", - "Con los dedos de ambas manos" + "q-2": { + "lesson": [ + { + "type": "title", + "content": "Prueba diagnóstica de Lengua de Señas Colombiana (LSC)" + }, + { + "type": "image", + "content": "s/hola.png" + }, + { + "type": "paragraph", + "content": "La prueba diagnóstica de Lengua de Señas Colombiana (LSC) se utiliza para evaluar el nivel de competencia y fluidez en la Lengua de Señas Colombiana. Esta prueba es crucial para determinar el grado de habilidad y comprensión en la comunicación a través de la LSC." + } ], + "question": "¿Qué parte del cuerpo se utiliza principalmente para expresar emociones en Lengua de Señas Colombiana?", + "answers": ["Manos", "Pies", "Brazos", "Rostro"], "correct": 3 } - ] + } } From 1f67205836ef971d09e06a69c9a8cbadc82e1d5c Mon Sep 17 00:00:00 2001 From: alizarazot Date: Sun, 26 May 2024 21:50:11 -0500 Subject: [PATCH 2/4] Restructure code --- public/lesson/index.json | 15 --- src/component/single-choice-question.ts | 6 +- src/lesson/index.ts | 156 ++++++++++++------------ src/main.ts | 4 +- src/view/home.ts | 50 +++++--- src/view/lesson.ts | 18 +-- src/view/stats.ts | 8 +- 7 files changed, 129 insertions(+), 128 deletions(-) diff --git a/public/lesson/index.json b/public/lesson/index.json index 2c8eb24..588130b 100644 --- a/public/lesson/index.json +++ b/public/lesson/index.json @@ -3,20 +3,5 @@ "id": "diagnostic-test", "name": "Prueba diagnóstica", "require": [] - }, - { - "id": "lesson-1", - "name": "Lección 1", - "require": ["diagnostic-test"] - }, - { - "id": "lesson-2", - "name": "Lección 2", - "require": ["lesson-1"] - }, - { - "id": "lesson-3", - "name": "Lección 3", - "require": ["lesson-2"] } ] diff --git a/src/component/single-choice-question.ts b/src/component/single-choice-question.ts index b1739d7..1b3c7b4 100644 --- a/src/component/single-choice-question.ts +++ b/src/component/single-choice-question.ts @@ -7,7 +7,7 @@ import { defineComponents, } from "igniteui-webcomponents"; -import { SingleChoiceQuestion } from "lesson"; +import { Question } from "lesson"; @customElement("component-single-choice-question") export class ComponentSingleChoiceQuestion extends LitElement { @@ -26,7 +26,7 @@ export class ComponentSingleChoiceQuestion extends LitElement { } `; - constructor(question: SingleChoiceQuestion) { + constructor(question: Question) { super(); this.question = question; @@ -39,7 +39,7 @@ export class ComponentSingleChoiceQuestion extends LitElement { } @property({ attribute: false }) - question: SingleChoiceQuestion; + question: Question; @state() private _lastRadio = -1; diff --git a/src/lesson/index.ts b/src/lesson/index.ts index 89e4c0a..aa1b1eb 100644 --- a/src/lesson/index.ts +++ b/src/lesson/index.ts @@ -1,96 +1,46 @@ -export class Lesson { - static readonly rootDirectory = location.origin + "/lesson"; - static readonly rootIndex = Lesson.rootDirectory + "/index.json"; +const rootDirectory = location.origin + "/lesson"; +const rootIndex = rootDirectory + "/index.json"; +export class LessonMetadata { constructor( - public readonly id: string, + private readonly _id: string, public readonly name: string, - public readonly title: string, - public readonly require: Lesson[], - public readonly description: string, - public readonly summary: string, - public readonly content: LessonContent[], - public readonly questions: SingleChoiceQuestion[], + public readonly require: LessonMetadata[], ) {} - static async avaible(): Promise<{ [id: string]: Lesson }> { - const lessonIndex = await (await fetch(Lesson.rootIndex)).json(); - - let lessons: { [id: string]: Lesson } = {}; - - for (let rawLesson of lessonIndex) { - let require = Lesson.parseRequeriments(rawLesson.require, lessons); - - let rawLessonDetails: any; - try { - rawLessonDetails = await Lesson.rawLessonDetails(rawLesson.id); - } catch (e) { - console.error("Invalid or unexistent lesson content:", rawLesson.id); - continue; - } - - lessons[rawLesson.id] = new Lesson( - rawLesson.id, - rawLesson.name, - rawLessonDetails.title, - require, - rawLessonDetails.description, - rawLessonDetails.summary, - Lesson.parseContent(rawLessonDetails.content), - Lesson.parseQuestions(rawLessonDetails.questions), - ); - } + async load(): Promise { + const rawLesson = await LessonMetadata.rawLessonDetails(this._id); - return lessons; + return new LessonData( + rawLesson.title, + rawLesson.description, + rawLesson.summary, + LessonMetadata.parseQuestions(rawLesson.questions), + ); } protected static async rawLessonDetails(id: string): Promise { - return await ( - await fetch(Lesson.rootDirectory + "/" + id + "/index.json") - ).json(); - } - - protected static parseRequeriments( - require: string[], - lessons: { [id: string]: Lesson }, - ): Lesson[] { - let requeriments: Lesson[] = []; - - for (let req of require) { - for (let id in lessons) { - if (req === id) { - requeriments.push(lessons[id]); - } - } - } - - return requeriments; + return await (await fetch(rootDirectory + "/" + id + "/index.json")).json(); } - protected static parseQuestions(questions: any): SingleChoiceQuestion[] { - let parsedQuestions: SingleChoiceQuestion[] = []; - - for (let question of questions) { - if (question.type !== "single-choice") { - console.error("Unkonown question type:", question.type); - continue; - } + protected static parseQuestions(questions: any): Question[] { + let parsedQuestions: Question[] = []; - parsedQuestions.push(SingleChoiceQuestion.parse(question)); + for (let question in questions) { + parsedQuestions.push(Question.parse(questions[question])); } return parsedQuestions; } +} - protected static parseContent(content: any): LessonContent[] { - let parsedContent: LessonContent[] = []; - - for (let c of content) { - parsedContent.push(LessonContent.parse(c)); - } - - return parsedContent; - } +export class LessonData { + constructor( + public readonly title: string, + public readonly description: string, + public readonly summary: string, + public readonly questions: Question[], + ) {} } export class LessonContent { @@ -103,16 +53,27 @@ export class LessonContent { if (content.type === "image") { return new LessonContent( content.type, - Lesson.rootDirectory + "/image/" + content.content, + rootDirectory + "/image/" + content.content, ); } return new LessonContent(content.type, content.content); } + + static parseList(content: any): LessonContent[] { + let parsedContent: LessonContent[] = []; + + for (let c of content) { + parsedContent.push(LessonContent.parse(c)); + } + + return parsedContent; + } } -export class SingleChoiceQuestion { +export class Question { constructor( + public readonly lesson: LessonContent[], public readonly question: string, public readonly answers: string[], private readonly _indexCorrect: number, @@ -122,11 +83,46 @@ export class SingleChoiceQuestion { return this.answers[this._indexCorrect]; } - static parse(question: any): SingleChoiceQuestion { - return new SingleChoiceQuestion( + static parse(question: any): Question { + return new Question( + LessonContent.parseList(question.lesson), question.question, question.answers, question.correct, ); } } + +export async function avaibleLessons(): Promise> { + const lessonIndex = await (await fetch(rootIndex)).json(); + + let lessons = new Map(); + + for (let rawLesson of lessonIndex) { + let require = parseLessonRequeriments(rawLesson.require, lessons); + + lessons.set( + rawLesson.id, + new LessonMetadata(rawLesson.id, rawLesson.name, require), + ); + } + + return lessons; +} + +function parseLessonRequeriments( + require: string[], + lessons: Map, +): LessonMetadata[] { + let requeriments: LessonMetadata[] = []; + + for (let req of require) { + for (let [id, lesson] of lessons) { + if (req === id) { + requeriments.push(lesson); + } + } + } + + return requeriments; +} diff --git a/src/main.ts b/src/main.ts index 230ad9d..38a82bf 100644 --- a/src/main.ts +++ b/src/main.ts @@ -8,7 +8,7 @@ import { registerServiceWorker } from "service-worker"; import "igniteui-webcomponents/themes/light/fluent.css"; -import { Lesson } from "lesson"; +import { avaibleLessons } from "lesson"; import { currentSession } from "session"; import "view/home"; @@ -38,7 +38,7 @@ export class MainComponent extends LitElement { render: (params) => html``, enter: async (params) => { - if ((await Lesson.avaible())[params["id"]!] != null) { + if ((await avaibleLessons()).get(params["id"]!) != null) { return true; } diff --git a/src/view/home.ts b/src/view/home.ts index feadedf..c0cab94 100644 --- a/src/view/home.ts +++ b/src/view/home.ts @@ -8,7 +8,7 @@ import { IgcDialogComponent, } from "igniteui-webcomponents"; -import { Lesson } from "lesson"; +import { LessonData, LessonMetadata, avaibleLessons } from "lesson"; import { currentSession } from "session"; import type { PartialNavDrawer } from "./partial/nav-drawer"; @@ -49,15 +49,27 @@ export class ViewHome extends LitElement { defineComponents(IgcDialogComponent, IgcCardComponent, IgcButtonComponent); - Lesson.avaible().then((lessons) => { - this.lessons = lessons; + avaibleLessons().then((lessons) => { + this._lessonsMetadata = lessons; + + for (let [id] of this._lessonsMetadata) { + this._lessonsMetadata + .get(id)! + .load() + .then((lesson) => { + this._lessonsData.set(id, lesson); + this.requestUpdate(); + }); + } }); this.loadTotalScore(); } @state() - lessons: { [id: string]: Lesson } = {}; + private _lessonsMetadata = new Map(); + @state() + private _lessonsData = new Map(); @state() private _session = currentSession(); @@ -69,10 +81,14 @@ export class ViewHome extends LitElement { private _navDrawer!: PartialNavDrawer; override render() { - const lessons: Lesson[] = []; - for (let id in this.lessons) { + if (this._lessonsData.size === 0) { + return html`Loading...`; + } + + const lessonsId: string[] = []; + for (let [id] of this._lessonsMetadata) { if (this._session.getPoints(id) <= 75) { - lessons.push(this.lessons[id]); + lessonsId.push(id); } } @@ -90,28 +106,28 @@ export class ViewHome extends LitElement {

Puntos totales: ${this.totalScore}

- ${lessons.map( - (i) => html` + ${lessonsId.map( + (id) => html` -

${i.name}

-

${i.title}

+

${this._lessonsMetadata.get(id)!.name}

+

${this._lessonsData.get(id)!.title}

-

${i.description}

+

${this._lessonsData.get(id)!.description}

{ - this._startLesson(i); + this._startLesson(id); }} >Comenzar { - this._showLessonDescription(i); + this._showLessonDescription(this._lessonsData.get(id)!); }} >Previsualizar @@ -130,16 +146,16 @@ export class ViewHome extends LitElement { @query("igc-dialog", true) private _dialog!: IgcDialogComponent; - private _showLessonDescription(lesson: Lesson) { + private _showLessonDescription(lesson: LessonData) { this._dialog.innerHTML = `

${lesson.summary}

`; this._dialog.show(); } - private _startLesson(lesson: Lesson) { + private _startLesson(id: string) { this.dispatchEvent( new CustomEvent("goto-url", { composed: true, - detail: `/lesson/${lesson.id}`, + detail: `/lesson/${id}`, }), ); } diff --git a/src/view/lesson.ts b/src/view/lesson.ts index a19cb20..c1a21c3 100644 --- a/src/view/lesson.ts +++ b/src/view/lesson.ts @@ -16,7 +16,7 @@ import { import { ComponentSingleChoiceQuestion } from "component/single-choice-question"; -import { Lesson } from "lesson"; +import { LessonData, avaibleLessons } from "lesson"; import { currentSession } from "session"; import type { PartialNavDrawer } from "view/partial/nav-drawer"; @@ -71,9 +71,13 @@ export class ViewLesson extends LitElement { super.connectedCallback(); if (this._lesson == null) { - Lesson.avaible().then((lessons) => { - this._lesson = lessons[this.lessonId]; - }); + avaibleLessons() + .then((lessons) => { + return lessons.get(this.lessonId)!.load(); + }) + .then((lesson) => { + this._lesson = lesson; + }); } defineComponents(IgcButtonComponent, IgcStepperComponent); @@ -83,7 +87,7 @@ export class ViewLesson extends LitElement { lessonId: string = ""; @state() - private _lesson?: Lesson; + private _lesson?: LessonData; @state() private _score = 0; @@ -114,7 +118,7 @@ export class ViewLesson extends LitElement { Descripción
- ${this._lesson.content.map((i) => { + ${this._lesson.questions[0].lesson.map((i) => { switch (i.type) { case "title": return html`

${i.content}

`; @@ -162,7 +166,7 @@ export class ViewLesson extends LitElement { private _handleLessonEnd() { if (this._lesson != null) { - currentSession().setPoints(this._lesson.id, this._score); + currentSession().setPoints(this.lessonId, this._score); } this.dispatchEvent( diff --git a/src/view/stats.ts b/src/view/stats.ts index 3fa7200..9e640e5 100644 --- a/src/view/stats.ts +++ b/src/view/stats.ts @@ -3,7 +3,7 @@ import { customElement, query, state } from "lit/decorators.js"; import { IgcListComponent, defineComponents } from "igniteui-webcomponents"; -import { Lesson } from "lesson"; +import { LessonMetadata, avaibleLessons } from "lesson"; import { currentSession } from "session"; import type { PartialNavDrawer } from "./partial/nav-drawer"; @@ -22,7 +22,7 @@ export class ViewStats extends LitElement { override connectedCallback(): void { super.connectedCallback(); - Lesson.avaible().then((lessons) => { + avaibleLessons().then((lessons) => { this._lessons = lessons; }); @@ -30,7 +30,7 @@ export class ViewStats extends LitElement { } @state() - private _lessons: { [id: string]: Lesson } = {}; + private _lessons = new Map(); @state() private _session = currentSession(); @@ -59,7 +59,7 @@ export class ViewStats extends LitElement { ${idsWithPoints.map( (id) => html` ${this._lessons[id].name}: ${this._session.getPoints(id)} + >${this._lessons.get(id)!.name}: ${this._session.getPoints(id)} puntos. `, From 7be65cae1f1990aa0bc3bb6e207d95b921d04de3 Mon Sep 17 00:00:00 2001 From: alizarazot Date: Mon, 27 May 2024 14:27:05 -0500 Subject: [PATCH 3/4] Simplify the lessons format (JSON) --- public/lesson/index.json | 10 +-- .../index.json => lesson-1.json} | 3 +- public/lesson/lesson-1/index.json | 69 ---------------- public/lesson/lesson-2/index.json | 80 ------------------- public/lesson/lesson-3/index.json | 7 -- src/lesson/index.ts | 1 - 6 files changed, 4 insertions(+), 166 deletions(-) rename public/lesson/{diagnostic-test/index.json => lesson-1.json} (91%) delete mode 100644 public/lesson/lesson-1/index.json delete mode 100644 public/lesson/lesson-2/index.json delete mode 100644 public/lesson/lesson-3/index.json diff --git a/public/lesson/index.json b/public/lesson/index.json index 588130b..c4318ae 100644 --- a/public/lesson/index.json +++ b/public/lesson/index.json @@ -1,7 +1,3 @@ -[ - { - "id": "diagnostic-test", - "name": "Prueba diagnóstica", - "require": [] - } -] +{ + "lesson-1": [] +} diff --git a/public/lesson/diagnostic-test/index.json b/public/lesson/lesson-1.json similarity index 91% rename from public/lesson/diagnostic-test/index.json rename to public/lesson/lesson-1.json index a386d54..50cdeaa 100644 --- a/public/lesson/diagnostic-test/index.json +++ b/public/lesson/lesson-1.json @@ -1,7 +1,6 @@ { - "title": "Prueba de conocimientos", + "name": "Prueba diagnóstica", "description": "¡Pon a prueba tus conocimientos de Lengua de Señas Colombiana!", - "summary": "Esta prueba nos permitirá conocer su nivel de conocimiento actual de la Lengua de Señas Colombiana.", "questions": { "q-1": { "lesson": [ diff --git a/public/lesson/lesson-1/index.json b/public/lesson/lesson-1/index.json deleted file mode 100644 index 50274ea..0000000 --- a/public/lesson/lesson-1/index.json +++ /dev/null @@ -1,69 +0,0 @@ -{ - "title": "Conceptos básicos de LSC", - "description": "Aprende los conceptos básicos de Lengua de Señas Colombiana.", - "summary": "La LSC es una herramienta vital para la comunicación, la identidad y la participación de las personas sordas y con dificultades auditivas en Colombia. Su aprendizaje abre un mundo de posibilidades para la interacción y el desarrollo personal.", - "content": [ - { - "type": "title", - "content": "Conceptos básicos de Lengua de Señas Colombiana (LSC)" - }, - { - "type": "paragraph", - "content": "La Lengua de Señas Colombiana (LSC) es un sistema de comunicación utilizado por personas sordas en Colombia. A diferencia del lenguaje hablado, la LSC se basa en gestos y movimientos de manos." - }, - { - "type": "paragraph", - "content": "Los signos en LSC representan palabras, conceptos o ideas, y pueden incluir movimientos de manos, expresiones faciales y posturas corporales." - }, - { - "type": "paragraph", - "content": "La gramática de la LSC incluye aspectos como la configuración de las manos, el movimiento, la ubicación y la expresión facial, que son cruciales para la comprensión adecuada del mensaje." - } - ], - "questions": [ - { - "question": "¿Cuál es el signo de Lengua de Señas Colombiana para 'casa'?", - "type": "single-choice", - "answers": [ - "Punta del dedo índice tocando la barbilla", - "Movimiento circular con la mano sobre el pecho", - "Puño con el pulgar hacia arriba golpeando el pecho", - "Mano extendida moviéndose hacia arriba" - ], - "correct": 2 - }, - { - "question": "¿Cómo se hace el signo para 'familia' en Lengua de Señas Colombiana?", - "type": "single-choice", - "answers": [ - "Punta del dedo índice tocando la barbilla", - "Manos unidas y levantadas", - "Puño con el pulgar hacia arriba golpeando el pecho", - "Mano extendida moviéndose hacia arriba" - ], - "correct": 1 - }, - { - "question": "¿Cuál es el signo para 'amor' en Lengua de Señas Colombiana?", - "type": "single-choice", - "answers": [ - "Manos unidas formando un corazón", - "Puño con el pulgar hacia arriba golpeando el pecho", - "Movimiento circular con la mano sobre el pecho", - "Mano extendida moviéndose hacia arriba" - ], - "correct": 0 - }, - { - "question": "¿Cómo se dice 'gracias' en Lengua de Señas Colombiana?", - "type": "single-choice", - "answers": [ - "Movimiento circular con la mano sobre el pecho", - "Mano extendida moviéndose hacia arriba", - "Puño con el pulgar hacia arriba golpeando el pecho", - "Manos unidas y levantadas" - ], - "correct": 3 - } - ] -} diff --git a/public/lesson/lesson-2/index.json b/public/lesson/lesson-2/index.json deleted file mode 100644 index 6964bff..0000000 --- a/public/lesson/lesson-2/index.json +++ /dev/null @@ -1,80 +0,0 @@ -{ - "title": "Alfabeto", - "description": "Aprende el alfabeto de la Lengua de Señas Colombiana.", - "summary": "El alfabeto de la LSC es un sistema manual que representa las letras del español. Cada letra se forma con una configuración específica de la mano, la orientación y el movimiento.", - "content": [ - { - "type": "title", - "content": "Conceptos básicos del alfabeto en Lengua de Señas Colombiana (LSC)" - }, - { - "type": "paragraph", - "content": "El alfabeto en Lengua de Señas Colombiana (LSC) es un conjunto de signos que representan las letras del abecedario utilizado por personas sordas para deletrear palabras y expresar ideas." - }, - { - "type": "paragraph", - "content": "Cada letra del alfabeto en LSC se representa con un gesto específico de la mano, que puede incluir movimientos y posiciones particulares." - }, - { - "type": "paragraph", - "content": "Dominar el alfabeto en LSC es fundamental para la comunicación efectiva, ya que proporciona la base para la formación de palabras y frases en este sistema de comunicación." - } - ], - "questions": [ - { - "question": "¿Cuál es la letra 'A' en Lengua de Señas Colombiana?", - "type": "single-choice", - "answers": [ - "Mano con el pulgar, índice y medio extendidos y los otros dedos cerrados", - "Punta del dedo índice tocando la barbilla", - "Mano extendida moviéndose hacia arriba", - "Puño con el pulgar hacia arriba golpeando el pecho" - ], - "correct": 0 - }, - { - "question": "¿Cómo se hace la letra 'B' en Lengua de Señas Colombiana?", - "type": "single-choice", - "answers": [ - "Mano con el pulgar, índice y medio extendidos y los otros dedos cerrados", - "Manos unidas y levantadas", - "Puño con el pulgar hacia arriba golpeando el pecho", - "Movimiento circular con la mano sobre el pecho" - ], - "correct": 1 - }, - { - "question": "¿Cuál es la forma de la letra 'C' en Lengua de Señas Colombiana?", - "type": "single-choice", - "answers": [ - "Puño con el pulgar hacia arriba golpeando el pecho", - "Manos unidas y levantadas", - "Mano extendida moviéndose hacia arriba", - "Mano con el pulgar, índice y medio extendidos y los otros dedos cerrados" - ], - "correct": 3 - }, - { - "question": "¿Qué signo representa la letra 'D' en Lengua de Señas Colombiana?", - "type": "single-choice", - "answers": [ - "Manos unidas y levantadas", - "Puño con el pulgar hacia arriba golpeando el pecho", - "Mano extendida moviéndose hacia arriba", - "Mano con el pulgar, índice y medio extendidos y los otros dedos cerrados" - ], - "correct": 2 - }, - { - "question": "¿Cómo se hace la letra 'E' en Lengua de Señas Colombiana?", - "type": "single-choice", - "answers": [ - "Puño con el pulgar hacia arriba golpeando el pecho", - "Mano extendida moviéndose hacia arriba", - "Punta del dedo índice tocando la barbilla", - "Mano con el pulgar, índice y medio extendidos y los otros dedos cerrados" - ], - "correct": 2 - } - ] -} diff --git a/public/lesson/lesson-3/index.json b/public/lesson/lesson-3/index.json deleted file mode 100644 index 3e72132..0000000 --- a/public/lesson/lesson-3/index.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "title": "Gramática", - "description": "Aprende la gramática de la Lengua de Señas Colombiana.", - "summary": "La gramática de la LSC es un sistema de reglas que organiza la forma en que se construyen las oraciones y se expresa el significado en este lenguaje. Al igual que las lenguas habladas, la LSC tiene su propia sintaxis, morfología y pragmática.", - "content": [], - "questions": [] -} diff --git a/src/lesson/index.ts b/src/lesson/index.ts index aa1b1eb..d818149 100644 --- a/src/lesson/index.ts +++ b/src/lesson/index.ts @@ -38,7 +38,6 @@ export class LessonData { constructor( public readonly title: string, public readonly description: string, - public readonly summary: string, public readonly questions: Question[], ) {} } From 7af86d2a5cd23d3e61712b28ce2ddbba1413e8c6 Mon Sep 17 00:00:00 2001 From: alizarazot Date: Mon, 27 May 2024 15:50:43 -0500 Subject: [PATCH 4/4] Use new lesson library --- public/lesson/index.json | 4 +- public/lesson/lesson-1.json | 4 +- src/component/single-choice-question.ts | 8 +- src/lesson/index.ts | 124 +++++++----------------- src/main.ts | 6 +- src/view/home.ts | 100 ++++++++----------- src/view/lesson.ts | 21 ++-- src/view/stats.ts | 27 +++--- 8 files changed, 105 insertions(+), 189 deletions(-) diff --git a/public/lesson/index.json b/public/lesson/index.json index c4318ae..d6009ef 100644 --- a/public/lesson/index.json +++ b/public/lesson/index.json @@ -1,3 +1 @@ -{ - "lesson-1": [] -} +["lesson-1"] diff --git a/public/lesson/lesson-1.json b/public/lesson/lesson-1.json index 50cdeaa..8d11e72 100644 --- a/public/lesson/lesson-1.json +++ b/public/lesson/lesson-1.json @@ -3,7 +3,7 @@ "description": "¡Pon a prueba tus conocimientos de Lengua de Señas Colombiana!", "questions": { "q-1": { - "lesson": [ + "information": [ { "type": "title", "content": "Prueba diagnóstica de Lengua de Señas Colombiana (LSC)" @@ -22,7 +22,7 @@ "correct": 3 }, "q-2": { - "lesson": [ + "information": [ { "type": "title", "content": "Prueba diagnóstica de Lengua de Señas Colombiana (LSC)" diff --git a/src/component/single-choice-question.ts b/src/component/single-choice-question.ts index 1b3c7b4..a9379b6 100644 --- a/src/component/single-choice-question.ts +++ b/src/component/single-choice-question.ts @@ -80,13 +80,7 @@ export class ComponentSingleChoiceQuestion extends LitElement { return false; } - if ( - ( - this.shadowRoot?.querySelectorAll("igc-radio")[ - this._lastRadio - ] as IgcRadioComponent - ).innerText === this.question.correct - ) { + if (this._lastRadio === this.question.correct) { return true; } diff --git a/src/lesson/index.ts b/src/lesson/index.ts index d818149..fb65f34 100644 --- a/src/lesson/index.ts +++ b/src/lesson/index.ts @@ -1,127 +1,71 @@ const rootDirectory = location.origin + "/lesson"; -const rootIndex = rootDirectory + "/index.json"; +const rootIndex = `${rootDirectory}/index.json`; -export class LessonMetadata { +export class Lesson { constructor( - private readonly _id: string, public readonly name: string, - public readonly require: LessonMetadata[], + public readonly description: string, + public readonly questions: Map, ) {} - - async load(): Promise { - const rawLesson = await LessonMetadata.rawLessonDetails(this._id); - - return new LessonData( - rawLesson.title, - rawLesson.description, - rawLesson.summary, - LessonMetadata.parseQuestions(rawLesson.questions), - ); - } - - protected static async rawLessonDetails(id: string): Promise { - return await (await fetch(rootDirectory + "/" + id + "/index.json")).json(); - } - - protected static parseQuestions(questions: any): Question[] { - let parsedQuestions: Question[] = []; - - for (let question in questions) { - parsedQuestions.push(Question.parse(questions[question])); - } - - return parsedQuestions; - } } -export class LessonData { +export class Question { constructor( - public readonly title: string, - public readonly description: string, - public readonly questions: Question[], + public readonly information: Information[], + public readonly question: string, + public readonly answers: string[], + public readonly correct: number, ) {} + + static parse(question: any): Question { + return new Question( + Information.parseList(question.lesson), + question.question, + question.answers, + question.correct, + ); + } } -export class LessonContent { +export class Information { constructor( public readonly type: "title" | "paragraph" | "image", public readonly content: string, ) {} - static parse(content: any): LessonContent { + static parse(content: any): Information { if (content.type === "image") { - return new LessonContent( + return new Information( content.type, - rootDirectory + "/image/" + content.content, + `${rootDirectory}/image/${content.content}`, ); } - return new LessonContent(content.type, content.content); + return new Information(content.type, content.content); } - static parseList(content: any): LessonContent[] { - let parsedContent: LessonContent[] = []; + static parseList(content: any): Information[] { + let parsedContent: Information[] = []; for (let c of content) { - parsedContent.push(LessonContent.parse(c)); + parsedContent.push(Information.parse(c)); } return parsedContent; } } -export class Question { - constructor( - public readonly lesson: LessonContent[], - public readonly question: string, - public readonly answers: string[], - private readonly _indexCorrect: number, - ) {} - - get correct(): string { - return this.answers[this._indexCorrect]; - } - - static parse(question: any): Question { - return new Question( - LessonContent.parseList(question.lesson), - question.question, - question.answers, - question.correct, - ); - } -} - -export async function avaibleLessons(): Promise> { - const lessonIndex = await (await fetch(rootIndex)).json(); - - let lessons = new Map(); - - for (let rawLesson of lessonIndex) { - let require = parseLessonRequeriments(rawLesson.require, lessons); - - lessons.set( - rawLesson.id, - new LessonMetadata(rawLesson.id, rawLesson.name, require), - ); - } - - return lessons; +export async function avaibleLessons(): Promise { + return await (await fetch(rootIndex)).json(); } -function parseLessonRequeriments( - require: string[], - lessons: Map, -): LessonMetadata[] { - let requeriments: LessonMetadata[] = []; +export async function loadLesson(id: string): Promise { + const lesson = await (await fetch(`${rootDirectory}/${id}.json`)).json(); + lesson.questions = new Map(Object.entries(lesson.questions)); - for (let req of require) { - for (let [id, lesson] of lessons) { - if (req === id) { - requeriments.push(lesson); - } - } + for (let [_, question] of lesson.questions) { + question.information = Information.parseList(question.information); } - return requeriments; + return lesson; } diff --git a/src/main.ts b/src/main.ts index 38a82bf..73e54e8 100644 --- a/src/main.ts +++ b/src/main.ts @@ -38,11 +38,7 @@ export class MainComponent extends LitElement { render: (params) => html``, enter: async (params) => { - if ((await avaibleLessons()).get(params["id"]!) != null) { - return true; - } - - return false; + return (await avaibleLessons()).includes(params["id"]!); }, }, ]); diff --git a/src/view/home.ts b/src/view/home.ts index c0cab94..ff2ca74 100644 --- a/src/view/home.ts +++ b/src/view/home.ts @@ -1,4 +1,4 @@ -import { LitElement, css, html } from "lit"; +import { LitElement, css, html, type TemplateResult } from "lit"; import { customElement, property, query, state } from "lit/decorators.js"; import { @@ -8,7 +8,7 @@ import { IgcDialogComponent, } from "igniteui-webcomponents"; -import { LessonData, LessonMetadata, avaibleLessons } from "lesson"; +import { Lesson, avaibleLessons, loadLesson } from "lesson"; import { currentSession } from "session"; import type { PartialNavDrawer } from "./partial/nav-drawer"; @@ -50,16 +50,11 @@ export class ViewHome extends LitElement { defineComponents(IgcDialogComponent, IgcCardComponent, IgcButtonComponent); avaibleLessons().then((lessons) => { - this._lessonsMetadata = lessons; - - for (let [id] of this._lessonsMetadata) { - this._lessonsMetadata - .get(id)! - .load() - .then((lesson) => { - this._lessonsData.set(id, lesson); - this.requestUpdate(); - }); + for (let id of lessons) { + loadLesson(id).then((lesson) => { + this._lessons.set(id, lesson); + this.requestUpdate(); + }); } }); @@ -67,9 +62,7 @@ export class ViewHome extends LitElement { } @state() - private _lessonsMetadata = new Map(); - @state() - private _lessonsData = new Map(); + private _lessons = new Map(); @state() private _session = currentSession(); @@ -81,14 +74,15 @@ export class ViewHome extends LitElement { private _navDrawer!: PartialNavDrawer; override render() { - if (this._lessonsData.size === 0) { + if (this._lessons.size === 0) { return html`Loading...`; } - const lessonsId: string[] = []; - for (let [id] of this._lessonsMetadata) { + const lessons = new Map(); + + for (let [id, lesson] of this._lessons) { if (this._session.getPoints(id) <= 75) { - lessonsId.push(id); + lessons.set(id, lesson); } } @@ -106,51 +100,37 @@ export class ViewHome extends LitElement {

Puntos totales: ${this.totalScore}

- ${lessonsId.map( - (id) => html` - - -

${this._lessonsMetadata.get(id)!.name}

-

${this._lessonsData.get(id)!.title}

-
- -

${this._lessonsData.get(id)!.description}

-
- - { - this._startLesson(id); - }} - >Comenzar - { - this._showLessonDescription(this._lessonsData.get(id)!); - }} - >Previsualizar - -
- `, - )} + ${(() => { + const render = new Array(); + + for (let [id, lesson] of lessons) { + render.push(html` + + +

${lesson.name}

+
+ +

${lesson.description}

+
+ + { + this._startLesson(id); + }} + >Comenzar + +
+ `); + } + + return render; + })()}
- - -

Por hacer...

-
`; } - @query("igc-dialog", true) - private _dialog!: IgcDialogComponent; - - private _showLessonDescription(lesson: LessonData) { - this._dialog.innerHTML = `

${lesson.summary}

`; - this._dialog.show(); - } - private _startLesson(id: string) { this.dispatchEvent( new CustomEvent("goto-url", { diff --git a/src/view/lesson.ts b/src/view/lesson.ts index c1a21c3..6bbfc2c 100644 --- a/src/view/lesson.ts +++ b/src/view/lesson.ts @@ -16,7 +16,7 @@ import { import { ComponentSingleChoiceQuestion } from "component/single-choice-question"; -import { LessonData, avaibleLessons } from "lesson"; +import { Lesson, loadLesson } from "lesson"; import { currentSession } from "session"; import type { PartialNavDrawer } from "view/partial/nav-drawer"; @@ -71,13 +71,9 @@ export class ViewLesson extends LitElement { super.connectedCallback(); if (this._lesson == null) { - avaibleLessons() - .then((lessons) => { - return lessons.get(this.lessonId)!.load(); - }) - .then((lesson) => { - this._lesson = lesson; - }); + loadLesson(this.lessonId).then((lesson) => { + this._lesson = lesson; + }); } defineComponents(IgcButtonComponent, IgcStepperComponent); @@ -87,7 +83,7 @@ export class ViewLesson extends LitElement { lessonId: string = ""; @state() - private _lesson?: LessonData; + private _lesson?: Lesson; @state() private _score = 0; @@ -102,10 +98,12 @@ export class ViewLesson extends LitElement { let questions: ComponentSingleChoiceQuestion[] = []; - for (let question of this._lesson.questions) { + for (let [_, question] of this._lesson.questions) { questions.push(new ComponentSingleChoiceQuestion(question)); } + console.log(this._lesson); + return html` { @@ -118,7 +116,8 @@ export class ViewLesson extends LitElement { Descripción
- ${this._lesson.questions[0].lesson.map((i) => { + ${this._lesson.questions.get("q-1")!.information.map((i) => { + // ^ Temporary workarount. switch (i.type) { case "title": return html`

${i.content}

`; diff --git a/src/view/stats.ts b/src/view/stats.ts index 9e640e5..d51edae 100644 --- a/src/view/stats.ts +++ b/src/view/stats.ts @@ -3,7 +3,7 @@ import { customElement, query, state } from "lit/decorators.js"; import { IgcListComponent, defineComponents } from "igniteui-webcomponents"; -import { LessonMetadata, avaibleLessons } from "lesson"; +import { Lesson, avaibleLessons, loadLesson } from "lesson"; import { currentSession } from "session"; import type { PartialNavDrawer } from "./partial/nav-drawer"; @@ -23,14 +23,19 @@ export class ViewStats extends LitElement { super.connectedCallback(); avaibleLessons().then((lessons) => { - this._lessons = lessons; + for (let id of lessons) { + loadLesson(id).then((lesson) => { + this._lessons.set(id, lesson); + this.requestUpdate(); + }); + } }); defineComponents(IgcListComponent); } @state() - private _lessons = new Map(); + private _lessons = new Map(); @state() private _session = currentSession(); @@ -38,10 +43,11 @@ export class ViewStats extends LitElement { private _navDrawer!: PartialNavDrawer; protected override render(): unknown { - const idsWithPoints = []; - for (let id in this._lessons) { - if (this._session.getPoints(id) > 0) { - idsWithPoints.push(id); + const lessonsWithPoints = new Array<{ name: string; points: number }>(); + for (let [id, lesson] of this._lessons) { + const points = this._session.getPoints(id); + if (points > 0) { + lessonsWithPoints.push({ name: lesson.name, points: points }); } } @@ -56,11 +62,10 @@ export class ViewStats extends LitElement {

Estadísticas

- ${idsWithPoints.map( - (id) => html` + ${lessonsWithPoints.map( + (lesson) => html` ${this._lessons.get(id)!.name}: ${this._session.getPoints(id)} - puntos.${lesson.name}: ${lesson.points} puntos. `, )}