mirror of
https://github.com/rzmk/learnhouse.git
synced 2025-12-19 04:19:25 +00:00
feat: various improvements
wip: frontend feat: enable cascade on foreign keys wip1 wip2 fix chapters issues wip4
This commit is contained in:
parent
2bf80030d7
commit
187f75e583
71 changed files with 879 additions and 568 deletions
|
|
@ -62,9 +62,9 @@ const CollectionPage = async (params: any) => {
|
|||
<br />
|
||||
<div className="home_courses flex flex-wrap">
|
||||
{col.courses.map((course: any) => (
|
||||
<div className="pr-8" key={course.course_id}>
|
||||
<Link href={getUriWithOrg(orgslug, "/course/" + removeCoursePrefix(course.course_id))}>
|
||||
<div className="inset-0 ring-1 ring-inset ring-black/10 rounded-lg shadow-xl relative w-[249px] h-[131px] bg-cover" style={{ backgroundImage: `url(${getCourseThumbnailMediaDirectory(course.org_id, course.course_id, course.thumbnail)})` }}>
|
||||
<div className="pr-8" key={course.course_uuid}>
|
||||
<Link href={getUriWithOrg(orgslug, "/course/" + removeCoursePrefix(course.course_uuid))}>
|
||||
<div className="inset-0 ring-1 ring-inset ring-black/10 rounded-lg shadow-xl relative w-[249px] h-[131px] bg-cover" style={{ backgroundImage: `url(${getCourseThumbnailMediaDirectory(course.org_id, course.course_uuid, course.thumbnail)})` }}>
|
||||
</div>
|
||||
</Link>
|
||||
<h2 className="font-bold text-lg w-[250px] py-2">{course.name}</h2>
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ function NewCollection(params: any) {
|
|||
description: description,
|
||||
courses: selectedCourses,
|
||||
public: true,
|
||||
org_id: org.org_id,
|
||||
org_id: org.id,
|
||||
};
|
||||
await createCollection(collection);
|
||||
await revalidateTags(["collections"], orgslug);
|
||||
|
|
@ -69,26 +69,29 @@ function NewCollection(params: any) {
|
|||
) : (
|
||||
<div>
|
||||
{courses.map((course: any) => (
|
||||
<div key={course.course_id} className="flex items-center mb-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
id={course.course_id}
|
||||
name={course.course_id}
|
||||
value={course.course_id}
|
||||
checked={selectedCourses.includes(course.course_id)}
|
||||
onChange={(e) => {
|
||||
const courseId = e.target.value;
|
||||
setSelectedCourses((prevSelectedCourses: string[]) => {
|
||||
if (e.target.checked) {
|
||||
return [...prevSelectedCourses, courseId];
|
||||
} else {
|
||||
return prevSelectedCourses.filter((selectedCourse) => selectedCourse !== courseId);
|
||||
}
|
||||
});
|
||||
}}
|
||||
className="mr-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
/>
|
||||
<label htmlFor={course.course_id} className="text-sm">{course.name}</label>
|
||||
<div key={course.course_uuid} className="flex items-center mb-2">
|
||||
|
||||
<input
|
||||
|
||||
type="checkbox"
|
||||
id={course.id}
|
||||
name={course.name}
|
||||
value={course.id}
|
||||
// id is an integer, not a string
|
||||
|
||||
onChange={(e) => {
|
||||
if (e.target.checked) {
|
||||
setSelectedCourses([...selectedCourses, course.id]);
|
||||
}
|
||||
else {
|
||||
setSelectedCourses(selectedCourses.filter((course_uuid: any) => course_uuid !== course.course_uuid));
|
||||
}
|
||||
}
|
||||
}
|
||||
className="mr-2"
|
||||
/>
|
||||
|
||||
<label htmlFor={course.course_uuid} className="text-sm">{course.name}</label>
|
||||
</div>
|
||||
))}
|
||||
|
||||
|
|
|
|||
|
|
@ -49,14 +49,17 @@ const CollectionsPage = async (params: any) => {
|
|||
const access_token = await getAccessTokenFromRefreshTokenCookie(cookieStore)
|
||||
const orgslug = params.params.orgslug;
|
||||
const org = await getOrganizationContextInfo(orgslug, { revalidate: 1800, tags: ['organizations'] });
|
||||
const org_id = org.org_id;
|
||||
const org_id = org.id;
|
||||
const collections = await getOrgCollectionsWithAuthHeader(org_id, access_token ? access_token : null, { revalidate: 0, tags: ['collections'] });
|
||||
|
||||
return (
|
||||
<GeneralWrapperStyled>
|
||||
<div className="flex justify-between" >
|
||||
<TypeOfContentTitle title="Collections" type="col" />
|
||||
<AuthenticatedClientElement checkMethod='roles' orgId={org_id}>
|
||||
<AuthenticatedClientElement
|
||||
ressourceType="collection"
|
||||
action="create"
|
||||
checkMethod='roles' orgId={org_id}>
|
||||
<Link className="flex justify-center" href={getUriWithOrg(orgslug, "/collections/new")}>
|
||||
<NewCollectionButton />
|
||||
</Link>
|
||||
|
|
@ -64,7 +67,7 @@ const CollectionsPage = async (params: any) => {
|
|||
</div>
|
||||
<div className="home_collections flex flex-wrap">
|
||||
{collections.map((collection: any) => (
|
||||
<div className="flex flex-col py-1 px-3" key={collection.collection_id}>
|
||||
<div className="flex flex-col py-1 px-3" key={collection.collection_uuid}>
|
||||
<CollectionThumbnail collection={collection} orgslug={orgslug} org_id={org_id} />
|
||||
</div>
|
||||
))}
|
||||
|
|
@ -81,7 +84,10 @@ const CollectionsPage = async (params: any) => {
|
|||
<h1 className="text-3xl font-bold text-gray-600">No collections yet</h1>
|
||||
<p className="text-lg text-gray-400">Create a collection to group courses together</p>
|
||||
</div>
|
||||
<AuthenticatedClientElement checkMethod='roles' orgId={org_id}>
|
||||
<AuthenticatedClientElement checkMethod='roles'
|
||||
ressourceType="collection"
|
||||
action="create"
|
||||
orgId={org_id}>
|
||||
<Link href={getUriWithOrg(orgslug, "/collections/new")}>
|
||||
<NewCollectionButton />
|
||||
</Link>
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ function ActivityClient(props: ActivityClientProps) {
|
|||
<div className="flex space-x-6">
|
||||
<div className="flex">
|
||||
<Link href={getUriWithOrg(orgslug, "") + `/course/${courseid}`}>
|
||||
<img className="w-[100px] h-[57px] rounded-md drop-shadow-md" src={`${getCourseThumbnailMediaDirectory(course.course.org_id, course.course.course_id, course.course.thumbnail)}`} alt="" />
|
||||
<img className="w-[100px] h-[57px] rounded-md drop-shadow-md" src={`${getCourseThumbnailMediaDirectory(course.course.org_id, course.course.course_uuid, course.course.thumbnail)}`} alt="" />
|
||||
</Link>
|
||||
</div>
|
||||
<div className="flex flex-col -space-y-1">
|
||||
|
|
@ -55,7 +55,7 @@ function ActivityClient(props: ActivityClientProps) {
|
|||
<h1 className="font-bold text-gray-950 text-2xl first-letter:uppercase" >{course.course.name}</h1>
|
||||
</div>
|
||||
</div>
|
||||
<ActivityIndicators course_id={courseid} current_activity={activityid} orgslug={orgslug} course={course} />
|
||||
<ActivityIndicators course_uuid={courseid} current_activity={activityid} orgslug={orgslug} course={course} />
|
||||
|
||||
<div className="flex justify-between items-center">
|
||||
<div className="flex flex-col -space-y-1">
|
||||
|
|
@ -15,23 +15,24 @@ import { getUser } from "@services/users/users";
|
|||
|
||||
const CourseClient = (props: any) => {
|
||||
const [user, setUser] = useState<any>({});
|
||||
const courseid = props.courseid;
|
||||
const [learnings, setLearnings] = useState<any>([]);
|
||||
const courseuuid = props.courseuuid;
|
||||
const orgslug = props.orgslug;
|
||||
const course = props.course;
|
||||
const router = useRouter();
|
||||
|
||||
function getLearningTags() {
|
||||
// create array of learnings from a string object (comma separated)
|
||||
let learnings = course.learnings.split(",");
|
||||
setLearnings(learnings);
|
||||
|
||||
|
||||
async function getUserUI() {
|
||||
let user_id = course.course.authors[0];
|
||||
const user = await getUser(user_id);
|
||||
setUser(user);
|
||||
console.log(user);
|
||||
}
|
||||
|
||||
console.log(course);
|
||||
|
||||
async function startCourseUI() {
|
||||
// Create activity
|
||||
await startCourse("course_" + courseid, orgslug);
|
||||
await startCourse("course_" + courseuuid, orgslug);
|
||||
await revalidateTags(['courses'], orgslug);
|
||||
router.refresh();
|
||||
|
||||
|
|
@ -39,17 +40,23 @@ const CourseClient = (props: any) => {
|
|||
// window.location.reload();
|
||||
}
|
||||
|
||||
function isCourseStarted() {
|
||||
const runs = course.trail.runs;
|
||||
// checks if one of the obejcts in the array has the property "STATUS_IN_PROGRESS"
|
||||
return runs.some((run: any) => run.status === "STATUS_IN_PROGRESS");
|
||||
}
|
||||
|
||||
async function quitCourse() {
|
||||
// Close activity
|
||||
let activity = await removeCourse("course_" + courseid, orgslug);
|
||||
let activity = await removeCourse("course_" + courseuuid, orgslug);
|
||||
// Mutate course
|
||||
await revalidateTags(['courses'], orgslug);
|
||||
router.refresh();
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
getUserUI();
|
||||
}
|
||||
useEffect(() => {
|
||||
|
||||
}
|
||||
, []);
|
||||
|
||||
return (
|
||||
|
|
@ -61,26 +68,26 @@ const CourseClient = (props: any) => {
|
|||
<div className="pb-3">
|
||||
<p className="text-md font-bold text-gray-400 pb-2">Course</p>
|
||||
<h1 className="text-3xl -mt-3 font-bold">
|
||||
{course.course.name}
|
||||
{course.name}
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
|
||||
<div className="inset-0 ring-1 ring-inset ring-black/10 rounded-lg shadow-xl relative w-auto h-[300px] bg-cover bg-center mb-4" style={{ backgroundImage: `url(${getCourseThumbnailMediaDirectory(course.course.org_id, course.course.course_id, course.course.thumbnail)})` }}>
|
||||
<div className="inset-0 ring-1 ring-inset ring-black/10 rounded-lg shadow-xl relative w-auto h-[300px] bg-cover bg-center mb-4" style={{ backgroundImage: `url(${getCourseThumbnailMediaDirectory(course.org_id, course.course_uuid, course.thumbnail)})` }}>
|
||||
</div>
|
||||
|
||||
<ActivityIndicators course_id={props.course.course.course_id} orgslug={orgslug} course={course} />
|
||||
<ActivityIndicators course_uuid={props.course.course_uuid} orgslug={orgslug} course={course} />
|
||||
|
||||
<div className="flex flex-row pt-10">
|
||||
<div className="course_metadata_left grow space-y-2">
|
||||
<h2 className="py-3 text-2xl font-bold">Description</h2>
|
||||
<div className="bg-white shadow-md shadow-gray-300/25 outline outline-1 outline-neutral-200/40 rounded-lg overflow-hidden">
|
||||
<p className="py-5 px-5">{course.course.description}</p>
|
||||
<p className="py-5 px-5">{course.description}</p>
|
||||
</div>
|
||||
|
||||
<h2 className="py-3 text-2xl font-bold">What you will learn</h2>
|
||||
<div className="bg-white shadow-md shadow-gray-300/25 outline outline-1 outline-neutral-200/40 rounded-lg overflow-hidden px-5 py-5 space-y-2">
|
||||
{course.course.learnings.map((learning: any) => {
|
||||
{learnings.map((learning: any) => {
|
||||
return (
|
||||
<div key={learning}
|
||||
className="flex space-x-2 items-center font-semibold text-gray-500 capitalize">
|
||||
|
|
@ -118,48 +125,48 @@ const CourseClient = (props: any) => {
|
|||
</p>
|
||||
<div className="flex space-x-1 py-2 px-4 items-center">
|
||||
<div className="courseicon items-center flex space-x-2 text-neutral-400">
|
||||
{activity.type === "dynamic" &&
|
||||
{activity.activity_type === "TYPE_DYNAMIC" &&
|
||||
<div className="bg-gray-100 px-2 py-2 rounded-full">
|
||||
<Sparkles className="text-gray-400" size={13} />
|
||||
</div>
|
||||
}
|
||||
{activity.type === "video" &&
|
||||
{activity.activity_type === "TYPE_VIDEO" &&
|
||||
<div className="bg-gray-100 px-2 py-2 rounded-full">
|
||||
<Video className="text-gray-400" size={13} />
|
||||
</div>
|
||||
}
|
||||
{activity.type === "documentpdf" &&
|
||||
{activity.activity_type === "TYPE_DOCUMENT" &&
|
||||
<div className="bg-gray-100 px-2 py-2 rounded-full">
|
||||
<File className="text-gray-400" size={13} />
|
||||
</div>
|
||||
}
|
||||
|
||||
</div>
|
||||
<Link className="flex font-semibold grow pl-2 text-neutral-500" href={getUriWithOrg(orgslug, "") + `/course/${courseid}/activity/${activity.id.replace("activity_", "")}`} rel="noopener noreferrer">
|
||||
<Link className="flex font-semibold grow pl-2 text-neutral-500" href={getUriWithOrg(orgslug, "") + `/course/${courseuuid}/activity/${activity.activity_uuid.replace("activity_", "")}`} rel="noopener noreferrer">
|
||||
<p>{activity.name}</p>
|
||||
</Link>
|
||||
<div className="flex ">
|
||||
{activity.type === "dynamic" &&
|
||||
{activity.activity_type === "TYPE_DYNAMIC" &&
|
||||
<>
|
||||
<Link className="flex grow pl-2 text-gray-500" href={getUriWithOrg(orgslug, "") + `/course/${courseid}/activity/${activity.id.replace("activity_", "")}`} rel="noopener noreferrer">
|
||||
<Link className="flex grow pl-2 text-gray-500" href={getUriWithOrg(orgslug, "") + `/course/${courseuuid}/activity/${activity.activity_uuid.replace("activity_", "")}`} rel="noopener noreferrer">
|
||||
<div className="text-xs bg-gray-100 text-gray-400 font-bold px-2 py-1 rounded-full flex space-x-1 items-center">
|
||||
<p>Page</p>
|
||||
<ArrowRight size={13} /></div>
|
||||
</Link>
|
||||
</>
|
||||
}
|
||||
{activity.type === "video" &&
|
||||
{activity.activity_type === "TYPE_VIDEO" &&
|
||||
<>
|
||||
<Link className="flex grow pl-2 text-gray-500" href={getUriWithOrg(orgslug, "") + `/course/${courseid}/activity/${activity.id.replace("activity_", "")}`} rel="noopener noreferrer">
|
||||
<Link className="flex grow pl-2 text-gray-500" href={getUriWithOrg(orgslug, "") + `/course/${courseuuid}/activity/${activity.activity_uuid.replace("activity_", "")}`} rel="noopener noreferrer">
|
||||
<div className="text-xs bg-gray-100 text-gray-400 font-bold px-2 py-1 rounded-full flex space-x-1 items-center">
|
||||
<p>Video</p>
|
||||
<ArrowRight size={13} /></div>
|
||||
</Link>
|
||||
</>
|
||||
}
|
||||
{activity.type === "documentpdf" &&
|
||||
{activity.activity_type === "TYPE_DOCUMENT" &&
|
||||
<>
|
||||
<Link className="flex grow pl-2 text-gray-500" href={getUriWithOrg(orgslug, "") + `/course/${courseid}/activity/${activity.id.replace("activity_", "")}`} rel="noopener noreferrer">
|
||||
<Link className="flex grow pl-2 text-gray-500" href={getUriWithOrg(orgslug, "") + `/course/${courseuuid}/activity/${activity.activity_uuid.replace("activity_", "")}`} rel="noopener noreferrer">
|
||||
<div className="text-xs bg-gray-100 text-gray-400 font-bold px-2 py-1 rounded-full flex space-x-1 items-center">
|
||||
<p>Document</p>
|
||||
<ArrowRight size={13} /></div>
|
||||
|
|
@ -178,19 +185,20 @@ const CourseClient = (props: any) => {
|
|||
|
||||
</div>
|
||||
<div className="course_metadata_right space-y-3 w-64 antialiased flex flex-col ml-10 h-fit p-3 py-5 bg-white shadow-md shadow-gray-300/25 outline outline-1 outline-neutral-200/40 rounded-lg overflow-hidden">
|
||||
{ user &&
|
||||
{user &&
|
||||
<div className="flex mx-auto space-x-3 px-2 py-2 items-center">
|
||||
<div className="">
|
||||
<Avvvatars border borderSize={5} borderColor="white" size={50} shadow value={course.course.authors[0]} style='shape' />
|
||||
<div className="">
|
||||
<Avvvatars border borderSize={5} borderColor="white" size={50} shadow value={course.authors[0].username} style='shape' />
|
||||
</div>
|
||||
<div className="-space-y-2 ">
|
||||
<div className="text-[12px] text-neutral-400 font-semibold">Author</div>
|
||||
<div className="text-xl font-bold text-neutral-800">{course.authors[0].first_name} {course.authors[0].last_name}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="-space-y-2 ">
|
||||
<div className="text-[12px] text-neutral-400 font-semibold">Author</div>
|
||||
<div className="text-xl font-bold text-neutral-800">{user.full_name}</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
{console.log(course)}
|
||||
|
||||
{course.trail.status == "ongoing" ? (
|
||||
{isCourseStarted() ? (
|
||||
<button className="py-2 px-5 mx-auto rounded-xl text-white font-bold h-12 w-[200px] drop-shadow-md bg-red-600 hover:bg-red-700 hover:cursor-pointer" onClick={quitCourse}>
|
||||
Quit Course
|
||||
</button>
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
"use client";
|
||||
import React, { FC, use, useEffect, useReducer } from 'react'
|
||||
import React, { FC, useEffect, useReducer } from 'react'
|
||||
import { revalidateTags, swrFetcher } from "@services/utils/ts/requests";
|
||||
import { getAPIUrl, getUriWithOrg } from '@services/config/config';
|
||||
import useSWR, { mutate } from 'swr';
|
||||
|
|
@ -14,15 +14,40 @@ import Loading from '../../loading';
|
|||
import { updateCourse } from '@services/courses/courses';
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
function CourseEditClient({ courseid, subpage, params }: { courseid: string, subpage: string, params: any }) {
|
||||
const { data: chapters_meta, error: chapters_meta_error, isLoading: chapters_meta_isloading } = useSWR(`${getAPIUrl()}chapters/meta/course_${courseid}`, swrFetcher);
|
||||
const { data: course, error: course_error, isLoading: course_isloading } = useSWR(`${getAPIUrl()}courses/course_${courseid}`, swrFetcher);
|
||||
function CourseEditClient({ courseuuid, courseid, subpage, params }: { courseid: any, courseuuid: string, subpage: string, params: any }) {
|
||||
const { data: chapters_meta, error: chapters_meta_error, isLoading: chapters_meta_isloading } = useSWR(`${getAPIUrl()}chapters/course/course_${courseuuid}/meta`, swrFetcher);
|
||||
const { data: course, error: course_error, isLoading: course_isloading } = useSWR(`${getAPIUrl()}courses/course_${courseuuid}/meta`, swrFetcher);
|
||||
const [courseChaptersMetadata, dispatchCourseChaptersMetadata] = useReducer(courseChaptersReducer, {});
|
||||
const [courseState, dispatchCourseMetadata] = useReducer(courseReducer, {});
|
||||
const [savedContent, dispatchSavedContent] = useReducer(savedContentReducer, true);
|
||||
const router = useRouter();
|
||||
|
||||
|
||||
// This function is a quick fix to transform the payload object from what was used before to the new and improved format
|
||||
// The entire course edition frontend code will be remade in the future in a proper way.
|
||||
const ConvertToNewAPIOrderUpdatePayload = (courseChaptersMetadata: any) => {
|
||||
const old_format = courseChaptersMetadata
|
||||
console.log()
|
||||
|
||||
// Convert originalObject to the desired format
|
||||
const convertedObject = {
|
||||
"chapter_order_by_ids": old_format.chapterOrder.map((chapterId: string | number, chapterIndex: any) => {
|
||||
const chapter = old_format.chapters[chapterId];
|
||||
return {
|
||||
"chapter_id": chapter.id,
|
||||
"activities_order_by_ids": chapter.activityIds.map((activityId: any, activityIndex: any) => {
|
||||
return {
|
||||
"activity_id": activityIndex
|
||||
};
|
||||
})
|
||||
};
|
||||
})
|
||||
};
|
||||
|
||||
return convertedObject
|
||||
}
|
||||
|
||||
|
||||
|
||||
function courseChaptersReducer(state: any, action: any) {
|
||||
switch (action.type) {
|
||||
|
|
@ -57,22 +82,25 @@ function CourseEditClient({ courseid, subpage, params }: { courseid: string, sub
|
|||
|
||||
async function saveCourse() {
|
||||
if (subpage.toString() === 'content') {
|
||||
await updateChaptersMetadata(courseid, courseChaptersMetadata)
|
||||
let payload = ConvertToNewAPIOrderUpdatePayload(courseChaptersMetadata)
|
||||
await updateChaptersMetadata(courseuuid, payload)
|
||||
dispatchSavedContent({ type: 'saved_content' })
|
||||
await mutate(`${getAPIUrl()}chapters/meta/course_${courseid}`)
|
||||
await mutate(`${getAPIUrl()}chapters/course/course_${courseuuid}/meta`)
|
||||
await revalidateTags(['courses'], params.params.orgslug)
|
||||
router.refresh()
|
||||
}
|
||||
else if (subpage.toString() === 'general') {
|
||||
await updateCourse(courseid, courseState)
|
||||
await updateCourse(courseuuid, courseState)
|
||||
dispatchSavedContent({ type: 'saved_content' })
|
||||
await mutate(`${getAPIUrl()}courses/course_${courseid}`)
|
||||
await mutate(`${getAPIUrl()}courses/course_${courseuuid}`)
|
||||
await mutate(`${getAPIUrl()}chapters/course/course_${courseuuid}/meta`)
|
||||
await revalidateTags(['courses'], params.params.orgslug)
|
||||
router.refresh()
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
if (chapters_meta) {
|
||||
dispatchCourseChaptersMetadata({ type: 'updated_chapter', payload: chapters_meta })
|
||||
dispatchSavedContent({ type: 'saved_content' })
|
||||
|
|
@ -91,8 +119,8 @@ function CourseEditClient({ courseid, subpage, params }: { courseid: string, sub
|
|||
{course && <>
|
||||
<div className='flex items-center'><div className='info flex space-x-5 items-center grow'>
|
||||
<div className='flex'>
|
||||
<Link href={getUriWithOrg(params.params.orgslug, "") + `/course/${courseid}`}>
|
||||
<img className="w-[100px] h-[57px] rounded-md drop-shadow-md" src={`${getCourseThumbnailMediaDirectory(course.org_id, "course_" + courseid, course.thumbnail)}`} alt="" />
|
||||
<Link href={getUriWithOrg(params.params.orgslug, "") + `/course/${courseuuid}`}>
|
||||
<img className="w-[100px] h-[57px] rounded-md drop-shadow-md" src={`${getCourseThumbnailMediaDirectory(course.org_id, "course_" + courseuuid, course.thumbnail)}`} alt="" />
|
||||
</Link>
|
||||
</div>
|
||||
<div className="flex flex-col ">
|
||||
|
|
@ -118,27 +146,28 @@ function CourseEditClient({ courseid, subpage, params }: { courseid: string, sub
|
|||
</div>
|
||||
</>}
|
||||
<div className='flex space-x-5 pt-3 font-black text-sm'>
|
||||
<Link href={getUriWithOrg(params.params.orgslug, "") + `/course/${courseid}/edit/general`}>
|
||||
<Link href={getUriWithOrg(params.params.orgslug, "") + `/course/${courseuuid}/edit/general`}>
|
||||
<div className={`py-2 w-16 text-center border-black transition-all ease-linear ${subpage.toString() === 'general' ? 'border-b-4' : 'opacity-50'} cursor-pointer`}>General</div>
|
||||
</Link>
|
||||
<Link href={getUriWithOrg(params.params.orgslug, "") + `/course/${courseid}/edit/content`}>
|
||||
<Link href={getUriWithOrg(params.params.orgslug, "") + `/course/${courseuuid}/edit/content`}>
|
||||
<div className={`py-2 w-16 text-center border-black transition-all ease-linear ${subpage.toString() === 'content' ? 'border-b-4' : 'opacity-50'} cursor-pointer`}>Content</div>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<CoursePageViewer dispatchSavedContent={dispatchSavedContent} courseState={courseState} courseChaptersMetadata={courseChaptersMetadata} dispatchCourseMetadata={dispatchCourseMetadata} dispatchCourseChaptersMetadata={dispatchCourseChaptersMetadata} subpage={subpage} courseid={courseid} orgslug={params.params.orgslug} />
|
||||
<CoursePageViewer course={course} dispatchSavedContent={dispatchSavedContent} courseState={courseState} courseChaptersMetadata={courseChaptersMetadata} dispatchCourseMetadata={dispatchCourseMetadata} dispatchCourseChaptersMetadata={dispatchCourseChaptersMetadata} subpage={subpage} courseuuid={courseuuid} orgslug={params.params.orgslug} />
|
||||
</>
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
const CoursePageViewer = ({ subpage, courseid, orgslug, dispatchCourseMetadata, dispatchCourseChaptersMetadata, courseChaptersMetadata, dispatchSavedContent, courseState }: { subpage: string, courseid: string, orgslug: string, dispatchCourseChaptersMetadata: React.Dispatch<any>, dispatchCourseMetadata: React.Dispatch<any>, dispatchSavedContent: React.Dispatch<any>, courseChaptersMetadata: any, courseState: any }) => {
|
||||
if (subpage.toString() === 'general' && Object.keys(courseState).length !== 0) {
|
||||
return <CourseEdition data={courseState} dispatchCourseMetadata={dispatchCourseMetadata} dispatchSavedContent={dispatchSavedContent} />
|
||||
const CoursePageViewer = ({ subpage, course, orgslug, dispatchCourseMetadata, dispatchCourseChaptersMetadata, courseChaptersMetadata, dispatchSavedContent, courseState }: { subpage: string, courseuuid: string, orgslug: string, dispatchCourseChaptersMetadata: React.Dispatch<any>, dispatchCourseMetadata: React.Dispatch<any>, dispatchSavedContent: React.Dispatch<any>, courseChaptersMetadata: any, courseState: any, course: any }) => {
|
||||
|
||||
if (subpage.toString() === 'general' && Object.keys(courseState).length !== 0 && course) {
|
||||
return <CourseEdition course={course} orgslug={orgslug} course_chapters_with_orders_and_activities={courseState} dispatchCourseMetadata={dispatchCourseMetadata} dispatchSavedContent={dispatchSavedContent} />
|
||||
}
|
||||
else if (subpage.toString() === 'content' && Object.keys(courseChaptersMetadata).length !== 0) {
|
||||
return <CourseContentEdition data={courseChaptersMetadata} dispatchSavedContent={dispatchSavedContent} dispatchCourseChaptersMetadata={dispatchCourseChaptersMetadata} courseid={courseid} orgslug={orgslug} />
|
||||
else if (subpage.toString() === 'content' && Object.keys(courseChaptersMetadata).length !== 0 && course) {
|
||||
return <CourseContentEdition course={course} orgslug={orgslug} course_chapters_with_orders_and_activities={courseChaptersMetadata} dispatchSavedContent={dispatchSavedContent} dispatchCourseChaptersMetadata={dispatchCourseChaptersMetadata} />
|
||||
}
|
||||
else if (subpage.toString() === 'content' || subpage.toString() === 'general') {
|
||||
return <Loading />
|
||||
|
|
@ -6,7 +6,7 @@ import { Metadata } from 'next';
|
|||
import { getAccessTokenFromRefreshTokenCookie, getNewAccessTokenUsingRefreshTokenServer } from "@services/auth/auth";
|
||||
|
||||
type MetadataProps = {
|
||||
params: { orgslug: string, courseid: string };
|
||||
params: { orgslug: string, courseuuid: string };
|
||||
searchParams: { [key: string]: string | string[] | undefined };
|
||||
};
|
||||
|
||||
|
|
@ -19,20 +19,23 @@ export async function generateMetadata(
|
|||
|
||||
// Get Org context information
|
||||
const org = await getOrganizationContextInfo(params.orgslug, { revalidate: 1800, tags: ['organizations'] });
|
||||
const course_meta = await getCourseMetadataWithAuthHeader(params.courseid, { revalidate: 0, tags: ['courses'] }, access_token ? access_token : null)
|
||||
const course_meta = await getCourseMetadataWithAuthHeader(params.courseuuid, { revalidate: 0, tags: ['courses'] }, access_token ? access_token : null)
|
||||
|
||||
return {
|
||||
title: `Edit Course - ` + course_meta.course.name,
|
||||
description: course_meta.course.mini_description,
|
||||
title: `Edit Course - ` + course_meta.name,
|
||||
description: course_meta.mini_description,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function CourseEdit(params: any) {
|
||||
async function CourseEdit(params: any) {
|
||||
const cookieStore = cookies();
|
||||
const access_token = await getAccessTokenFromRefreshTokenCookie(cookieStore)
|
||||
let subpage = params.params.subpage ? params.params.subpage : 'general';
|
||||
const course_meta = await getCourseMetadataWithAuthHeader(params.params.courseuuid, { revalidate: 0, tags: ['courses'] }, access_token ? access_token : null)
|
||||
return (
|
||||
<>
|
||||
<CourseEditClient params={params} subpage={subpage} courseid={params.params.courseid} />
|
||||
<CourseEditClient params={params} subpage={subpage} courseid={course_meta.id} courseuuid={params.params.courseuuid} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
@ -14,40 +14,43 @@ import { denyAccessToUser } from "@services/utils/react/middlewares/views";
|
|||
import { Folders, Hexagon, SaveIcon } from "lucide-react";
|
||||
import GeneralWrapperStyled from "@components/StyledElements/Wrappers/GeneralWrapper";
|
||||
import { revalidateTags, swrFetcher } from "@services/utils/ts/requests";
|
||||
import { mutate } from "swr";
|
||||
import { getAPIUrl } from "@services/config/config";
|
||||
import { mutate } from "swr";
|
||||
|
||||
function CourseContentEdition(props: any) {
|
||||
const router = useRouter();
|
||||
// Initial Course State
|
||||
const data = props.data;
|
||||
// Initial Course Chapters State
|
||||
const course_chapters_with_orders_and_activities = props.course_chapters_with_orders_and_activities;
|
||||
|
||||
// New Chapter Modal State
|
||||
const [newChapterModal, setNewChapterModal] = useState(false) as any;
|
||||
// New Activity Modal State
|
||||
const [newActivityModal, setNewActivityModal] = useState(false) as any;
|
||||
const [newActivityModalData, setNewActivityModalData] = useState("") as any;
|
||||
const [selectedChapterToAddActivityTo, setSelectedChapterToAddActivityTo] = useState("") as any;
|
||||
|
||||
// Check window availability
|
||||
const [winReady, setwinReady] = useState(false);
|
||||
const courseid = props.courseid;
|
||||
const course = props.course;
|
||||
const course_uuid = props.course ? props.course.course_uuid : ''
|
||||
const orgslug = props.orgslug;
|
||||
|
||||
//
|
||||
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
setwinReady(true);
|
||||
}, [courseid, orgslug]);
|
||||
}, [course_uuid, orgslug]);
|
||||
|
||||
// get a list of chapters order by chapter order
|
||||
const getChapters = () => {
|
||||
const chapterOrder = data.chapterOrder ? data.chapterOrder : [];
|
||||
const chapterOrder = course_chapters_with_orders_and_activities.chapterOrder ? course_chapters_with_orders_and_activities.chapterOrder : [];
|
||||
return chapterOrder.map((chapterId: any) => {
|
||||
const chapter = data.chapters[chapterId];
|
||||
const chapter = course_chapters_with_orders_and_activities.chapters[chapterId];
|
||||
let activities = [];
|
||||
if (data.activities) {
|
||||
activities = chapter.activityIds.map((activityId: any) => data.activities[activityId])
|
||||
? chapter.activityIds.map((activityId: any) => data.activities[activityId])
|
||||
if (course_chapters_with_orders_and_activities.activities) {
|
||||
activities = chapter.activityIds.map((activityId: any) => course_chapters_with_orders_and_activities.activities[activityId])
|
||||
? chapter.activityIds.map((activityId: any) => course_chapters_with_orders_and_activities.activities[activityId])
|
||||
: [];
|
||||
}
|
||||
return {
|
||||
|
|
@ -61,9 +64,9 @@ function CourseContentEdition(props: any) {
|
|||
|
||||
// Submit new chapter
|
||||
const submitChapter = async (chapter: any) => {
|
||||
await createChapter(chapter, courseid);
|
||||
mutate(`${getAPIUrl()}chapters/meta/course_${courseid}`);
|
||||
// await getCourseChapters();
|
||||
await createChapter(chapter);
|
||||
|
||||
mutate(`${getAPIUrl()}chapters/course/${course_uuid}/meta`,true);
|
||||
await revalidateTags(['courses'], orgslug);
|
||||
router.refresh();
|
||||
setNewChapterModal(false);
|
||||
|
|
@ -72,22 +75,21 @@ function CourseContentEdition(props: any) {
|
|||
// Submit new activity
|
||||
const submitActivity = async (activity: any) => {
|
||||
let org = await getOrganizationContextInfoWithoutCredentials(orgslug, { revalidate: 1800 });
|
||||
await updateChaptersMetadata(courseid, data);
|
||||
await createActivity(activity, activity.chapterId, org.org_id);
|
||||
mutate(`${getAPIUrl()}chapters/meta/course_${courseid}`);
|
||||
mutate(`${getAPIUrl()}chapters/course/${course_uuid}/meta`);
|
||||
// await getCourseChapters();
|
||||
setNewActivityModal(false);
|
||||
await revalidateTags(['courses'], orgslug);
|
||||
router.refresh();
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// Submit File Upload
|
||||
const submitFileActivity = async (file: any, type: any, activity: any, chapterId: string) => {
|
||||
await updateChaptersMetadata(courseid, data);
|
||||
//await updateChaptersMetadata(course_uuid, course_chapters_with_orders_and_activities);
|
||||
await createFileActivity(file, type, activity, chapterId);
|
||||
mutate(`${getAPIUrl()}chapters/meta/course_${courseid}`);
|
||||
mutate(`${getAPIUrl()}chapters/course/${course_uuid}/meta`);
|
||||
// await getCourseChapters();
|
||||
setNewActivityModal(false);
|
||||
await revalidateTags(['courses'], orgslug);
|
||||
|
|
@ -96,9 +98,9 @@ function CourseContentEdition(props: any) {
|
|||
|
||||
// Submit YouTube Video Upload
|
||||
const submitExternalVideo = async (external_video_data: any, activity: any, chapterId: string) => {
|
||||
await updateChaptersMetadata(courseid, data);
|
||||
//await updateChaptersMetadata(course_uuid, course_chapters_with_orders_and_activities);
|
||||
await createExternalVideoActivity(external_video_data, activity, chapterId);
|
||||
mutate(`${getAPIUrl()}chapters/meta/course_${courseid}`);
|
||||
mutate(`${getAPIUrl()}chapters/course/${course_uuid}/meta`);
|
||||
// await getCourseChapters();
|
||||
setNewActivityModal(false);
|
||||
await revalidateTags(['courses'], orgslug);
|
||||
|
|
@ -106,19 +108,15 @@ function CourseContentEdition(props: any) {
|
|||
};
|
||||
|
||||
const deleteChapterUI = async (chapterId: any) => {
|
||||
|
||||
await deleteChapter(chapterId);
|
||||
mutate(`${getAPIUrl()}chapters/meta/course_${courseid}`);
|
||||
|
||||
mutate(`${getAPIUrl()}chapters/course/${course_uuid}/meta`,true);
|
||||
// await getCourseChapters();
|
||||
await revalidateTags(['courses'], orgslug);
|
||||
router.refresh();
|
||||
};
|
||||
|
||||
const updateChapters = () => {
|
||||
updateChaptersMetadata(courseid, data);
|
||||
revalidateTags(['courses'], orgslug);
|
||||
router.refresh();
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Modals
|
||||
|
|
@ -126,7 +124,7 @@ function CourseContentEdition(props: any) {
|
|||
|
||||
const openNewActivityModal = async (chapterId: any) => {
|
||||
setNewActivityModal(true);
|
||||
setNewActivityModalData(chapterId);
|
||||
setSelectedChapterToAddActivityTo(chapterId);
|
||||
};
|
||||
|
||||
// Close new chapter modal
|
||||
|
|
@ -157,12 +155,12 @@ function CourseContentEdition(props: any) {
|
|||
}
|
||||
//////////////////////////// CHAPTERS ////////////////////////////
|
||||
if (type === "chapter") {
|
||||
const newChapterOrder = Array.from(data.chapterOrder);
|
||||
const newChapterOrder = Array.from(course_chapters_with_orders_and_activities.chapterOrder);
|
||||
newChapterOrder.splice(source.index, 1);
|
||||
newChapterOrder.splice(destination.index, 0, draggableId);
|
||||
|
||||
const newState = {
|
||||
...data,
|
||||
...course_chapters_with_orders_and_activities,
|
||||
chapterOrder: newChapterOrder,
|
||||
};
|
||||
|
||||
|
|
@ -174,13 +172,13 @@ function CourseContentEdition(props: any) {
|
|||
|
||||
//////////////////////// ACTIVITIES IN SAME CHAPTERS ////////////////////////////
|
||||
// check if the activity is dropped in the same chapter
|
||||
const start = data.chapters[source.droppableId];
|
||||
const finish = data.chapters[destination.droppableId];
|
||||
const start = course_chapters_with_orders_and_activities.chapters[source.droppableId];
|
||||
const finish = course_chapters_with_orders_and_activities.chapters[destination.droppableId];
|
||||
|
||||
// check if the activity is dropped in the same chapter
|
||||
if (start === finish) {
|
||||
// create new arrays for chapters and activities
|
||||
const chapter = data.chapters[source.droppableId];
|
||||
const chapter = course_chapters_with_orders_and_activities.chapters[source.droppableId];
|
||||
const newActivityIds = Array.from(chapter.activityIds);
|
||||
|
||||
// remove the activity from the old position
|
||||
|
|
@ -195,9 +193,9 @@ function CourseContentEdition(props: any) {
|
|||
};
|
||||
|
||||
const newState = {
|
||||
...data,
|
||||
...course_chapters_with_orders_and_activities,
|
||||
chapters: {
|
||||
...data.chapters,
|
||||
...course_chapters_with_orders_and_activities.chapters,
|
||||
[newChapter.id]: newChapter,
|
||||
},
|
||||
};
|
||||
|
|
@ -229,9 +227,9 @@ function CourseContentEdition(props: any) {
|
|||
};
|
||||
|
||||
const newState = {
|
||||
...data,
|
||||
...course_chapters_with_orders_and_activities,
|
||||
chapters: {
|
||||
...data.chapters,
|
||||
...course_chapters_with_orders_and_activities.chapters,
|
||||
[newStart.id]: newStart,
|
||||
[newFinish.id]: newFinish,
|
||||
},
|
||||
|
|
@ -259,7 +257,8 @@ function CourseContentEdition(props: any) {
|
|||
submitFileActivity={submitFileActivity}
|
||||
submitExternalVideo={submitExternalVideo}
|
||||
submitActivity={submitActivity}
|
||||
chapterId={newActivityModalData}
|
||||
chapterId={selectedChapterToAddActivityTo}
|
||||
course={course}
|
||||
></NewActivityModal>}
|
||||
dialogTitle="Create Activity"
|
||||
dialogDescription="Choose between types of activities to add to the course"
|
||||
|
|
@ -276,7 +275,7 @@ function CourseContentEdition(props: any) {
|
|||
<>
|
||||
<Chapter
|
||||
orgslug={orgslug}
|
||||
courseid={courseid}
|
||||
course_uuid={course_uuid}
|
||||
openNewActivityModal={openNewActivityModal}
|
||||
deleteChapter={deleteChapterUI}
|
||||
key={index}
|
||||
|
|
@ -296,6 +295,7 @@ function CourseContentEdition(props: any) {
|
|||
onOpenChange={setNewChapterModal}
|
||||
minHeight="sm"
|
||||
dialogContent={<NewChapterModal
|
||||
course={props.course ? props.course : null}
|
||||
closeModal={closeNewChapterModal}
|
||||
submitChapter={submitChapter}
|
||||
></NewChapterModal>}
|
||||
|
|
@ -45,10 +45,10 @@ function CourseEdition(props: any) {
|
|||
const [error, setError] = React.useState('');
|
||||
const formik = useFormik({
|
||||
initialValues: {
|
||||
name: String(props.data.name),
|
||||
mini_description: String(props.data.mini_description),
|
||||
description: String(props.data.description),
|
||||
learnings: String(props.data.learnings),
|
||||
name: String(props.course_chapters_with_orders_and_activities.name),
|
||||
mini_description: String(props.course_chapters_with_orders_and_activities.mini_description),
|
||||
description: String(props.course_chapters_with_orders_and_activities.description),
|
||||
learnings: String(props.course_chapters_with_orders_and_activities.learnings),
|
||||
},
|
||||
validate,
|
||||
onSubmit: async values => {
|
||||
|
|
@ -61,11 +61,10 @@ function CourseEdition(props: any) {
|
|||
if (formik.values !== formik.initialValues) {
|
||||
props.dispatchSavedContent({ type: 'unsaved_content' });
|
||||
const updatedCourse = {
|
||||
...props.data,
|
||||
...props.course_chapters_with_orders_and_activities,
|
||||
name: formik.values.name,
|
||||
mini_description: formik.values.mini_description,
|
||||
description: formik.values.description,
|
||||
learnings: formik.values.learnings.split(", "),
|
||||
learnings: formik.values.learnings,
|
||||
};
|
||||
props.dispatchCourseMetadata({ type: 'updated_course', payload: updatedCourse });
|
||||
}
|
||||
|
|
@ -88,12 +87,7 @@ function CourseEdition(props: any) {
|
|||
<Input style={{ backgroundColor: "white" }} onChange={formik.handleChange} value={formik.values.name} type="text" required />
|
||||
</Form.Control>
|
||||
</FormField>
|
||||
<FormField name="mini_description">
|
||||
<FormLabelAndMessage label='Mini description' message={formik.errors.mini_description} />
|
||||
<Form.Control asChild>
|
||||
<Input style={{ backgroundColor: "white" }} onChange={formik.handleChange} value={formik.values.mini_description} type="text" required />
|
||||
</Form.Control>
|
||||
</FormField>
|
||||
|
||||
<FormField name="description">
|
||||
<FormLabelAndMessage label='Description' message={formik.errors.description} />
|
||||
<Form.Control asChild>
|
||||
|
|
@ -7,7 +7,7 @@ import { Metadata } from 'next';
|
|||
import { getAccessTokenFromRefreshTokenCookie, getNewAccessTokenUsingRefreshTokenServer } from '@services/auth/auth';
|
||||
|
||||
type MetadataProps = {
|
||||
params: { orgslug: string, courseid: string };
|
||||
params: { orgslug: string, courseuuid: string };
|
||||
searchParams: { [key: string]: string | string[] | undefined };
|
||||
};
|
||||
|
||||
|
|
@ -19,14 +19,14 @@ export async function generateMetadata(
|
|||
|
||||
// Get Org context information
|
||||
const org = await getOrganizationContextInfo(params.orgslug, { revalidate: 1800, tags: ['organizations'] });
|
||||
const course_meta = await getCourseMetadataWithAuthHeader(params.courseid, { revalidate: 0, tags: ['courses'] }, access_token ? access_token : null)
|
||||
const course_meta = await getCourseMetadataWithAuthHeader(params.courseuuid, { revalidate: 0, tags: ['courses'] }, access_token ? access_token : null)
|
||||
|
||||
|
||||
// SEO
|
||||
return {
|
||||
title: course_meta.course.name + ` — ${org.name}`,
|
||||
description: course_meta.course.mini_description,
|
||||
keywords: course_meta.course.learnings,
|
||||
title: course_meta.name + ` — ${org.name}`,
|
||||
description: course_meta.description,
|
||||
keywords: course_meta.learnings,
|
||||
robots: {
|
||||
index: true,
|
||||
follow: true,
|
||||
|
|
@ -38,11 +38,11 @@ export async function generateMetadata(
|
|||
}
|
||||
},
|
||||
openGraph: {
|
||||
title: course_meta.course.name + ` — ${org.name}`,
|
||||
description: course_meta.course.mini_description,
|
||||
title: course_meta.name + ` — ${org.name}`,
|
||||
description: course_meta.description,
|
||||
type: 'article',
|
||||
publishedTime: course_meta.course.creationDate,
|
||||
tags: course_meta.course.learnings,
|
||||
publishedTime: course_meta.creation_date,
|
||||
tags: course_meta.learnings,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
@ -50,14 +50,14 @@ export async function generateMetadata(
|
|||
|
||||
const CoursePage = async (params: any) => {
|
||||
const cookieStore = cookies();
|
||||
const courseid = params.params.courseid
|
||||
const courseuuid = params.params.courseuuid
|
||||
const orgslug = params.params.orgslug;
|
||||
const access_token = await getAccessTokenFromRefreshTokenCookie(cookieStore)
|
||||
const course_meta = await getCourseMetadataWithAuthHeader(courseid, { revalidate: 0, tags: ['courses'] }, access_token ? access_token : null)
|
||||
const course_meta = await getCourseMetadataWithAuthHeader(courseuuid, { revalidate: 0, tags: ['courses'] }, access_token ? access_token : null)
|
||||
|
||||
return (
|
||||
<div>
|
||||
<CourseClient courseid={courseid} orgslug={orgslug} course={course_meta} />
|
||||
<CourseClient courseuuid={courseuuid} orgslug={orgslug} course={course_meta} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -32,7 +32,10 @@ function Courses(props: CourseProps) {
|
|||
|
||||
<div className='flex flex-wrap justify-between'>
|
||||
<TypeOfContentTitle title="Courses" type="cou" />
|
||||
<AuthenticatedClientElement checkMethod='roles' orgId={props.org_id}>
|
||||
<AuthenticatedClientElement checkMethod='roles'
|
||||
action='create'
|
||||
ressourceType='course'
|
||||
orgId={props.org_id}>
|
||||
<Modal
|
||||
isDialogOpen={newCourseModal}
|
||||
onOpenChange={setNewCourseModal}
|
||||
|
|
@ -56,7 +59,7 @@ function Courses(props: CourseProps) {
|
|||
|
||||
<div className="flex flex-wrap">
|
||||
{courses.map((course: any) => (
|
||||
<div className="px-3" key={course.course_id}>
|
||||
<div className="px-3" key={course.course_uuid}>
|
||||
<CourseThumbnail course={course} orgslug={orgslug} />
|
||||
</div>
|
||||
))}
|
||||
|
|
@ -73,7 +76,10 @@ function Courses(props: CourseProps) {
|
|||
<h1 className="text-3xl font-bold text-gray-600">No courses yet</h1>
|
||||
<p className="text-lg text-gray-400">Create a course to add content</p>
|
||||
</div>
|
||||
<AuthenticatedClientElement checkMethod='roles' orgId={props.org_id}>
|
||||
<AuthenticatedClientElement
|
||||
action='create'
|
||||
ressourceType='course'
|
||||
checkMethod='roles' orgId={props.org_id}>
|
||||
<Modal
|
||||
isDialogOpen={newCourseModal}
|
||||
onOpenChange={setNewCourseModal}
|
||||
|
|
|
|||
|
|
@ -56,8 +56,8 @@ const OrgHomePage = async (params: any) => {
|
|||
const access_token = await getAccessTokenFromRefreshTokenCookie(cookieStore)
|
||||
const courses = await getOrgCoursesWithAuthHeader(orgslug, { revalidate: 0, tags: ['courses'] }, access_token ? access_token : null);
|
||||
const org = await getOrganizationContextInfo(orgslug, { revalidate: 1800, tags: ['organizations'] });
|
||||
const org_id = org.org_id;
|
||||
const collections = await getOrgCollectionsWithAuthHeader(org.org_id, access_token ? access_token : null, { revalidate: 0, tags: ['courses'] });
|
||||
const org_id = org.id;
|
||||
const collections = await getOrgCollectionsWithAuthHeader(org.id, access_token ? access_token : null, { revalidate: 0, tags: ['courses'] });
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
|
@ -67,7 +67,11 @@ const OrgHomePage = async (params: any) => {
|
|||
<div className='flex grow'>
|
||||
<TypeOfContentTitle title="Collections" type="col" />
|
||||
</div>
|
||||
<AuthenticatedClientElement checkMethod='roles' orgId={org_id}>
|
||||
<AuthenticatedClientElement
|
||||
checkMethod='roles'
|
||||
ressourceType='collection'
|
||||
action='create'
|
||||
orgId={org_id}>
|
||||
<Link href={getUriWithOrg(orgslug, "/collections/new")}>
|
||||
<NewCollectionButton />
|
||||
</Link>
|
||||
|
|
@ -105,7 +109,11 @@ const OrgHomePage = async (params: any) => {
|
|||
<div className='flex grow'>
|
||||
<TypeOfContentTitle title="Courses" type="cou" />
|
||||
</div>
|
||||
<AuthenticatedClientElement checkMethod='roles' orgId={org_id}>
|
||||
<AuthenticatedClientElement
|
||||
ressourceType='course'
|
||||
action='create'
|
||||
checkMethod='roles'
|
||||
orgId={org_id}>
|
||||
<Link href={getUriWithOrg(orgslug, "/courses?new=true")}>
|
||||
<NewCourseButton />
|
||||
</Link>
|
||||
|
|
@ -113,7 +121,7 @@ const OrgHomePage = async (params: any) => {
|
|||
</div>
|
||||
<div className="home_courses flex flex-wrap">
|
||||
{courses.map((course: any) => (
|
||||
<div className="py-3 px-3" key={course.course_id}>
|
||||
<div className="py-3 px-3" key={course.course_uuid}>
|
||||
<CourseThumbnail course={course} orgslug={orgslug} />
|
||||
</div>
|
||||
))}
|
||||
|
|
|
|||
|
|
@ -8,12 +8,15 @@ import Avvvatars from 'avvvatars-react';
|
|||
import Image from 'next/image';
|
||||
import AuthenticatedClientElement from '@components/Security/AuthenticatedClientElement';
|
||||
import { getOrganizationContextInfo } from '@services/organizations/orgs';
|
||||
import useSWR, { mutate } from "swr";
|
||||
import { getAPIUrl } from '@services/config/config';
|
||||
import { swrFetcher } from '@services/utils/ts/requests';
|
||||
|
||||
async function SettingsLayout({ children, params }: { children: React.ReactNode, params: any }) {
|
||||
function SettingsLayout({ children, params }: { children: React.ReactNode, params: any }) {
|
||||
const auth: any = React.useContext(AuthContext);
|
||||
const orgslug = params.orgslug;
|
||||
|
||||
let org = await getOrganizationContextInfo(orgslug, {});
|
||||
const { data: org, error: error } = useSWR(`${getAPIUrl()}orgs/slug/${orgslug}`, swrFetcher);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
@ -33,7 +36,10 @@ async function SettingsLayout({ children, params }: { children: React.ReactNode,
|
|||
<li><Link href="/settings/account/profile">Profile</Link></li>
|
||||
<li><Link href="/settings/account/passwords">Passwords</Link></li>
|
||||
</ul>
|
||||
<AuthenticatedClientElement checkMethod='roles' orgId={org.org_id} >
|
||||
<AuthenticatedClientElement
|
||||
ressourceType='organization'
|
||||
action='update'
|
||||
checkMethod='roles' >
|
||||
<MenuTitle>Organization</MenuTitle>
|
||||
<ul>
|
||||
<li><Link href="/settings/organization/general">General</Link></li>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue