From f84bbc60169f933d2e5bf24a097b546a09a5c71c Mon Sep 17 00:00:00 2001 From: Ibitoye Rotimi Best Date: Wed, 14 Jul 2021 09:05:09 +0300 Subject: [PATCH] Sync lesson/id w/ server + edit & view mode --- .../components/Lesson/Exercises/index.svelte | 35 +-- .../Lesson/Materials/EditMode.svelte | 28 ++ .../Lesson/Materials/ViewMode.svelte | 96 +++++++ .../Lesson/{Readme => Materials}/index.svelte | 0 .../components/Lesson/Readme/EditMode.svelte | 16 -- .../components/Lesson/Readme/ViewMode.svelte | 62 ----- .../Course/components/Lesson/index.svelte | 40 --- .../Course/components/Lesson/store/lessons.js | 35 ++- .../Course/components/Navigation/index.svelte | 59 ++-- src/components/CourseContainer/index.svelte | 19 +- src/components/MarkdownRender/index.svelte | 9 + src/routes/api/_db.js | 259 ++++++++++-------- src/routes/api/course.js | 20 +- .../lessons/[...lessonParams]/index.svelte | 54 ++-- 14 files changed, 415 insertions(+), 317 deletions(-) create mode 100644 src/components/Course/components/Lesson/Materials/EditMode.svelte create mode 100644 src/components/Course/components/Lesson/Materials/ViewMode.svelte rename src/components/Course/components/Lesson/{Readme => Materials}/index.svelte (100%) delete mode 100644 src/components/Course/components/Lesson/Readme/EditMode.svelte delete mode 100644 src/components/Course/components/Lesson/Readme/ViewMode.svelte delete mode 100644 src/components/Course/components/Lesson/index.svelte create mode 100644 src/components/MarkdownRender/index.svelte diff --git a/src/components/Course/components/Lesson/Exercises/index.svelte b/src/components/Course/components/Lesson/Exercises/index.svelte index 1b4dc2e8..ce346a77 100644 --- a/src/components/Course/components/Lesson/Exercises/index.svelte +++ b/src/components/Course/components/Lesson/Exercises/index.svelte @@ -5,21 +5,11 @@ import TextField from '../../../../Form/TextField.svelte'; import Exercise from '../Exercise/index.svelte'; + import { lesson } from '../store/lessons'; + export let path; export let exerciseId; - let exercises = [ - { - id: 1, - title: 'Practice Exercise', - link: `${path}/1`, - }, - { - id: 2, - title: 'Home task', - link: `${path}/2`, - }, - ]; let open = false; let newExercise = { id: 1, @@ -28,13 +18,16 @@ }; function handleAddExercise() { - exercises = [ - ...exercises, - { - ...newExercise, - link: `${path}/${exercises.length + 1}`, - }, - ]; + lesson.update((_lesson) => ({ + ..._lesson, + exercises: [ + ..._lesson.exercises, + { + ...newExercise, + link: `${path}/${_lesson.exercises.length + 1}`, + }, + ], + })); handleCancelAddExercise(); } @@ -42,7 +35,7 @@ function handleCancelAddExercise() { open = false; newExercise = { - id: exercises.length + 1, + id: $lesson.exercises.length + 1, title: '', link: '', }; @@ -81,7 +74,7 @@
- {#each exercises as exercise, index} + {#each $lesson.exercises as exercise}

{exercise.title}

Created Jul 3, 2021

diff --git a/src/components/Course/components/Lesson/Materials/EditMode.svelte b/src/components/Course/components/Lesson/Materials/EditMode.svelte new file mode 100644 index 00000000..40458441 --- /dev/null +++ b/src/components/Course/components/Lesson/Materials/EditMode.svelte @@ -0,0 +1,28 @@ + + + + + + + +
+ + + + + + + + + +
+
diff --git a/src/components/Course/components/Lesson/Materials/ViewMode.svelte b/src/components/Course/components/Lesson/Materials/ViewMode.svelte new file mode 100644 index 00000000..61c4aba8 --- /dev/null +++ b/src/components/Course/components/Lesson/Materials/ViewMode.svelte @@ -0,0 +1,96 @@ + + + + + + + +
+ + + + + - {:else if currentTab === 2} - - {/if} -
- - diff --git a/src/components/Course/components/Lesson/index.svelte b/src/components/Course/components/Lesson/index.svelte deleted file mode 100644 index ad9a2c6f..00000000 --- a/src/components/Course/components/Lesson/index.svelte +++ /dev/null @@ -1,40 +0,0 @@ - - -
- - -
- {#if tab === 'lessons'} - - {:else if tab === 'exercises'} - - {/if} -
-
- - diff --git a/src/components/Course/components/Lesson/store/lessons.js b/src/components/Course/components/Lesson/store/lessons.js index 139586ff..d422d7f1 100644 --- a/src/components/Course/components/Lesson/store/lessons.js +++ b/src/components/Course/components/Lesson/store/lessons.js @@ -1,42 +1,51 @@ -import { writable } from "svelte/store"; +import { writable } from 'svelte/store'; export const lessons = writable([]); +export const lesson = writable({ + lesson_id: null, + materials: { + note: '', + slide: '', + video: '', + }, + exercises: [], +}); export const tutors = writable([ { id: 1, - text: "Sergey Semko", + text: 'Sergey Semko', }, { id: 3, - text: "Jonathan Nelson", + text: 'Jonathan Nelson', }, { id: 4, - text: "Sasha Pokidin", + text: 'Sasha Pokidin', }, { id: 5, - text: "Natasha Rudenko", + text: 'Natasha Rudenko', }, { id: 6, - text: "Yulia Marushko", + text: 'Yulia Marushko', }, ]); export function handleAddLesson() { const resources = [ { - label: "lesson", + label: 'lesson', value: 0, }, { - label: "quiz", + label: 'quiz', value: 0, }, { - label: "home task", + label: 'home task', value: 0, }, ]; @@ -45,13 +54,13 @@ export function handleAddLesson() { return [ ..._lessons, { - title: "Untitled lesson", - to: "/courses/1/lessons/" + (_lessons.length + 1), + title: 'Untitled lesson', + to: '/courses/1/lessons/' + (_lessons.length + 1), resources, tutor: { userId: 1, - avatar: "https://picsum.photos/32/32/?random", - name: "", + avatar: 'https://picsum.photos/32/32/?random', + name: '', }, date: new Date(), }, diff --git a/src/components/Course/components/Navigation/index.svelte b/src/components/Course/components/Navigation/index.svelte index 212531c0..31a1def2 100644 --- a/src/components/Course/components/Navigation/index.svelte +++ b/src/components/Course/components/Navigation/index.svelte @@ -1,20 +1,20 @@ diff --git a/src/components/MarkdownRender/index.svelte b/src/components/MarkdownRender/index.svelte new file mode 100644 index 00000000..5cca87e2 --- /dev/null +++ b/src/components/MarkdownRender/index.svelte @@ -0,0 +1,9 @@ + + +
+ {@html marked(content, { breaks: true, gfm: true })} +
diff --git a/src/routes/api/_db.js b/src/routes/api/_db.js index 12c9b4da..fdce85ab 100644 --- a/src/routes/api/_db.js +++ b/src/routes/api/_db.js @@ -1,5 +1,5 @@ -import { STATUS } from "../../utils/constants/answers"; -import { QUESTION_TYPE } from "../../components/Question/constants"; +import { STATUS } from '../../utils/constants/answers'; +import { QUESTION_TYPE } from '../../components/Question/constants'; const ROLE = { ADMIN: 0, @@ -10,66 +10,66 @@ const ROLE = { const tutors = [ { id: 1, - text: "Sergey Semko", + text: 'Sergey Semko', }, { id: 3, - text: "Jonathan Nelson", + text: 'Jonathan Nelson', }, { id: 4, - text: "Sasha Pokidin", + text: 'Sasha Pokidin', }, { id: 5, - text: "Natasha Rudenko", + text: 'Natasha Rudenko', }, { id: 6, - text: "Yulia Marushko", + text: 'Yulia Marushko', }, ]; const people = [ { - name: "Alexander Pokidin", - title: "Senior Software Engineer", - avatar: "https://i.pravatar.cc/150?img=1", + name: 'Alexander Pokidin', + title: 'Senior Software Engineer', + avatar: 'https://i.pravatar.cc/150?img=1', role: ROLE.TUTOR, - telegramLink: "https://t.me/seed_of_abraham", - mailLink: "mailto:irb.ossystem@gmail.com", + telegramLink: 'https://t.me/seed_of_abraham', + mailLink: 'mailto:irb.ossystem@gmail.com', }, { - name: "Andrey Filatov", - title: "Fullstack Software Engineer", - avatar: "https://i.pravatar.cc/150?img=2", + name: 'Andrey Filatov', + title: 'Fullstack Software Engineer', + avatar: 'https://i.pravatar.cc/150?img=2', role: ROLE.TUTOR, - telegramLink: "https://t.me/seed_of_abraham", - mailLink: "mailto:irb.ossystem@gmail.com", + telegramLink: 'https://t.me/seed_of_abraham', + mailLink: 'mailto:irb.ossystem@gmail.com', }, { - name: "Sergey Semko", - title: "Senior Software Engineer", - avatar: "https://i.pravatar.cc/150?img=3", + name: 'Sergey Semko', + title: 'Senior Software Engineer', + avatar: 'https://i.pravatar.cc/150?img=3', role: ROLE.TUTOR, - telegramLink: "https://t.me/seed_of_abraham", - mailLink: "mailto:irb.ossystem@gmail.com", + telegramLink: 'https://t.me/seed_of_abraham', + mailLink: 'mailto:irb.ossystem@gmail.com', }, { - name: "Natalia Fedii", - title: "Project Manager", - avatar: "https://i.pravatar.cc/150?img=4", + name: 'Natalia Fedii', + title: 'Project Manager', + avatar: 'https://i.pravatar.cc/150?img=4', role: ROLE.TUTOR, - telegramLink: "https://t.me/seed_of_abraham", - mailLink: "mailto:irb.ossystem@gmail.com", + telegramLink: 'https://t.me/seed_of_abraham', + mailLink: 'mailto:irb.ossystem@gmail.com', }, ]; const courses = [ { id: 1, - title: "React.js Fundamentals", - status: "", + title: 'React.js Fundamentals', + status: '', }, ]; @@ -87,24 +87,24 @@ const lessons = [ { id: 1, course_id: 1, - title: "Вступительное слово. Софт скилы", - to: "/courses/1/lessons/1", + title: 'Вступительное слово. Софт скилы', + to: '/courses/1/lessons/1', tutor: { userId: 1, - avatar: "https://picsum.photos/32/32/?random", - name: "Sergey Semko", + avatar: 'https://picsum.photos/32/32/?random', + name: 'Sergey Semko', }, resources: [ { - label: "lesson", + label: 'lesson', value: 1, }, { - label: "quiz", + label: 'quiz', value: 1, }, { - label: "home task", + label: 'home task', value: 2, }, ], @@ -114,24 +114,24 @@ const lessons = [ { id: 2, course_id: 1, - title: "Введение в ReactJS", - to: "/courses/1/lessons/2", + title: 'Введение в ReactJS', + to: '/courses/1/lessons/2', tutor: { userId: 1, - avatar: "https://picsum.photos/32/32/?random", - name: "Sergey Semko", + avatar: 'https://picsum.photos/32/32/?random', + name: 'Sergey Semko', }, resources: [ { - label: "lesson", + label: 'lesson', value: 1, }, { - label: "quiz", + label: 'quiz', value: 1, }, { - label: "home task", + label: 'home task', value: 2, }, ], @@ -141,24 +141,24 @@ const lessons = [ { id: 3, course_id: 1, - title: "Компоненты", - to: "/courses/1/lessons/3", + title: 'Компоненты', + to: '/courses/1/lessons/3', tutor: { userId: 1, - avatar: "https://picsum.photos/32/32/?random", - name: "Sergey Semko", + avatar: 'https://picsum.photos/32/32/?random', + name: 'Sergey Semko', }, resources: [ { - label: "lesson", + label: 'lesson', value: 1, }, { - label: "quiz", + label: 'quiz', value: 1, }, { - label: "home task", + label: 'home task', value: 2, }, ], @@ -168,24 +168,24 @@ const lessons = [ { id: 4, course_id: 1, - title: "Состояние компонентов и пропсы", - to: "/courses/1/lessons/4", + title: 'Состояние компонентов и пропсы', + to: '/courses/1/lessons/4', tutor: { userId: 1, - avatar: "https://picsum.photos/32/32/?random", - name: "Sergey Semko", + avatar: 'https://picsum.photos/32/32/?random', + name: 'Sergey Semko', }, resources: [ { - label: "lesson", + label: 'lesson', value: 1, }, { - label: "quiz", + label: 'quiz', value: 1, }, { - label: "home task", + label: 'home task', value: 2, }, ], @@ -195,24 +195,24 @@ const lessons = [ { id: 5, course_id: 1, - title: "Жизненный цикл", - to: "/courses/1/lessons/5", + title: 'Жизненный цикл', + to: '/courses/1/lessons/5', tutor: { userId: 1, - avatar: "https://picsum.photos/32/32/?random", - name: "Sergey Semko", + avatar: 'https://picsum.photos/32/32/?random', + name: 'Sergey Semko', }, resources: [ { - label: "lesson", + label: 'lesson', value: 1, }, { - label: "quiz", + label: 'quiz', value: 1, }, { - label: "home task", + label: 'home task', value: 2, }, ], @@ -221,43 +221,65 @@ const lessons = [ }, ]; +const lessonData = [ + { + lesson_id: 1, + materials: { + note: `# Introduction\n\nWelcome to this course, we are glad you made it here\n\n## What you'l learn\n\n1. Build powerful, fast, user-friendly and reactive web apps.\n2. Provide amazing user experiences by leveraging the power of JavaScript with ease.\n3. Apply for high-paid jobs or work as a freelancer in one the most-demanded sectors you can find in web dev right now.\n4. Learn all about React Hooks and React Components.`, + slide: + 'https://docs.google.com/presentation/d/e/2PACX-1vS7mulzY5v1X_D0Gz68M2sggq2zjHCuoyY5JI07hcsOA4svDV5rxhLD9V3ckO_Rz7TK1YniQJtu0CXM/embed?start=false&loop=false&delayms=3000', + video: 'https://www.youtube.com/embed/luM5uobewhA', + }, + exercises: [ + { + id: 1, + title: 'Practice Exercise', + }, + { + id: 2, + title: 'Home task', + }, + ], + }, +]; + // id, lesson_id -const exercises = [ +const lesson_exercise = [ { id: 1, lesson_id: 1, - title: "Home task 1", + title: 'Home task 1', description: "You will be to answer 10 questions, it isn't timed so you can take your time to answer. You can also continue from where you left off, you don't need to worry cause everything is automatically syncronized in the cloud.", questions: [ { - id: "react-founder", + id: 'react-founder', type: QUESTION_TYPE.CHECKBOX, - title: "Who is the creator of React.js", + title: 'Who is the creator of React.js', options: [ { - id: "1", - value: "Dan Abrahmov", + id: '1', + value: 'Dan Abrahmov', }, { - id: "2", - value: "Google", + id: '2', + value: 'Google', }, { - id: "3", - value: "Facebook", + id: '3', + value: 'Facebook', }, { - id: "4", - value: "Traversy Media", + id: '4', + value: 'Traversy Media', }, ], - answers: ["3"], + answers: ['3'], }, { - id: "vue-founder", + id: 'vue-founder', type: QUESTION_TYPE.CHECKBOX, - title: "Who is the creator of Vue.js", + title: 'Who is the creator of Vue.js', code: `const name = 'Josh Perez';\nconst element =

Hello, {name}

;\n\nReactDOM.render(\n element,\, document.getElementById('root') @@ -265,62 +287,63 @@ const exercises = [ `, options: [ { - id: "1", - value: "Evan Vue", + id: '1', + value: 'Evan Vue', }, { - id: "2", - value: "Mark Zukerberg", + id: '2', + value: 'Mark Zukerberg', }, { - id: "3", - value: "Prince Charles", + id: '3', + value: 'Prince Charles', }, { - id: "4", - value: "Bill Gates", + id: '4', + value: 'Bill Gates', }, ], - answers: ["3"], + answers: ['3'], }, { - id: "svelte-founder", + id: 'svelte-founder', type: QUESTION_TYPE.RADIO, - title: "Who is the creator of Svelte.js", + title: 'Who is the creator of Svelte.js', options: [ { - id: "1", - value: "Hillary Svelte", + id: '1', + value: 'Hillary Svelte', }, { - id: "2", - value: "Mircosoft", + id: '2', + value: 'Mircosoft', }, { - id: "3", - value: "Elevate", + id: '3', + value: 'Elevate', }, { - id: "4", - value: "Coding Train", + id: '4', + value: 'Coding Train', }, ], - answers: ["2"], + answers: ['2'], }, { - id: "angular-founder", + id: 'angular-founder', type: QUESTION_TYPE.TEXTAREA, - title: "Who is the creator of Angular.js", - value: "", + title: 'Who is the creator of Angular.js', + value: '', }, ], }, ]; -const answers = [ +const exercise_answers = [ { lesson_id: 1, exercise_id: 1, + taken_by: {}, answers: {}, scores: {}, currentQuestionIndex: 0, @@ -330,15 +353,15 @@ const answers = [ }, ]; -const lessonLookup = new Map(); -lessons.forEach((lesson) => { - lessonLookup.set(`${lesson.id}`, JSON.stringify(lesson)); -}); +// const lessonLookup = new Map(); +// lessons.forEach((lesson) => { +// lessonLookup.set(`${lesson.id}`, JSON.stringify(lesson)); +// }); export function getCourse(id) { return { id, - name: "React.js", + name: 'React.js', people, roles: ROLE, lessons: getLessons(id), @@ -350,16 +373,28 @@ export function getLessons(courseId) { } export function getLesson(id) { - return lookup.get(id); + return ( + lessonData.find((lesson) => lesson.lesson_id === id) || { + lesson_id: null, + materials: { + note: '', + slide: '', + video: '', + }, + exercises: [], + } + ); } export function getExercises(lessonId) { - return exercises.filter((exercise) => exercise.lesson_id === lessonId); + return lesson_exercise.filter((exercise) => exercise.lesson_id === lessonId); } export function getExercise(exerciseId) { return { - exercise: exercises.find((exercise) => exercise.id === exerciseId), - answers: answers.find((answer) => answer.exercise_id === exerciseId), + exercise: lesson_exercise.find((exercise) => exercise.id === exerciseId), + answers: exercise_answers.find( + (answer) => answer.exercise_id === exerciseId + ), }; } diff --git a/src/routes/api/course.js b/src/routes/api/course.js index 68078d52..029144ea 100644 --- a/src/routes/api/course.js +++ b/src/routes/api/course.js @@ -1,15 +1,27 @@ -import { getCourse } from "./_db"; +import { getCourse, getExercise, getLesson } from './_db'; function writeJsonHead(res, statusCode) { res.writeHead(statusCode, { - "Content-Type": "application/json", + 'Content-Type': 'application/json', }); } export function get(req, res, next) { - const { id } = req.query; + const { id, lessonId, exerciseId } = req.query; + + const result = { + ...getCourse(parseInt(id, 2)), + }; + + if (lessonId) { + result.lesson = getLesson(parseInt(lessonId, 2)); + } + + if (exerciseId) { + result.exercise = getExercise(parseInt(exerciseId, 2)); + } writeJsonHead(res, 200); - return res.end(JSON.stringify(getCourse(parseInt(id, 2)))); + return res.end(JSON.stringify(result)); } diff --git a/src/routes/courses/[id]/lessons/[...lessonParams]/index.svelte b/src/routes/courses/[id]/lessons/[...lessonParams]/index.svelte index a91c487b..db52c580 100644 --- a/src/routes/courses/[id]/lessons/[...lessonParams]/index.svelte +++ b/src/routes/courses/[id]/lessons/[...lessonParams]/index.svelte @@ -3,11 +3,18 @@ const { id: courseId, lessonParams = [] } = params; const [lessonId, exerciseRouteName, exerciseId] = lessonParams; - const res = await this.fetch(`api/course?id=${courseId}`); + const res = await this.fetch( + `api/course?id=${courseId}&lessonId=${lessonId}&exerciseId=${exerciseId}` + ); const data = await res.json(); if (res.status === 200) { - return { courseData: data, lessonId, exerciseRouteName, exerciseId }; + return { + courseData: data, + lessonId, + isMaterialsTabActive: !exerciseRouteName, + exerciseId, + }; } else { this.error(res.status, data.message); } @@ -15,47 +22,60 @@ + > + +
+ (mode = mode === MODES.edit ? MODES.view : MODES.edit)} + /> +
+
+
- {#if !!exerciseRouteName} + {#if !isMaterialsTabActive} {:else} - + {/if}