From 832394777e96795b5248c02d6f89b35b4ee864ca Mon Sep 17 00:00:00 2001 From: swve Date: Tue, 19 Sep 2023 21:14:55 +0200 Subject: [PATCH 1/2] refactor: use components for thumbnails --- .../(withmenu)/collections/admin.tsx | 48 ----------- .../[orgslug]/(withmenu)/collections/page.tsx | 22 +---- .../[orgslug]/(withmenu)/courses/courses.tsx | 19 ++--- front/app/orgs/[orgslug]/(withmenu)/page.tsx | 21 +---- .../Objects/Other/CollectionThumbnail.tsx | 81 +++++++++++++++++++ .../Objects/Other/CourseThumbnail.tsx | 76 +++++++++++++++++ 6 files changed, 171 insertions(+), 96 deletions(-) delete mode 100644 front/app/orgs/[orgslug]/(withmenu)/collections/admin.tsx create mode 100644 front/components/Objects/Other/CollectionThumbnail.tsx create mode 100644 front/components/Objects/Other/CourseThumbnail.tsx diff --git a/front/app/orgs/[orgslug]/(withmenu)/collections/admin.tsx b/front/app/orgs/[orgslug]/(withmenu)/collections/admin.tsx deleted file mode 100644 index 09ad6d53..00000000 --- a/front/app/orgs/[orgslug]/(withmenu)/collections/admin.tsx +++ /dev/null @@ -1,48 +0,0 @@ -'use client'; - -import AuthenticatedClientElement from '@components/Security/AuthenticatedClientElement'; -import { AuthContext } from '@components/Security/AuthProvider'; -import ConfirmationModal from '@components/StyledElements/ConfirmationModal/ConfirmationModal'; -import { getUriWithOrg } from '@services/config/config'; -import { deleteCollection } from '@services/courses/collections'; -import { revalidateTags } from '@services/utils/ts/requests'; -import { Link, Trash, X } from 'lucide-react'; -import { useRouter } from 'next/navigation'; -import React from 'react' - -const CollectionAdminEditsArea = (props: any) => { - const router = useRouter(); - - const deleteCollectionUI = async (collectionId: number) => { - await deleteCollection(collectionId); - 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' - > - -
- ) -} - -export default CollectionAdminEditsArea; \ No newline at end of file diff --git a/front/app/orgs/[orgslug]/(withmenu)/collections/page.tsx b/front/app/orgs/[orgslug]/(withmenu)/collections/page.tsx index 82399971..9a1c5fa6 100644 --- a/front/app/orgs/[orgslug]/(withmenu)/collections/page.tsx +++ b/front/app/orgs/[orgslug]/(withmenu)/collections/page.tsx @@ -7,9 +7,9 @@ import { getOrganizationContextInfo } from "@services/organizations/orgs"; import { Metadata } from "next"; import { cookies } from "next/headers"; import Link from "next/link"; -import CollectionAdminEditsArea from "./admin"; import { getCourseThumbnailMediaDirectory } from "@services/media/media"; import { getAccessTokenFromRefreshTokenCookie, getNewAccessTokenUsingRefreshTokenServer } from "@services/auth/auth"; +import CollectionThumbnail from "@components/Objects/Other/CollectionThumbnail"; type MetadataProps = { params: { orgslug: string, courseid: string }; @@ -22,7 +22,7 @@ export async function generateMetadata( const cookieStore = cookies(); // Get Org context information const org = await getOrganizationContextInfo(params.orgslug, { revalidate: 1800, tags: ['organizations'] }); - + // SEO return { title: `Collections — ${org.name}`, @@ -45,10 +45,6 @@ export async function generateMetadata( }; } -const removeCollectionPrefix = (collectionid: string) => { - return collectionid.replace("collection_", "") -} - const CollectionsPage = async (params: any) => { const cookieStore = cookies(); @@ -71,19 +67,7 @@ const CollectionsPage = async (params: any) => {
{collections.map((collection: any) => (
- - -
-

{collection.name}

-
- {collection.courses.slice(0, 3).map((course: any) => ( - - {course.name} - - ))} -
-
- +
))}
diff --git a/front/app/orgs/[orgslug]/(withmenu)/courses/courses.tsx b/front/app/orgs/[orgslug]/(withmenu)/courses/courses.tsx index f5af8a02..afabb52d 100644 --- a/front/app/orgs/[orgslug]/(withmenu)/courses/courses.tsx +++ b/front/app/orgs/[orgslug]/(withmenu)/courses/courses.tsx @@ -17,6 +17,7 @@ import AuthenticatedClientElement from '@components/Security/AuthenticatedClient 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'; interface CourseProps { orgslug: string; @@ -75,13 +76,7 @@ function Courses(props: CourseProps) {
{courses.map((course: any) => (
- - -
- -
- -

{course.name}

+
))}
@@ -107,11 +102,11 @@ const AdminEditsArea = (props: { orgSlug: string, courseId: string, course: any, status='warning' > -
- -
+
+ +
diff --git a/front/app/orgs/[orgslug]/(withmenu)/page.tsx b/front/app/orgs/[orgslug]/(withmenu)/page.tsx index 83675fb2..ebfac310 100644 --- a/front/app/orgs/[orgslug]/(withmenu)/page.tsx +++ b/front/app/orgs/[orgslug]/(withmenu)/page.tsx @@ -13,6 +13,8 @@ import GeneralWrapperStyled from '@components/StyledElements/Wrappers/GeneralWra import TypeOfContentTitle from '@components/StyledElements/Titles/TypeOfContentTitle'; import { getCourseThumbnailMediaDirectory } from '@services/media/media'; import { getAccessTokenFromRefreshTokenCookie, getNewAccessTokenUsingRefreshTokenServer } from '@services/auth/auth'; +import CourseThumbnail from '@components/Objects/Other/CourseThumbnail'; +import CollectionThumbnail from '@components/Objects/Other/CollectionThumbnail'; type MetadataProps = { params: { orgslug: string }; @@ -74,18 +76,7 @@ const OrgHomePage = async (params: any) => {
{collections.map((collection: any) => (
- -
-

{collection.name}

-
- {collection.courses.slice(0, 3).map((course: any) => ( - - {course.name} - - ))} -
-
- +
))}
@@ -96,11 +87,7 @@ const OrgHomePage = async (params: any) => {
{courses.map((course: any) => (
- -
-
- -

{course.name}

+
))}
diff --git a/front/components/Objects/Other/CollectionThumbnail.tsx b/front/components/Objects/Other/CollectionThumbnail.tsx new file mode 100644 index 00000000..7075e595 --- /dev/null +++ b/front/components/Objects/Other/CollectionThumbnail.tsx @@ -0,0 +1,81 @@ +"use client"; +import AuthenticatedClientElement from '@components/Security/AuthenticatedClientElement' +import ConfirmationModal from '@components/StyledElements/ConfirmationModal/ConfirmationModal' +import { getUriWithOrg } from '@services/config/config' +import { deleteCollection } from '@services/courses/collections' +import { getCourseThumbnailMediaDirectory } from '@services/media/media' +import { revalidateTags } from '@services/utils/ts/requests' +import { X } from 'lucide-react' +import Link from 'next/link' +import { useRouter } from 'next/navigation' +import React from 'react' + +type PropsType = { + collection: any, + orgslug: string, + org_id: string +} + +const removeCollectionPrefix = (collectionid: string) => { + return collectionid.replace("collection_", "") +} + +function CollectionThumbnail(props: PropsType) { + return ( +
+ + +
+
+ {props.collection.courses.slice(0, 3).map((course: any) => ( + + +
+ +
+ + ))} +
+

{props.collection.name}

+
+ +
+ ) +} + +const CollectionAdminEditsArea = (props: any) => { + const router = useRouter(); + + const deleteCollectionUI = async (collectionId: number) => { + await deleteCollection(collectionId); + 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' + > + +
+ ) +} + +export default CollectionThumbnail \ No newline at end of file diff --git a/front/components/Objects/Other/CourseThumbnail.tsx b/front/components/Objects/Other/CourseThumbnail.tsx new file mode 100644 index 00000000..2aa2eaa8 --- /dev/null +++ b/front/components/Objects/Other/CourseThumbnail.tsx @@ -0,0 +1,76 @@ +"use client"; +import AuthenticatedClientElement from '@components/Security/AuthenticatedClientElement'; +import ConfirmationModal from '@components/StyledElements/ConfirmationModal/ConfirmationModal'; +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 Link from 'next/link'; +import { useRouter } from 'next/navigation'; +import React from 'react' + +type PropsType = { + course: any, + orgslug: string +} + +// function to remove "course_" from the course_id +function removeCoursePrefix(course_id: string) { + return course_id.replace("course_", ""); +} + +function CourseThumbnail(props: PropsType) { + const router = useRouter(); + + async function deleteCourses(course_id: any) { + await deleteCourseFromBackend(course_id); + await revalidateTags(['courses'], props.orgslug); + + router.refresh(); + } + + return ( +
+ + +
+ +
+ +

{props.course.name}

+
+ ) +} + +const AdminEditsArea = (props: { orgSlug: string, courseId: string, course: any, deleteCourses: any }) => { + return ( + +
+ +
+ +
+ + + +
} + functionToExecute={() => props.deleteCourses(props.courseId)} + status='warning' + > + + +
+ ) +} + +export default CourseThumbnail \ No newline at end of file From ebb8c64fd7752f77a798e716a9494b92f9bb28b6 Mon Sep 17 00:00:00 2001 From: swve Date: Thu, 21 Sep 2023 17:55:28 +0200 Subject: [PATCH 2/2] 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