From ebb8c64fd7752f77a798e716a9494b92f9bb28b6 Mon Sep 17 00:00:00 2001 From: swve Date: Thu, 21 Sep 2023 17:55:28 +0200 Subject: [PATCH] feat: refactor + home improvements --- .../[orgslug]/(withmenu)/collections/page.tsx | 35 ++++-- .../[orgslug]/(withmenu)/courses/courses.tsx | 100 ++++++++---------- front/app/orgs/[orgslug]/(withmenu)/page.tsx | 87 +++++++++++---- .../Modals/Course/Create/CreateCourse.tsx | 6 +- .../Objects/Other/CollectionThumbnail.tsx | 38 +++---- .../Objects/Other/CourseThumbnail.tsx | 11 +- .../Buttons/NewCollectionButton.tsx | 13 +++ .../Buttons/NewCourseButton.tsx | 12 +++ 8 files changed, 187 insertions(+), 115 deletions(-) create mode 100644 front/components/StyledElements/Buttons/NewCollectionButton.tsx create mode 100644 front/components/StyledElements/Buttons/NewCourseButton.tsx diff --git a/front/app/orgs/[orgslug]/(withmenu)/collections/page.tsx b/front/app/orgs/[orgslug]/(withmenu)/collections/page.tsx index 9a1c5fa6..6e97087a 100644 --- a/front/app/orgs/[orgslug]/(withmenu)/collections/page.tsx +++ b/front/app/orgs/[orgslug]/(withmenu)/collections/page.tsx @@ -1,15 +1,15 @@ import AuthenticatedClientElement from "@components/Security/AuthenticatedClientElement"; import TypeOfContentTitle from "@components/StyledElements/Titles/TypeOfContentTitle"; import GeneralWrapperStyled from "@components/StyledElements/Wrappers/GeneralWrapper"; -import { getBackendUrl, getUriWithOrg } from "@services/config/config"; -import { deleteCollection, getOrgCollectionsWithAuthHeader } from "@services/courses/collections"; +import { getUriWithOrg } from "@services/config/config"; +import { getOrgCollectionsWithAuthHeader } from "@services/courses/collections"; import { getOrganizationContextInfo } from "@services/organizations/orgs"; import { Metadata } from "next"; import { cookies } from "next/headers"; import Link from "next/link"; -import { getCourseThumbnailMediaDirectory } from "@services/media/media"; -import { getAccessTokenFromRefreshTokenCookie, getNewAccessTokenUsingRefreshTokenServer } from "@services/auth/auth"; +import { getAccessTokenFromRefreshTokenCookie } from "@services/auth/auth"; import CollectionThumbnail from "@components/Objects/Other/CollectionThumbnail"; +import NewCollectionButton from "@components/StyledElements/Buttons/NewCollectionButton"; type MetadataProps = { params: { orgslug: string, courseid: string }; @@ -19,7 +19,6 @@ type MetadataProps = { export async function generateMetadata( { params }: MetadataProps, ): Promise { - const cookieStore = cookies(); // Get Org context information const org = await getOrganizationContextInfo(params.orgslug, { revalidate: 1800, tags: ['organizations'] }); @@ -45,7 +44,6 @@ export async function generateMetadata( }; } - const CollectionsPage = async (params: any) => { const cookieStore = cookies(); const access_token = await getAccessTokenFromRefreshTokenCookie(cookieStore) @@ -60,16 +58,37 @@ const CollectionsPage = async (params: any) => { - +
{collections.map((collection: any) => ( -
+
))} + {collections.length == 0 && +
+
+
+ + + + +
+
+

No collections yet

+

Create a collection to group courses together

+
+ + + + + +
+
+ }
); diff --git a/front/app/orgs/[orgslug]/(withmenu)/courses/courses.tsx b/front/app/orgs/[orgslug]/(withmenu)/courses/courses.tsx index afabb52d..f8265a07 100644 --- a/front/app/orgs/[orgslug]/(withmenu)/courses/courses.tsx +++ b/front/app/orgs/[orgslug]/(withmenu)/courses/courses.tsx @@ -1,23 +1,13 @@ 'use client'; import CreateCourseModal from '@components/Objects/Modals/Course/Create/CreateCourse'; import Modal from '@components/StyledElements/Modal/Modal'; -import { getBackendUrl, getUriWithOrg } from '@services/config/config'; -import CoursesLogo from "public/svg/courses.svg"; -import CollectionsLogo from "public/svg/collections.svg"; -import { deleteCourseFromBackend } from '@services/courses/courses'; -import Link from 'next/link'; import React from 'react' -import Image from 'next/image'; -import { AuthContext } from '@components/Security/AuthProvider'; -import { revalidateTags } from '@services/utils/ts/requests'; -import { useRouter } from 'next/navigation'; +import { useSearchParams } from 'next/navigation'; import GeneralWrapperStyled from '@components/StyledElements/Wrappers/GeneralWrapper'; import TypeOfContentTitle from '@components/StyledElements/Titles/TypeOfContentTitle'; import AuthenticatedClientElement from '@components/Security/AuthenticatedClientElement'; -import { getCourseThumbnailMediaDirectory } from '@services/media/media'; -import ConfirmationModal from '@components/StyledElements/ConfirmationModal/ConfirmationModal'; -import { Pencil, X } from 'lucide-react'; import CourseThumbnail from '@components/Objects/Other/CourseThumbnail'; +import NewCourseButton from '@components/StyledElements/Buttons/NewCourseButton'; interface CourseProps { orgslug: string; @@ -25,23 +15,12 @@ interface CourseProps { org_id: string; } -// function to remove "course_" from the course_id -function removeCoursePrefix(course_id: string) { - return course_id.replace("course_", ""); -} - function Courses(props: CourseProps) { const orgslug = props.orgslug; const courses = props.courses; - const [newCourseModal, setNewCourseModal] = React.useState(false); - const router = useRouter(); - - async function deleteCourses(course_id: any) { - await deleteCourseFromBackend(course_id); - await revalidateTags(['courses'], orgslug); - - router.refresh(); - } + const searchParams = useSearchParams(); + const isCreatingCourse = searchParams.get('new') ? true : false; + const [newCourseModal, setNewCourseModal] = React.useState(isCreatingCourse); async function closeNewCourseModal() { setNewCourseModal(false); @@ -65,8 +44,10 @@ function Courses(props: CourseProps) { dialogTitle="Create Course" dialogDescription="Create a new course" dialogTrigger={ - - } + + } />
@@ -79,39 +60,48 @@ function Courses(props: CourseProps) { ))} + {courses.length == 0 && +
+
+
+ + + + +
+
+

No courses yet

+

Create a course to add content

+
+ + } + dialogTitle="Create Course" + dialogDescription="Create a new course" + dialogTrigger={ + } + /> + +
+
+ } + + ) } -const AdminEditsArea = (props: { orgSlug: string, courseId: string, course: any, deleteCourses: any }) => { - return ( -
- - -
} - functionToExecute={() => props.deleteCourses(props.courseId)} - status='warning' - > - -
- -
- - -
- ) -} + export default Courses \ No newline at end of file diff --git a/front/app/orgs/[orgslug]/(withmenu)/page.tsx b/front/app/orgs/[orgslug]/(withmenu)/page.tsx index ebfac310..518c32e2 100644 --- a/front/app/orgs/[orgslug]/(withmenu)/page.tsx +++ b/front/app/orgs/[orgslug]/(withmenu)/page.tsx @@ -1,20 +1,20 @@ export const dynamic = 'force-dynamic'; -import { Metadata, ResolvingMetadata } from 'next'; -import { getBackendUrl, getUriWithOrg } from "@services/config/config"; -import { getCourse, getOrgCourses, getOrgCoursesWithAuthHeader } from "@services/courses/courses"; - +import { Metadata } from 'next'; +import { getUriWithOrg } from "@services/config/config"; +import { getOrgCoursesWithAuthHeader } from "@services/courses/courses"; import Link from "next/link"; -import Image from "next/image"; -import { getOrgCollections, getOrgCollectionsWithAuthHeader } from "@services/courses/collections"; +import { getOrgCollectionsWithAuthHeader } from "@services/courses/collections"; import { getOrganizationContextInfo } from '@services/organizations/orgs'; - import { cookies } from 'next/headers'; import GeneralWrapperStyled from '@components/StyledElements/Wrappers/GeneralWrapper'; import TypeOfContentTitle from '@components/StyledElements/Titles/TypeOfContentTitle'; -import { getCourseThumbnailMediaDirectory } from '@services/media/media'; -import { getAccessTokenFromRefreshTokenCookie, getNewAccessTokenUsingRefreshTokenServer } from '@services/auth/auth'; +import { getAccessTokenFromRefreshTokenCookie } from '@services/auth/auth'; import CourseThumbnail from '@components/Objects/Other/CourseThumbnail'; import CollectionThumbnail from '@components/Objects/Other/CollectionThumbnail'; +import AuthenticatedClientElement from '@components/Security/AuthenticatedClientElement'; +import { Plus, PlusCircle } from 'lucide-react'; +import NewCourseButton from '@components/StyledElements/Buttons/NewCourseButton'; +import NewCollectionButton from '@components/StyledElements/Buttons/NewCollectionButton'; type MetadataProps = { params: { orgslug: string }; @@ -56,40 +56,85 @@ 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'] }); - - // function to remove "course_" from the course_id - function removeCoursePrefix(course_id: string) { - return course_id.replace("course_", ""); - } - - function removeCollectionPrefix(collection_id: string) { - return collection_id.replace("collection_", ""); - } - return (
{/* Collections */} - +
+
+ +
+ + + + + +
{collections.map((collection: any) => (
))} + {collections.length == 0 && +
+
+
+
+ + + + +
+
+

No collections yet

+

Create a collection to group courses together

+
+
+
+
+ }
{/* Courses */}
- +
+
+ +
+ + + + + +
{courses.map((course: any) => (
))} + {courses.length == 0 && +
+
+
+
+ + + + +
+
+

No courses yet

+

Create a course to add content

+
+
+
+
+ }
diff --git a/front/components/Objects/Modals/Course/Create/CreateCourse.tsx b/front/components/Objects/Modals/Course/Create/CreateCourse.tsx index 9456dfc2..a6ec2a09 100644 --- a/front/components/Objects/Modals/Course/Create/CreateCourse.tsx +++ b/front/components/Objects/Modals/Course/Create/CreateCourse.tsx @@ -1,12 +1,10 @@ import FormLayout, { ButtonBlack, Flex, FormField, FormLabel, Input, Textarea } from '@components/StyledElements/Form/Form' import * as Form from '@radix-ui/react-form' -import { getAPIUrl, getUriWithOrg } from '@services/config/config'; import { FormMessage } from "@radix-ui/react-form"; import { createNewCourse } from '@services/courses/courses'; -import { getOrganizationContextInfo, getOrganizationContextInfoWithoutCredentials } from '@services/organizations/orgs'; +import { getOrganizationContextInfoWithoutCredentials } from '@services/organizations/orgs'; import React, { useState } from 'react' import { BarLoader } from 'react-spinners' -import { mutate } from 'swr'; import { revalidateTags } from '@services/utils/ts/requests'; import { useRouter } from 'next/navigation'; @@ -96,7 +94,7 @@ function CreateCourseModal({ closeModal, orgslug }: any) { - Course Learnings + Course keywords Please provide learning elements, separated by comma (,) diff --git a/front/components/Objects/Other/CollectionThumbnail.tsx b/front/components/Objects/Other/CollectionThumbnail.tsx index 7075e595..fc38df48 100644 --- a/front/components/Objects/Other/CollectionThumbnail.tsx +++ b/front/components/Objects/Other/CollectionThumbnail.tsx @@ -22,23 +22,23 @@ const removeCollectionPrefix = (collectionid: string) => { function CollectionThumbnail(props: PropsType) { return ( -
- - -
-
- {props.collection.courses.slice(0, 3).map((course: any) => ( - - -
- +
+
+
+ {props.collection.courses.slice(0, 2).map((course: any) => ( + <> + +
- ))} -
-

{props.collection.name}

+ + ))}
- + +

{props.collection.name}

+ + +
) } @@ -51,24 +51,20 @@ const CollectionAdminEditsArea = (props: any) => { await revalidateTags(["collections"], props.orgslug); // reload the page router.refresh(); - router.push(getUriWithOrg(props.orgslug, "/collections")); - - // refresh page (FIX for Next.js BUG) - //window.location.reload(); } return ( -
+
- +
} functionToExecute={() => deleteCollectionUI(props.collection_id)} status='warning' diff --git a/front/components/Objects/Other/CourseThumbnail.tsx b/front/components/Objects/Other/CourseThumbnail.tsx index 2aa2eaa8..3ac0fdd6 100644 --- a/front/components/Objects/Other/CourseThumbnail.tsx +++ b/front/components/Objects/Other/CourseThumbnail.tsx @@ -5,7 +5,7 @@ import { getUriWithOrg } from '@services/config/config'; import { deleteCourseFromBackend } from '@services/courses/courses'; import { getCourseThumbnailMediaDirectory } from '@services/media/media'; import { revalidateTags } from '@services/utils/ts/requests'; -import { FileEdit, Pencil, X } from 'lucide-react'; +import { FileEdit, X } from 'lucide-react'; import Link from 'next/link'; import { useRouter } from 'next/navigation'; import React from 'react' @@ -34,8 +34,8 @@ function CourseThumbnail(props: PropsType) {
-
- +
+

{props.course.name}

@@ -49,7 +49,7 @@ const AdminEditsArea = (props: { orgSlug: string, courseId: string, course: any,
@@ -60,14 +60,13 @@ const AdminEditsArea = (props: { orgSlug: string, courseId: string, course: any, dialogTitle={'Delete ' + props.course.name + ' ?'} dialogTrigger={
} functionToExecute={() => props.deleteCourses(props.courseId)} status='warning' > -
) diff --git a/front/components/StyledElements/Buttons/NewCollectionButton.tsx b/front/components/StyledElements/Buttons/NewCollectionButton.tsx new file mode 100644 index 00000000..2008e5d4 --- /dev/null +++ b/front/components/StyledElements/Buttons/NewCollectionButton.tsx @@ -0,0 +1,13 @@ +"use client"; + +function NewCollectionButton() { + return ( + + + ) +} + +export default NewCollectionButton \ No newline at end of file diff --git a/front/components/StyledElements/Buttons/NewCourseButton.tsx b/front/components/StyledElements/Buttons/NewCourseButton.tsx new file mode 100644 index 00000000..6511f26b --- /dev/null +++ b/front/components/StyledElements/Buttons/NewCourseButton.tsx @@ -0,0 +1,12 @@ +"use client"; + +function NewCourseButton() { + return ( + + ) +} + +export default NewCourseButton \ No newline at end of file