mirror of
https://github.com/rzmk/learnhouse.git
synced 2025-12-19 04:19:25 +00:00
Merge pull request #7 from learnhouse/feat/coursepage_improvements
Feat/coursepage improvements
This commit is contained in:
commit
23c4224b2b
6 changed files with 220 additions and 22 deletions
|
|
@ -66,16 +66,16 @@ function CourseEdit() {
|
|||
// Submit new chapter
|
||||
const submitChapter = async (chapter: any) => {
|
||||
await createChapter(chapter, courseid);
|
||||
getCourseChapters();
|
||||
await getCourseChapters();
|
||||
setNewChapterModal(false);
|
||||
};
|
||||
|
||||
// Submit new element
|
||||
const submitElement = async (element: any) => {
|
||||
console.log("submitElement", element);
|
||||
updateChaptersMetadata(courseid, data);
|
||||
await updateChaptersMetadata(courseid, data);
|
||||
await createElement(element, element.chapterId);
|
||||
getCourseChapters();
|
||||
await getCourseChapters();
|
||||
setNewElementModal(false);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -31,9 +31,25 @@ function ElementPage() {
|
|||
|
||||
const output = useMemo(() => {
|
||||
if (router.isReady) {
|
||||
console.log("element", element.content);
|
||||
console.log( "el",element.content);
|
||||
|
||||
let content = Object.keys(element.content).length > 0 ? element.content : {
|
||||
"type": "doc",
|
||||
"content": [
|
||||
{
|
||||
"type": "paragraph",
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "Hello world, this is a example Canva ⚡️"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
console.log("element", content);
|
||||
|
||||
return generateHTML(element.content, [Document, StarterKit, Paragraph, Text, Bold]);
|
||||
return generateHTML(content, [Document, StarterKit, Paragraph, Text, Bold]);
|
||||
}
|
||||
}, [element.content]);
|
||||
|
||||
|
|
@ -44,7 +60,7 @@ function ElementPage() {
|
|||
) : (
|
||||
<div>
|
||||
<p>element</p>
|
||||
<h1>{element.name}</h1>
|
||||
<h1>{element.name} </h1>
|
||||
<hr />
|
||||
<div dangerouslySetInnerHTML={{ __html: output } as any}></div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,23 +1,25 @@
|
|||
import { EyeOpenIcon, Pencil2Icon } from "@radix-ui/react-icons";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
import Layout from "../../../../../components/ui/Layout";
|
||||
import { getAPIUrl, getBackendUrl } from "../../../../../services/config";
|
||||
import { getCourse } from "../../../../../services/courses/courses";
|
||||
import { getCourse, getCourseMetadata } from "../../../../../services/courses/courses";
|
||||
import { getOrganizationContextInfo } from "../../../../../services/orgs";
|
||||
|
||||
const CourseIdPage = () => {
|
||||
const router = useRouter();
|
||||
const { courseid } = router.query;
|
||||
const { courseid, orgslug } = router.query;
|
||||
|
||||
const [isLoading, setIsLoading] = React.useState(true);
|
||||
const [courseInfo, setCourseInfo] = React.useState({}) as any;
|
||||
|
||||
async function fetchCourseInfo() {
|
||||
const course = await getCourse("course_" + courseid);
|
||||
const course = await getCourseMetadata("course_" + courseid);
|
||||
|
||||
setCourseInfo(course);
|
||||
console.log("courseinfo" , courseInfo);
|
||||
|
||||
|
||||
setIsLoading(false);
|
||||
}
|
||||
|
|
@ -27,7 +29,7 @@ const CourseIdPage = () => {
|
|||
fetchCourseInfo();
|
||||
}
|
||||
return () => {};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [router.isReady]);
|
||||
|
||||
return (
|
||||
|
|
@ -35,22 +37,82 @@ const CourseIdPage = () => {
|
|||
{isLoading ? (
|
||||
<div>Loading...</div>
|
||||
) : (
|
||||
<div>
|
||||
<CoursePageLayout>
|
||||
<br></br>
|
||||
<h1>{courseInfo.name}</h1>
|
||||
<CourseWrapper>
|
||||
<img src={`${getBackendUrl()}content/uploads/img/${courseInfo.thumbnail}`} alt="" />
|
||||
</CourseWrapper>
|
||||
</div>
|
||||
<p>Course</p>
|
||||
<h1>
|
||||
{courseInfo.course.name}{" "}
|
||||
<Link href={`/org/${orgslug}/course/${courseid}/edit`}>
|
||||
<a target="_blank" rel="noopener noreferrer">
|
||||
<Pencil2Icon />
|
||||
</a>
|
||||
</Link>{" "}
|
||||
</h1>
|
||||
<br />
|
||||
<ChaptersWrapper>
|
||||
{courseInfo.chapters.map((chapter: any) => {
|
||||
return (
|
||||
<>
|
||||
{chapter.elements.map((element: any) => {
|
||||
return (
|
||||
<>
|
||||
<Link href={`/org/${orgslug}/course/${courseid}/element/${element.id.replace("element_", "")}`}>
|
||||
<a target="_blank" rel="noopener noreferrer">
|
||||
<ChapterIndicator />
|
||||
</a>
|
||||
</Link>{" "}
|
||||
</>
|
||||
);
|
||||
})}
|
||||
|
||||
</>
|
||||
);
|
||||
})}
|
||||
</ChaptersWrapper>
|
||||
|
||||
<CourseThumbnailWrapper>
|
||||
<img src={`${getBackendUrl()}content/uploads/img/${courseInfo.course.thumbnail}`} alt="" />
|
||||
</CourseThumbnailWrapper>
|
||||
|
||||
<h2>Description</h2>
|
||||
<p>{courseInfo.course.description}</p>
|
||||
|
||||
<h2>What you will learn</h2>
|
||||
<p>{courseInfo.course.learnings == ![] ? "no data" : courseInfo.course.learnings}</p>
|
||||
|
||||
<h2>Course Lessons</h2>
|
||||
|
||||
{courseInfo.chapters.map((chapter: any) => {
|
||||
return (
|
||||
<>
|
||||
<h3>Chapter : {chapter.name}</h3>
|
||||
{chapter.elements.map((element: any) => {
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
Element {element.name}
|
||||
<Link href={`/org/${orgslug}/course/${courseid}/element/${element.id.replace("element_", "")}`}>
|
||||
<a target="_blank" rel="noopener noreferrer">
|
||||
<EyeOpenIcon />
|
||||
</a>
|
||||
</Link>{" "}
|
||||
</p>
|
||||
</>
|
||||
);
|
||||
})}
|
||||
|
||||
</>
|
||||
);
|
||||
})}
|
||||
</CoursePageLayout>
|
||||
)}
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
const CourseWrapper = styled.div`
|
||||
const CourseThumbnailWrapper = styled.div`
|
||||
display: flex;
|
||||
img {
|
||||
position: absolute;
|
||||
width: 794px;
|
||||
height: 224.28px;
|
||||
object-fit: cover;
|
||||
|
|
@ -62,5 +124,29 @@ const CourseWrapper = styled.div`
|
|||
border-radius: 7px;
|
||||
}
|
||||
`;
|
||||
const CoursePageLayout = styled.div`
|
||||
margin-left: 40px;
|
||||
margin-right: 40px;
|
||||
`;
|
||||
|
||||
const ChaptersWrapper = styled.div`
|
||||
display: flex;
|
||||
`;
|
||||
const ChapterIndicator = styled.div`
|
||||
border-radius: 20px;
|
||||
height: 5px;
|
||||
background: #151515;
|
||||
border-radius: 3px;
|
||||
width: 40px;
|
||||
background-color: black;
|
||||
margin: 10px;
|
||||
margin-left: 0px;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
width: 50px;
|
||||
cursor: pointer;
|
||||
}
|
||||
`;
|
||||
|
||||
export default CourseIdPage;
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ export async function getOrgCourses(org_id: number) {
|
|||
.catch((error) => console.log("error", error));
|
||||
}
|
||||
|
||||
export async function getCourse(course_id: any) {
|
||||
export async function getCourse(course_id: string) {
|
||||
const HeadersConfig = new Headers({ "Content-Type": "application/json" });
|
||||
|
||||
const requestOptions: any = {
|
||||
|
|
@ -31,6 +31,23 @@ export async function getCourse(course_id: any) {
|
|||
.catch((error) => console.log("error", error));
|
||||
}
|
||||
|
||||
export async function getCourseMetadata(course_id: string) {
|
||||
const HeadersConfig = new Headers({ "Content-Type": "application/json" });
|
||||
|
||||
const requestOptions: any = {
|
||||
method: "GET",
|
||||
headers: HeadersConfig,
|
||||
redirect: "follow",
|
||||
credentials: "include",
|
||||
};
|
||||
|
||||
// todo : add course id to url
|
||||
return fetch(`${getAPIUrl()}courses/meta/${course_id}`, requestOptions)
|
||||
.then((result) => result.json())
|
||||
.catch((error) => console.log("error", error));
|
||||
|
||||
}
|
||||
|
||||
export async function createNewCourse(org_id: string, course_body: any, thumbnail: any) {
|
||||
const HeadersConfig = new Headers();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
from fastapi import APIRouter, Depends, UploadFile, Form
|
||||
from src.dependencies.auth import get_current_user
|
||||
|
||||
from src.services.courses.courses import Course, create_course, get_course, get_courses, update_course, delete_course, update_course_thumbnail
|
||||
from src.services.courses.courses import Course, create_course, get_course, get_course_meta, get_courses, update_course, delete_course, update_course_thumbnail
|
||||
from src.services.users import PublicUser
|
||||
|
||||
|
||||
|
|
@ -34,6 +34,14 @@ async def api_get_course(course_id: str, current_user: PublicUser = Depends(get
|
|||
return await get_course(course_id, current_user=current_user)
|
||||
|
||||
|
||||
@router.get("/meta/{course_id}")
|
||||
async def api_get_course_meta(course_id: str, current_user: PublicUser = Depends(get_current_user)):
|
||||
"""
|
||||
Get single Course Metadata (chapters, elements) by course_id
|
||||
"""
|
||||
return await get_course_meta(course_id, current_user=current_user)
|
||||
|
||||
|
||||
@router.get("/{org_id}/page/{page}/limit/{limit}")
|
||||
async def api_get_course_by(page: int, limit: int, org_id: str):
|
||||
"""
|
||||
|
|
@ -56,4 +64,4 @@ async def api_delete_course(course_id: str, current_user: PublicUser = Depends(g
|
|||
Delete Course by ID
|
||||
"""
|
||||
|
||||
return await delete_course(course_id, current_user)
|
||||
return await delete_course(course_id, current_user)
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import os
|
|||
from typing import List
|
||||
from uuid import uuid4
|
||||
from pydantic import BaseModel
|
||||
from src.services.courses.elements import ElementInDB
|
||||
from src.services.uploads import upload_thumbnail
|
||||
from src.services.users import PublicUser, User
|
||||
from src.services.database import create_config_collection, check_database, create_database, learnhouseDB
|
||||
|
|
@ -30,6 +31,21 @@ class CourseInDB(Course):
|
|||
updateDate: str
|
||||
authors: List[str]
|
||||
|
||||
|
||||
# TODO : wow terrible, fix this
|
||||
# those models need to be available only in the chapters service
|
||||
class CourseChapter(BaseModel):
|
||||
name: str
|
||||
description: str
|
||||
elements: list
|
||||
|
||||
|
||||
class CourseChapterInDB(CourseChapter):
|
||||
coursechapter_id: str
|
||||
course_id: str
|
||||
creationDate: str
|
||||
updateDate: str
|
||||
|
||||
#### Classes ####################################################
|
||||
|
||||
# TODO : Add courses photo & cover upload and delete
|
||||
|
|
@ -56,6 +72,61 @@ async def get_course(course_id: str, current_user: PublicUser):
|
|||
return course
|
||||
|
||||
|
||||
async def get_course_meta(course_id: str, current_user: PublicUser):
|
||||
await check_database()
|
||||
courses = learnhouseDB["courses"]
|
||||
coursechapters = learnhouseDB["coursechapters"]
|
||||
course = courses.find_one({"course_id": course_id})
|
||||
elements = learnhouseDB["elements"]
|
||||
|
||||
|
||||
# verify course rights
|
||||
await verify_rights(course_id, current_user, "read")
|
||||
|
||||
if not course:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_409_CONFLICT, detail="Course does not exist")
|
||||
|
||||
|
||||
coursechapters = coursechapters.find(
|
||||
{"course_id": course_id}).sort("name", 1)
|
||||
|
||||
# elements
|
||||
coursechapter_elementIds_global = []
|
||||
|
||||
# chapters
|
||||
chapters = {}
|
||||
for coursechapter in coursechapters:
|
||||
coursechapter = CourseChapterInDB(**coursechapter)
|
||||
coursechapter_elementIds = []
|
||||
|
||||
for element in coursechapter.elements:
|
||||
coursechapter_elementIds.append(element)
|
||||
coursechapter_elementIds_global.append(element)
|
||||
|
||||
chapters[coursechapter.coursechapter_id] = {
|
||||
"id": coursechapter.coursechapter_id, "name": coursechapter.name, "elementIds": coursechapter_elementIds
|
||||
}
|
||||
|
||||
# elements
|
||||
elements_list = {}
|
||||
for element in elements.find({"element_id": {"$in": coursechapter_elementIds_global}}):
|
||||
element = ElementInDB(**element)
|
||||
elements_list[element.element_id] = {
|
||||
"id": element.element_id, "name": element.name, "type": element.type, "content": element.content
|
||||
}
|
||||
|
||||
chapters_list_with_elements = []
|
||||
for chapter in chapters:
|
||||
chapters_list_with_elements.append(
|
||||
{"id": chapters[chapter]["id"], "name": chapters[chapter]["name"], "elements": [elements_list[element] for element in chapters[chapter]["elementIds"]]})
|
||||
course = Course(**course)
|
||||
return {
|
||||
"course": course,
|
||||
"chapters": chapters_list_with_elements,
|
||||
}
|
||||
|
||||
|
||||
async def create_course(course_object: Course, org_id: str, current_user: PublicUser, thumbnail_file: UploadFile | None = None):
|
||||
await check_database()
|
||||
courses = learnhouseDB["courses"]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue