diff --git a/front/app/orgs/[orgslug]/(withmenu)/course/[courseid]/activity/[activityid]/activity.tsx b/front/app/orgs/[orgslug]/(withmenu)/course/[courseid]/activity/[activityid]/activity.tsx index bf498799..285784c1 100644 --- a/front/app/orgs/[orgslug]/(withmenu)/course/[courseid]/activity/[activityid]/activity.tsx +++ b/front/app/orgs/[orgslug]/(withmenu)/course/[courseid]/activity/[activityid]/activity.tsx @@ -10,6 +10,7 @@ import { Check } from "lucide-react"; import { markActivityAsComplete } from "@services/courses/activity"; import ToolTip from "@components/UI/Tooltip/Tooltip"; import DocumentPdfActivity from "@components/Pages/Activities/DocumentPdf/DocumentPdf"; +import ActivityIndicators from "@components/Pages/Courses/ActivityIndicators"; interface ActivityClientProps { activityid: string; @@ -35,81 +36,60 @@ function ActivityClient(props: ActivityClientProps) { return ( <> - -
{JSON.stringify(activity, null, 2)}
- - - - - - - -

Course

-

{course.course.name}

-
-
- - {course.chapters.map((chapter: any) => { - return ( - <> -
- {chapter.activities.map((activity: any) => { - return ( - - - - - - ); - })} -
-      - - ); - })} -
+
+
{JSON.stringify(activity, null, 2)}
+ + + + + + + +

Course

+

{course.course.name}

+
+
+ - {activity ? ( + {activity ? ( +
- {activity.type == "dynamic" && } - {/* todo : use apis & streams instead of this */} - {activity.type == "video" && } + {activity.type == "dynamic" && } + {/* todo : use apis & streams instead of this */} + {activity.type == "video" && } - {activity.type == "documentpdf" && } + {activity.type == "documentpdf" && } - + - {course.trail.activities_marked_complete && - course.trail.activities_marked_complete.includes("activity_" + activityid) && - course.trail.status == "ongoing" ? ( - - ) : ( - - )} - - - ) : (
)} - {
} - + {course.trail.activities_marked_complete && + course.trail.activities_marked_complete.includes("activity_" + activityid) && + course.trail.status == "ongoing" ? ( + + ) : ( + + )} + + +
+ ) : (
)} + {
} +
); } -const ActivityLayout = styled.div``; const ActivityThumbnail = styled.div` padding-right: 30px; @@ -133,32 +113,8 @@ const ActivityInfo = styled.div` } `; -const ChaptersWrapper = styled.div` - display: flex; - // row - flex-direction: row; - width: 100%; - width: 1300px; - margin: 0 auto; -`; -const ChapterIndicator = styled.div < { active?: boolean, done?: boolean } > ` - border-radius: 20px; - height: 5px; - background: #151515; - border-radius: 3px; - width: 35px; - background-color: ${props => props.done ? "green" : (props.active ? "#9d9d9d" : "black")}; - margin: 10px; - margin-bottom: 0px; - margin-left: 0px; - - &:hover { - cursor: pointer; - background-color: #9d9d9d; - } -`; const ActivityTopWrapper = styled.div` width: 1300px; @@ -171,7 +127,6 @@ const CourseContent = styled.div` display: flex; flex-direction: column; background-color: white; - min-height: 600px; `; const ActivityMarkerWrapper = styled.div` diff --git a/front/app/orgs/[orgslug]/(withmenu)/course/[courseid]/course.tsx b/front/app/orgs/[orgslug]/(withmenu)/course/[courseid]/course.tsx index d88b6ce8..cb29bdcb 100644 --- a/front/app/orgs/[orgslug]/(withmenu)/course/[courseid]/course.tsx +++ b/front/app/orgs/[orgslug]/(withmenu)/course/[courseid]/course.tsx @@ -2,68 +2,74 @@ import { EyeOpenIcon, Pencil2Icon } from "@radix-ui/react-icons"; import { removeCourse, startCourse } from "@services/courses/activity"; import Link from "next/link"; -import React from "react"; +import React, { use } from "react"; import styled from "styled-components"; import { getAPIUrl, getBackendUrl, getUriWithOrg } from "@services/config/config"; import useSWR, { mutate } from "swr"; import ToolTip from "@components/UI/Tooltip/Tooltip"; import PageLoading from "@components/Pages/PageLoading"; import { revalidateTags } from "@services/utils/ts/requests"; +import ActivityIndicators from "@components/Pages/Courses/ActivityIndicators"; +import { useRouter } from "next/navigation"; const CourseClient = (props: any) => { const courseid = props.courseid; const orgslug = props.orgslug; const course = props.course; + const router = useRouter(); async function startCourseUI() { // Create activity await startCourse("course_" + courseid, orgslug); revalidateTags(['courses']); + router.refresh(); } async function quitCourse() { - // Close activity let activity = await removeCourse("course_" + courseid, orgslug); // Mutate course revalidateTags(['courses']); + router.refresh(); } console.log(course); + return ( <> {!course ? ( ) : ( - -

Course

-

- {course.course.name}{" "} - - - {" "} -

+
+
+

Course

+

+ {course.course.name} +

+
- - - - - -

Description

+
- +
+ + + +
+
+

Description

+

{course.course.description}

- +
+ +

What you will learn

+ -

What you will learn

-

{course.learnings == ![] ? "no data" : course.learnings}

-
+
-

Course Lessons

- - +

Course Lessons

+ {course.chapters.map((chapter: any) => { return (
{
); })} -
- - + + +
+
{course.trail.status == "ongoing" ? ( - ) : ( - + )} - - - +
+
+
)} ); }; -const CourseThumbnailWrapper = styled.div` - display: flex; - padding-bottom: 20px; - img { - width: 100%; - height: 300px; - object-fit: cover; - object-position: center; - background: url(), #d9d9d9; - border: 1px solid rgba(255, 255, 255, 0.19); - box-shadow: 0px 13px 33px -13px rgba(0, 0, 0, 0.42); - border-radius: 7px; - } -`; -const CoursePageLayout = styled.div` - width: 1300px; - margin: 0 auto; - p { - margin-bottom: 0px; - letter-spacing: -0.05em; - color: #727272; - font-weight: 700; - } - h1 { - margin-top: 5px; - letter-spacing: -0.05em; - margin-bottom: 10px; - } -`; +const StyledBox = (props: any) => ( +
+ {props.children} +
-const ChaptersWrapper = styled.div` - display: flex; - width: 100%; -`; -const CourseIndicator = styled.div< { active?: boolean, done?: boolean } >` - border-radius: 20px; - height: 5px; - background: #151515; - border-radius: 3px; +); - background-color: ${props => props.done ? "green" : "black"}; - - width: 40px; - margin: 10px; - margin-bottom: 20px; - margin-left: 0px; - - &:hover { - cursor: pointer; - background-color: #9d9d9d; - } -`; - -const ChapterSeparator = styled.div` - display: flex; - flex-direction: row; - padding-right: 7px; -`; - -const BoxWrapper = styled.div` - background: #ffffff; - box-shadow: 0px 4px 16px rgba(0, 0, 0, 0.03); - border-radius: 7px; - padding: 20px; - padding-top: 7px; - padding-left: 30px; - - p { - font-family: "DM Sans"; - font-style: normal; - font-weight: 500; - line-height: 16px; - letter-spacing: -0.02em; - - color: #9d9d9d; - } -`; - -const CourseMetaWrapper = styled.div` - display: flex; - justify-content: space-between; -`; - -const CourseMetaLeft = styled.div` - width: 80%; -`; - -const CourseMetaRight = styled.div` - background: #ffffff; - box-shadow: 0px 4px 16px rgba(0, 0, 0, 0.03); - border-radius: 7px; - padding: 20px; - width: 30%; - display: flex; - height: 100%; - justify-content: center; - margin-left: 50px; - margin-top: 20px; - button { - width: 100%; - height: 50px; - background: #151515; - border-radius: 15px; - border: none; - color: white; - font-weight: 700; - font-family: "DM Sans"; - font-size: 16px; - letter-spacing: -0.05em; - transition: all 0.2s ease; - box-shadow: 0px 13px 33px -13px rgba(0, 0, 0, 0.42); - - &:hover { - cursor: pointer; - background: #000000; - } - } -`; export default CourseClient; diff --git a/front/app/orgs/[orgslug]/(withmenu)/course/[courseid]/edit/page.tsx b/front/app/orgs/[orgslug]/(withmenu)/course/[courseid]/edit/page.tsx index 0dda558b..3d9790c0 100644 --- a/front/app/orgs/[orgslug]/(withmenu)/course/[courseid]/edit/page.tsx +++ b/front/app/orgs/[orgslug]/(withmenu)/course/[courseid]/edit/page.tsx @@ -15,6 +15,7 @@ import { createActivity, createFileActivity, createExternalVideoActivity } from import { getOrganizationContextInfo } from "@services/organizations/orgs"; import Modal from "@components/UI/Modal/Modal"; import { denyAccessToUser } from "@services/utils/react/middlewares/views"; +import { Folders, Package2 } from "lucide-react"; function CourseEdit(params: any) { @@ -243,21 +244,7 @@ function CourseEdit(params: any) { Edit Course {" "} - <Modal - isDialogOpen={newChapterModal} - onOpenChange={setNewChapterModal} - minHeight="sm" - dialogContent={<NewChapterModal - closeModal={closeNewChapterModal} - submitChapter={submitChapter} - ></NewChapterModal>} - dialogTitle="Create chapter" - dialogDescription="Add a new chapter to the course" - dialogTrigger={ - <button> Add chapter + - </button> - } - /> + <button onClick={() => { @@ -287,7 +274,7 @@ function CourseEdit(params: any) { <br /> {winReady && ( - <ChapterlistWrapper> + <div className="flex flex-col max-w-7xl justify-center items-center mx-auto"> <DragDropContext onDragEnd={onDragEnd}> <Droppable key="chapters" droppableId="chapters" type="chapter"> {(provided) => ( @@ -312,7 +299,24 @@ function CourseEdit(params: any) { )} </Droppable> </DragDropContext> - </ChapterlistWrapper> + <Modal + isDialogOpen={newChapterModal} + onOpenChange={setNewChapterModal} + minHeight="sm" + dialogContent={<NewChapterModal + closeModal={closeNewChapterModal} + submitChapter={submitChapter} + ></NewChapterModal>} + dialogTitle="Create chapter" + dialogDescription="Add a new chapter to the course" + dialogTrigger={ + <div className="flex max-w-7xl bg-black shadow rounded-md text-white justify-center space-x-2 p-3 w-72 hover:bg-gray-900 hover:cursor-pointer"> + <Folders size={20} /> + <div>Add chapter +</div> + </div> + } + /> + </div> )} </Page > </> @@ -351,9 +355,5 @@ const Page = styled.div` } } `; -const ChapterlistWrapper = styled.div` - display: flex; - padding-left: 30px; - justify-content: center; -`; + export default CourseEdit; diff --git a/front/app/orgs/[orgslug]/(withmenu)/page.tsx b/front/app/orgs/[orgslug]/(withmenu)/page.tsx index b51d1a7d..d9484001 100644 --- a/front/app/orgs/[orgslug]/(withmenu)/page.tsx +++ b/front/app/orgs/[orgslug]/(withmenu)/page.tsx @@ -73,6 +73,7 @@ const OrgHomePage = async (params: any) => { </div> {/* Courses */} + <div className='h-5'></div> <Title title="Courses" type="cou" /> <div className="home_courses flex flex-wrap"> {courses.map((course: any) => ( @@ -92,13 +93,13 @@ const OrgHomePage = async (params: any) => { }; -const Title = (props: any) => { + const Title = (props: any) => { return ( - <div className="home_category_title flex my-5"> + <div className="home_category_title flex my-5 items-center"> <div className="rounded-full ring-1 ring-slate-900/5 shadow-sm p-2 my-auto mr-4"> <Image className="" src={props.type == "col" ? CollectionsLogo : CoursesLogo} alt="Courses logo" /> </div> - <h1 className="font-bold text-lg">{props.title}</h1> + <h1 className="font-bold text-2xl">{props.title}</h1> </div> ) } diff --git a/front/components/Editor/Extensions/Callout/Info/InfoCalloutComponent.tsx b/front/components/Editor/Extensions/Callout/Info/InfoCalloutComponent.tsx index e52430e0..b04503b9 100644 --- a/front/components/Editor/Extensions/Callout/Info/InfoCalloutComponent.tsx +++ b/front/components/Editor/Extensions/Callout/Info/InfoCalloutComponent.tsx @@ -7,7 +7,7 @@ function InfoCalloutComponent(props: any) { return ( <NodeViewWrapper> <InfoCalloutWrapper contentEditable={props.extension.options.editable}> - <AlertCircle /> <NodeViewContent contentEditable={props.extension.options.editable} className="content" /> + <AlertCircle /> <NodeViewContent contentEditable={props.extension.options.editable} className="content" /> </InfoCalloutWrapper> </NodeViewWrapper> ); @@ -17,7 +17,7 @@ const InfoCalloutWrapper = styled.div` display: flex; flex-direction: row; color: #1f3a8a; - background-color: #dbe9fe; + background-color: #dbe9fe; border: 1px solid #c1d9fb; border-radius: 16px; margin: 1rem 0; @@ -36,14 +36,6 @@ const InfoCalloutWrapper = styled.div` } `; -const DragHandle = styled.div` - position: absolute; - top: 0; - left: 0; - width: 1rem; - height: 100%; - cursor: move; - z-index: 1; -`; + export default InfoCalloutComponent; diff --git a/front/components/Pages/Activities/DynamicCanva/DynamicCanva.tsx b/front/components/Pages/Activities/DynamicCanva/DynamicCanva.tsx index 59cc3497..b988b488 100644 --- a/front/components/Pages/Activities/DynamicCanva/DynamicCanva.tsx +++ b/front/components/Pages/Activities/DynamicCanva/DynamicCanva.tsx @@ -64,7 +64,7 @@ function Canva(props: Editor) { const CanvaWrapper = styled.div` padding-top: 20px; - width: 1300px; + width: 100%; margin: 0 auto; `; diff --git a/front/components/Pages/CourseEdit/Draggables/Activity.tsx b/front/components/Pages/CourseEdit/Draggables/Activity.tsx index c3afd69d..3ca68255 100644 --- a/front/components/Pages/CourseEdit/Draggables/Activity.tsx +++ b/front/components/Pages/CourseEdit/Draggables/Activity.tsx @@ -11,7 +11,7 @@ function Activity(props: any) { <Draggable key={props.activity.id} draggableId={props.activity.id} index={props.index}> {(provided) => ( <div - className="flex flex-row items-center py-2 my-3 rounded-md justify-center bg-gray-50 hover:bg-gray-100 space-x-2" key={props.activity.id} {...provided.draggableProps} {...provided.dragHandleProps} ref={provided.innerRef}> + className="flex flex-row items-center py-2 my-3 rounded-md justify-center bg-gray-50 hover:bg-gray-100 space-x-2 w-auto" key={props.activity.id} {...provided.draggableProps} {...provided.dragHandleProps} ref={provided.innerRef}> <p>{props.activity.name} </p> <Link href={getUriWithOrg(props.orgslug, "") + `/course/${props.courseid}/activity/${props.activity.id.replace("activity_", "")}`} diff --git a/front/components/Pages/CourseEdit/Draggables/Chapter.tsx b/front/components/Pages/CourseEdit/Draggables/Chapter.tsx index a26b1c86..e0361818 100644 --- a/front/components/Pages/CourseEdit/Draggables/Chapter.tsx +++ b/front/components/Pages/CourseEdit/Draggables/Chapter.tsx @@ -2,6 +2,7 @@ import React from "react"; import styled from "styled-components"; import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd"; import Activity from "./Activity"; +import { PlusSquare } from "lucide-react"; function Chapter(props: any) { return ( @@ -16,16 +17,9 @@ function Chapter(props: any) { > <h3 className="pt-3 font-bold text-md"> {props.info.list.chapter.name} - <button - onClick={() => { - props.openNewActivityModal(props.info.list.chapter.id); - }} - > - - Create Activity - </button> - + + <button onClick={() => { props.deleteChapter(props.info.list.chapter.id); @@ -37,13 +31,24 @@ function Chapter(props: any) { <Droppable key={props.info.list.chapter.id} droppableId={props.info.list.chapter.id} type="activity"> {(provided) => ( <ActivitiesList {...provided.droppableProps} ref={provided.innerRef}> - {props.info.list.activities.map((activity: any, index: any) => ( - <Activity orgslug={props.orgslug} courseid={props.courseid} key={activity.id} activity={activity} index={index}></Activity> - ))} - {provided.placeholder} + <div className="flex flex-col "> + {props.info.list.activities.map((activity: any, index: any) => ( + <Activity orgslug={props.orgslug} courseid={props.courseid} key={activity.id} activity={activity} index={index}></Activity> + ))} + {provided.placeholder} + + <div onClick={() => { + props.openNewActivityModal(props.info.list.chapter.id); + }} className="flex space-x-2 items-center py-2 my-3 rounded-md justify-center outline outline-3 text-slate-500 outline-slate-200 bg-slate-50 hover:cursor-pointer"> + <PlusSquare className="" size={17} /> + <div className="text-sm mx-auto my-auto items-center font-bold">Add Activity</div> + </div> + </div> </ActivitiesList> + )} </Droppable> + </ChapterWrapper> )} </Draggable> diff --git a/front/components/Pages/Courses/ActivityIndicators.tsx b/front/components/Pages/Courses/ActivityIndicators.tsx new file mode 100644 index 00000000..b0fe82cf --- /dev/null +++ b/front/components/Pages/Courses/ActivityIndicators.tsx @@ -0,0 +1,73 @@ +import ToolTip from '@components/UI/Tooltip/Tooltip' +import { getUriWithOrg } from '@services/config/config' +import Link from 'next/link' +import React from 'react' + + +interface Props { + course: any + orgslug: string + current_activity?: any +} + +function ActivityIndicators(props: Props) { + const course = props.course + const orgslug = props.orgslug + const courseid = course.course.course_id.replace("course_", "") + + const done_activity_style = 'bg-teal-600 hover:bg-teal-700' + const black_activity_style = 'bg-black hover:bg-gray-700' + const current_activity_style = 'bg-gray-600 animate-pulse hover:bg-gray-700' + + + function isActivityDone(activity: any) { + if (course.trail.activities_marked_complete && course.trail.activities_marked_complete.includes(activity.id) && course.trail.status == "ongoing") { + return true + } + return false + } + + function isActivityCurrent(activity: any) { + let activityid = activity.id.replace("activity_", "") + if (props.current_activity && props.current_activity == activityid) { + return true + } + return false + } + + function getActivityClass(activity: any) { + if (isActivityDone(activity)) { + return done_activity_style + } + if (isActivityCurrent(activity)) { + return current_activity_style + } + return black_activity_style + } + + + return ( + <div className='grid grid-flow-col justify-stretch space-x-6'> + {course.chapters.map((chapter: any) => { + return ( + <> + <div className='grid grid-flow-col justify-stretch space-x-2'> + {chapter.activities.map((activity: any) => { + return ( + <ToolTip sideOffset={-5} slateBlack content={activity.name} key={activity.id}> + <Link href={getUriWithOrg(orgslug, "") + `/course/${courseid}/activity/${activity.id.replace("activity_", "")}`}> + <div className={`h-[7px] w-auto ${getActivityClass(activity)} rounded-lg shadow-md`}></div> + + </Link> + </ToolTip> + ); + })} + </div> + </> + ); + })} + </div> + ) +} + +export default ActivityIndicators \ No newline at end of file diff --git a/front/components/UI/Modal/Modal.tsx b/front/components/UI/Modal/Modal.tsx index dab976b9..350c099e 100644 --- a/front/components/UI/Modal/Modal.tsx +++ b/front/components/UI/Modal/Modal.tsx @@ -79,7 +79,7 @@ const contentClose = keyframes({ const DialogOverlay = styled(Dialog.Overlay, { backgroundColor: blackA.blackA9, position: 'fixed', - + zIndex: 500, inset: 0, animation: `${overlayShow} 150ms cubic-bezier(0.16, 1, 0.3, 1)`, '&[data-state="closed"]': { @@ -111,6 +111,7 @@ const DialogContent = styled(Dialog.Content, { backgroundColor: 'white', borderRadius: 18, + zIndex: 501, boxShadow: 'hsl(206 22% 7% / 35%) 0px 10px 38px -10px, hsl(206 22% 7% / 20%) 0px 10px 20px -15px', position: 'fixed', top: '50%',