From a147ad6610d81539af95db46457880d2921f3cf0 Mon Sep 17 00:00:00 2001 From: swve Date: Fri, 9 Feb 2024 21:22:15 +0100 Subject: [PATCH] feat: format with prettier --- apps/web/app/api/revalidate/route.ts | 16 +- .../activity/[activityuuid]/edit/loading.tsx | 11 +- .../activity/[activityuuid]/edit/page.tsx | 80 +- apps/web/app/editor/main.ts | 2 +- apps/web/app/global-error.tsx | 36 +- apps/web/app/install/install.tsx | 173 +-- apps/web/app/install/page.tsx | 17 +- .../app/install/steps/account_creation.tsx | 289 +++-- .../app/install/steps/default_elements.tsx | 76 +- .../install/steps/disable_install_mode.tsx | 38 +- apps/web/app/install/steps/finish.tsx | 31 +- apps/web/app/install/steps/get_started.tsx | 125 +- apps/web/app/install/steps/org_creation.tsx | 283 +++-- apps/web/app/install/steps/sample_data.tsx | 39 +- apps/web/app/install/steps/steps.tsx | 45 +- apps/web/app/layout.tsx | 20 +- apps/web/app/organizations/new/page.tsx | 55 +- apps/web/app/organizations/page.tsx | 47 +- .../collection/[collectionid]/error.tsx | 22 +- .../collection/[collectionid]/loading.tsx | 9 +- .../collection/[collectionid]/page.tsx | 123 +- .../(withmenu)/collections/loading.tsx | 11 +- .../(withmenu)/collections/new/page.tsx | 141 +-- .../[orgslug]/(withmenu)/collections/page.tsx | 232 ++-- .../activity/[activityid]/activity.tsx | 232 ++-- .../activity/[activityid]/error.tsx | 22 +- .../activity/[activityid]/loading.tsx | 11 +- .../activity/[activityid]/page.tsx | 139 ++- .../(withmenu)/course/[courseuuid]/course.tsx | 382 +++--- .../(withmenu)/course/[courseuuid]/error.tsx | 22 +- .../course/[courseuuid]/loading.tsx | 11 +- .../(withmenu)/course/[courseuuid]/page.tsx | 121 +- .../[orgslug]/(withmenu)/courses/courses.tsx | 229 ++-- .../[orgslug]/(withmenu)/courses/error.tsx | 22 +- .../[orgslug]/(withmenu)/courses/loading.tsx | 11 +- .../[orgslug]/(withmenu)/courses/page.tsx | 67 +- .../app/orgs/[orgslug]/(withmenu)/error.tsx | 24 +- .../app/orgs/[orgslug]/(withmenu)/layout.tsx | 16 +- .../app/orgs/[orgslug]/(withmenu)/loading.tsx | 9 +- .../app/orgs/[orgslug]/(withmenu)/page.tsx | 211 ++-- .../orgs/[orgslug]/(withmenu)/trail/page.tsx | 53 +- .../orgs/[orgslug]/(withmenu)/trail/trail.tsx | 51 +- .../orgs/[orgslug]/dash/courses/client.tsx | 220 ++-- .../course/[courseuuid]/[subpage]/page.tsx | 141 ++- .../app/orgs/[orgslug]/dash/courses/page.tsx | 98 +- apps/web/app/orgs/[orgslug]/dash/layout.tsx | 36 +- .../dash/org/settings/[subpage]/page.tsx | 80 +- apps/web/app/orgs/[orgslug]/dash/page.tsx | 132 ++- .../user-account/settings/[subpage]/page.tsx | 138 ++- .../dash/users/settings/[subpage]/page.tsx | 199 ++-- apps/web/app/orgs/[orgslug]/layout.tsx | 23 +- apps/web/app/orgs/[orgslug]/login/login.tsx | 286 +++-- apps/web/app/orgs/[orgslug]/login/page.tsx | 44 +- .../[orgslug]/signup/InviteOnlySignUp.tsx | 308 ++--- .../app/orgs/[orgslug]/signup/OpenSignup.tsx | 323 +++--- apps/web/app/orgs/[orgslug]/signup/page.tsx | 49 +- apps/web/app/orgs/[orgslug]/signup/signup.tsx | 340 +++--- apps/web/app/page.tsx | 39 +- .../components/AI/Hooks/useGetAIFeatures.tsx | 25 +- .../Contexts/AI/AIChatBotContext.tsx | 108 +- .../Contexts/AI/AIEditorContext.tsx | 143 +-- .../web/components/Contexts/CourseContext.tsx | 103 +- .../Contexts/Editor/EditorContext.tsx | 28 +- apps/web/components/Contexts/OrgContext.tsx | 34 +- .../components/Contexts/SessionContext.tsx | 100 +- .../EditCourseGeneral/EditCourseGeneral.tsx | 344 +++--- .../EditCourseGeneral/ThumbnailUpdate.tsx | 165 +-- .../Buttons/NewActivityButton.tsx | 183 +-- .../DraggableElements/ActivityElement.tsx | 307 +++-- .../DraggableElements/ChapterElement.tsx | 272 +++-- .../EditCourseStructure.tsx | 299 ++--- .../Org/OrgEditGeneral/OrgEditGeneral.tsx | 80 +- .../components/Dashboard/UI/BreadCrumbs.tsx | 76 +- .../Dashboard/UI/CourseOverviewTop.tsx | 101 +- apps/web/components/Dashboard/UI/LeftMenu.tsx | 241 ++-- .../web/components/Dashboard/UI/SaveState.tsx | 221 ++-- .../UserEditGeneral/UserEditGeneral.tsx | 168 +-- .../UserEditPassword/UserEditPassword.tsx | 108 +- .../Dashboard/Users/OrgAccess/OrgAccess.tsx | 367 +++--- .../Dashboard/Users/OrgUsers/OrgUsers.tsx | 240 ++-- .../Objects/Activities/AI/AIActivityAsk.tsx | 710 +++++++----- .../Activities/DocumentPdf/DocumentPdf.tsx | 34 +- .../DynamicCanva/AI/AICanvaToolkit.tsx | 317 +++-- .../Activities/DynamicCanva/DynamicCanva.tsx | 216 ++-- .../Objects/Activities/Video/Video.tsx | 76 +- .../Objects/Editor/AI/AIEditorToolkit.tsx | 1030 ++++++++++------- apps/web/components/Objects/Editor/Editor.tsx | 490 ++++---- .../Objects/Editor/EditorWrapper.tsx | 81 +- .../Extensions/Callout/Info/InfoCallout.ts | 22 +- .../Callout/Info/InfoCalloutComponent.tsx | 37 +- .../Callout/Warning/WarningCallout.ts | 22 +- .../Warning/WarningCalloutComponent.tsx | 37 +- .../Editor/Extensions/Image/ImageBlock.ts | 22 +- .../Extensions/Image/ImageBlockComponent.tsx | 152 ++- .../MathEquation/MathEquationBlock.ts | 24 +- .../MathEquationBlockComponent.tsx | 66 +- .../Extensions/NoTextInput/NoTextInput.tsx | 46 +- .../Objects/Editor/Extensions/PDF/PDFBlock.ts | 22 +- .../Extensions/PDF/PDFBlockComponent.tsx | 109 +- .../Editor/Extensions/Quiz/QuizBlock.ts | 22 +- .../Extensions/Quiz/QuizBlockComponent.tsx | 419 ++++--- .../Editor/Extensions/Video/VideoBlock.ts | 24 +- .../Extensions/Video/VideoBlockComponent.tsx | 111 +- .../Objects/Editor/Toolbar/ToolbarButtons.tsx | 110 +- .../Objects/Loaders/PageLoading.tsx | 79 +- apps/web/components/Objects/Menu/Menu.tsx | 188 +-- .../web/components/Objects/Menu/MenuLinks.tsx | 130 ++- .../components/Objects/Menu/ProfileArea.tsx | 115 +- .../Modals/Activities/Create/NewActivity.tsx | 160 ++- .../Create/NewActivityModal/DocumentPdf.tsx | 84 +- .../Create/NewActivityModal/DynamicCanva.tsx | 73 +- .../Create/NewActivityModal/Video.tsx | 202 ++-- .../Objects/Modals/Chapters/NewChapter.tsx | 71 +- .../Modals/Course/Create/CreateCourse.tsx | 296 ++--- .../Modals/Dash/OrgUsers/RolesUpdate.tsx | 160 +-- .../Objects/Modals/Feedback/Feedback.tsx | 176 +-- .../Thumbnails/CollectionThumbnail.tsx | 141 ++- .../Objects/Thumbnails/CourseThumbnail.tsx | 173 +-- apps/web/components/Objects/UserAvatar.tsx | 107 +- .../Pages/CourseEdit/Draggables/Activity.tsx | 213 +++- .../Pages/CourseEdit/Draggables/Chapter.tsx | 166 ++- .../Pages/CourseEdit/Draggables/data.ts | 36 +- .../Pages/Courses/ActivityIndicators.tsx | 142 ++- .../Pages/Trail/TrailCourseElement.tsx | 145 ++- .../Security/AdminAuthorization.tsx | 240 ++-- .../Security/AuthenticatedClientElement.tsx | 131 ++- .../components/Security/HeaderProfileBox.tsx | 44 +- .../Buttons/NewCollectionButton.tsx | 7 +- .../Buttons/NewCourseButton.tsx | 6 +- .../ConfirmationModal/ConfirmationModal.tsx | 223 ++-- .../components/StyledElements/Error/Error.tsx | 30 +- .../components/StyledElements/Form/Form.tsx | 168 +-- .../components/StyledElements/Modal/Modal.tsx | 259 ++--- .../Titles/TypeOfContentTitle.tsx | 47 +- .../components/StyledElements/Toast/Toast.tsx | 15 +- .../StyledElements/Tooltip/Tooltip.tsx | 60 +- .../Wrappers/GeneralWrapper.tsx | 14 +- apps/web/components/Utils/ClientComp.tsx | 14 +- .../components/Utils/libs/styled-registry.tsx | 27 +- apps/web/middleware.ts | 52 +- apps/web/sentry.client.config.ts | 8 +- apps/web/sentry.server.config.ts | 8 +- apps/web/services/ai/ai.ts | 61 +- apps/web/services/auth/auth.ts | 163 +-- apps/web/services/blocks/Image/images.ts | 24 +- apps/web/services/blocks/Pdf/pdf.ts | 24 +- apps/web/services/blocks/Quiz/quiz.ts | 16 +- apps/web/services/blocks/Video/video.ts | 24 +- apps/web/services/config/config.ts | 40 +- apps/web/services/courses/activities.ts | 120 +- apps/web/services/courses/activity.ts | 37 +- apps/web/services/courses/chapters.ts | 65 +- apps/web/services/courses/collections.ts | 73 +- apps/web/services/courses/courses.ts | 120 +- apps/web/services/install/install.ts | 68 +- apps/web/services/media/media.ts | 73 +- apps/web/services/organizations/invites.ts | 50 +- apps/web/services/organizations/orgs.ts | 94 +- apps/web/services/settings/org.ts | 32 +- apps/web/services/settings/password.ts | 15 +- apps/web/services/settings/profile.ts | 15 +- apps/web/services/users/users.ts | 33 +- .../services/utils/react/middlewares/views.ts | 8 +- apps/web/services/utils/ts/requests.ts | 124 +- 164 files changed, 11257 insertions(+), 8154 deletions(-) diff --git a/apps/web/app/api/revalidate/route.ts b/apps/web/app/api/revalidate/route.ts index 3ca5eec1..e0645121 100644 --- a/apps/web/app/api/revalidate/route.ts +++ b/apps/web/app/api/revalidate/route.ts @@ -1,19 +1,19 @@ -import { NextRequest, NextResponse } from "next/server"; -import { revalidateTag } from "next/cache"; +import { NextRequest, NextResponse } from 'next/server' +import { revalidateTag } from 'next/cache' export async function GET(request: NextRequest) { - const tag: any = request.nextUrl.searchParams.get("tag"); - revalidateTag(tag); + const tag: any = request.nextUrl.searchParams.get('tag') + revalidateTag(tag) return NextResponse.json( { revalidated: true, now: Date.now(), tag }, { status: 200, headers: { - "Access-Control-Allow-Origin": "*", - "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS", - "Access-Control-Allow-Headers": "Content-Type, Authorization", + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', + 'Access-Control-Allow-Headers': 'Content-Type, Authorization', }, } - ); + ) } diff --git a/apps/web/app/editor/course/[courseid]/activity/[activityuuid]/edit/loading.tsx b/apps/web/app/editor/course/[courseid]/activity/[activityuuid]/edit/loading.tsx index 3f902486..3da44848 100644 --- a/apps/web/app/editor/course/[courseid]/activity/[activityuuid]/edit/loading.tsx +++ b/apps/web/app/editor/course/[courseid]/activity/[activityuuid]/edit/loading.tsx @@ -1,9 +1,6 @@ -import PageLoading from "@components/Objects/Loaders/PageLoading"; +import PageLoading from '@components/Objects/Loaders/PageLoading' export default function Loading() { - // Or a custom loading skeleton component - return ( - - ) - -} \ No newline at end of file + // Or a custom loading skeleton component + return +} diff --git a/apps/web/app/editor/course/[courseid]/activity/[activityuuid]/edit/page.tsx b/apps/web/app/editor/course/[courseid]/activity/[activityuuid]/edit/page.tsx index 14aa9953..27c85c02 100644 --- a/apps/web/app/editor/course/[courseid]/activity/[activityuuid]/edit/page.tsx +++ b/apps/web/app/editor/course/[courseid]/activity/[activityuuid]/edit/page.tsx @@ -1,52 +1,72 @@ -import { default as React, } from "react"; -import EditorWrapper from "@components/Objects/Editor/EditorWrapper"; -import { getCourseMetadataWithAuthHeader } from "@services/courses/courses"; -import { cookies } from "next/headers"; -import { Metadata } from "next"; -import { getActivityWithAuthHeader } from "@services/courses/activities"; -import { getAccessTokenFromRefreshTokenCookie } from "@services/auth/auth"; -import { getOrganizationContextInfoWithId } from "@services/organizations/orgs"; -import SessionProvider from "@components/Contexts/SessionContext"; -import EditorOptionsProvider from "@components/Contexts/Editor/EditorContext"; -import AIEditorProvider from "@components/Contexts/AI/AIEditorContext"; +import { default as React } from 'react' +import EditorWrapper from '@components/Objects/Editor/EditorWrapper' +import { getCourseMetadataWithAuthHeader } from '@services/courses/courses' +import { cookies } from 'next/headers' +import { Metadata } from 'next' +import { getActivityWithAuthHeader } from '@services/courses/activities' +import { getAccessTokenFromRefreshTokenCookie } from '@services/auth/auth' +import { getOrganizationContextInfoWithId } from '@services/organizations/orgs' +import SessionProvider from '@components/Contexts/SessionContext' +import EditorOptionsProvider from '@components/Contexts/Editor/EditorContext' +import AIEditorProvider from '@components/Contexts/AI/AIEditorContext' type MetadataProps = { - params: { orgslug: string, courseid: string, activityid: string }; - searchParams: { [key: string]: string | string[] | undefined }; -}; + params: { orgslug: string; courseid: string; activityid: string } + searchParams: { [key: string]: string | string[] | undefined } +} -export async function generateMetadata( - { params }: MetadataProps, -): Promise { - const cookieStore = cookies(); +export async function generateMetadata({ + params, +}: MetadataProps): Promise { + const cookieStore = cookies() const access_token = await getAccessTokenFromRefreshTokenCookie(cookieStore) - // Get Org context information - const course_meta = await getCourseMetadataWithAuthHeader(params.courseid, { revalidate: 0, tags: ['courses'] }, access_token ? access_token : null) + // Get Org context information + const course_meta = await getCourseMetadataWithAuthHeader( + params.courseid, + { revalidate: 0, tags: ['courses'] }, + access_token ? access_token : null + ) return { title: `Edit - ${course_meta.name} Activity`, description: course_meta.mini_description, - }; + } } const EditActivity = async (params: any) => { - const cookieStore = cookies(); + const cookieStore = cookies() const access_token = await getAccessTokenFromRefreshTokenCookie(cookieStore) - const activityuuid = params.params.activityuuid; - const courseid = params.params.courseid; - const courseInfo = await getCourseMetadataWithAuthHeader(courseid, { revalidate: 0, tags: ['courses'] }, access_token ? access_token : null) - const activity = await getActivityWithAuthHeader(activityuuid, { revalidate: 0, tags: ['activities'] }, access_token ? access_token : null) - const org = await getOrganizationContextInfoWithId(courseInfo.org_id, { revalidate: 1800, tags: ['organizations'] }); + const activityuuid = params.params.activityuuid + const courseid = params.params.courseid + const courseInfo = await getCourseMetadataWithAuthHeader( + courseid, + { revalidate: 0, tags: ['courses'] }, + access_token ? access_token : null + ) + const activity = await getActivityWithAuthHeader( + activityuuid, + { revalidate: 0, tags: ['activities'] }, + access_token ? access_token : null + ) + const org = await getOrganizationContextInfoWithId(courseInfo.org_id, { + revalidate: 1800, + tags: ['organizations'], + }) return ( - + - ); + ) } -export default EditActivity; +export default EditActivity diff --git a/apps/web/app/editor/main.ts b/apps/web/app/editor/main.ts index e5c583e4..8e0c8401 100644 --- a/apps/web/app/editor/main.ts +++ b/apps/web/app/editor/main.ts @@ -1 +1 @@ -export const EDITOR = "main"; +export const EDITOR = 'main' diff --git a/apps/web/app/global-error.tsx b/apps/web/app/global-error.tsx index 49bbd2bc..451e8d52 100644 --- a/apps/web/app/global-error.tsx +++ b/apps/web/app/global-error.tsx @@ -1,24 +1,24 @@ -"use client"; +'use client' -import * as Sentry from "@sentry/nextjs"; -import NextError from "next/error"; -import { useEffect } from "react"; +import * as Sentry from '@sentry/nextjs' +import NextError from 'next/error' +import { useEffect } from 'react' export default function GlobalError({ - error, + error, }: { - error: Error & { digest?: string }; + error: Error & { digest?: string } }) { - useEffect(() => { - Sentry.captureException(error); - }, [error]); + useEffect(() => { + Sentry.captureException(error) + }, [error]) - return ( - - - {/* This is the default Next.js error component but it doesn't allow omitting the statusCode property yet. */} - - - - ); -} \ No newline at end of file + return ( + + + {/* This is the default Next.js error component but it doesn't allow omitting the statusCode property yet. */} + + + + ) +} diff --git a/apps/web/app/install/install.tsx b/apps/web/app/install/install.tsx index 01039e41..d5753dd9 100644 --- a/apps/web/app/install/install.tsx +++ b/apps/web/app/install/install.tsx @@ -5,87 +5,118 @@ import GeneralWrapperStyled from '@components/StyledElements/Wrappers/GeneralWra import { useRouter, useSearchParams } from 'next/navigation' import { Suspense } from 'react' - function InstallClient() { - return ( - - - <> - - - - - ) + return ( + + + <> + + + + + ) } const Stepscomp = () => { - const searchParams = useSearchParams() - const router = useRouter() - const step: any = parseInt(searchParams.get('step') || '0'); - const [stepNumber, setStepNumber] = React.useState(step) - const [stepsState, setStepsState] = React.useState(INSTALL_STEPS) + const searchParams = useSearchParams() + const router = useRouter() + const step: any = parseInt(searchParams.get('step') || '0') + const [stepNumber, setStepNumber] = React.useState(step) + const [stepsState, setStepsState] = React.useState(INSTALL_STEPS) - function handleStepChange(stepNumber: number) { - setStepNumber(stepNumber) - router.push(`/install?step=${stepNumber}`) - } + function handleStepChange(stepNumber: number) { + setStepNumber(stepNumber) + router.push(`/install?step=${stepNumber}`) + } - useEffect(() => { - setStepNumber(step) - }, [step]) + useEffect(() => { + setStepNumber(step) + }, [step]) - return ( -
-
-
- -
-
-
- {stepsState.map((step, index) => ( -
handleStepChange(index)} - > -
- {index} -
-
{step.name}
- -
- ))} -
-
-
- -
-

{stepsState[stepNumber].name}

-
- {stepsState[stepNumber].component} -
-
+ return ( +
+
+
+
- ) +
+
+ {stepsState.map((step, index) => ( +
handleStepChange(index)} + > +
+ {index} +
+
{step.name}
+
+ ))} +
+
+
+ +
+

{stepsState[stepNumber].name}

+
{stepsState[stepNumber].component}
+
+
+ ) } const LearnHouseLogo = () => { - return ( - - - - - - - - - - - - - - ) - + return ( + + + + + + + + + + + + + + ) } -export default InstallClient \ No newline at end of file +export default InstallClient diff --git a/apps/web/app/install/page.tsx b/apps/web/app/install/page.tsx index 18b90b4d..80df7509 100644 --- a/apps/web/app/install/page.tsx +++ b/apps/web/app/install/page.tsx @@ -1,18 +1,17 @@ import React from 'react' import InstallClient from './install' - export const metadata = { - title: "Install LearnHouse", - description: "Install Learnhouse on your server", + title: 'Install LearnHouse', + description: 'Install Learnhouse on your server', } function InstallPage() { - return ( -
- -
- ) + return ( +
+ +
+ ) } -export default InstallPage \ No newline at end of file +export default InstallPage diff --git a/apps/web/app/install/steps/account_creation.tsx b/apps/web/app/install/steps/account_creation.tsx index db7fb1fd..98cc1760 100644 --- a/apps/web/app/install/steps/account_creation.tsx +++ b/apps/web/app/install/steps/account_creation.tsx @@ -1,131 +1,178 @@ -"use client"; -import FormLayout, { ButtonBlack, FormField, FormLabelAndMessage, Input } from '@components/StyledElements/Form/Form' -import * as Form from '@radix-ui/react-form'; -import { getAPIUrl } from '@services/config/config'; -import { createNewUserInstall, updateInstall } from '@services/install/install'; -import { swrFetcher } from '@services/utils/ts/requests'; -import { useFormik } from 'formik'; -import { useRouter } from 'next/navigation'; +'use client' +import FormLayout, { + ButtonBlack, + FormField, + FormLabelAndMessage, + Input, +} from '@components/StyledElements/Form/Form' +import * as Form from '@radix-ui/react-form' +import { getAPIUrl } from '@services/config/config' +import { createNewUserInstall, updateInstall } from '@services/install/install' +import { swrFetcher } from '@services/utils/ts/requests' +import { useFormik } from 'formik' +import { useRouter } from 'next/navigation' import React from 'react' -import { BarLoader } from 'react-spinners'; -import useSWR from "swr"; +import { BarLoader } from 'react-spinners' +import useSWR from 'swr' const validate = (values: any) => { - const errors: any = {}; + const errors: any = {} - if (!values.email) { - errors.email = 'Required'; - } - else if ( - !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email) - ) { - errors.email = 'Invalid email address'; - } + if (!values.email) { + errors.email = 'Required' + } else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email)) { + errors.email = 'Invalid email address' + } - if (!values.password) { - errors.password = 'Required'; - } - else if (values.password.length < 8) { - errors.password = 'Password must be at least 8 characters'; - } + if (!values.password) { + errors.password = 'Required' + } else if (values.password.length < 8) { + errors.password = 'Password must be at least 8 characters' + } - if (!values.confirmPassword) { - errors.confirmPassword = 'Required'; - } - else if (values.confirmPassword !== values.password) { - errors.confirmPassword = 'Passwords must match'; - } + if (!values.confirmPassword) { + errors.confirmPassword = 'Required' + } else if (values.confirmPassword !== values.password) { + errors.confirmPassword = 'Passwords must match' + } - if (!values.username) { - errors.username = 'Required'; - } - else if (values.username.length < 3) { - errors.username = 'Username must be at least 3 characters'; - } + if (!values.username) { + errors.username = 'Required' + } else if (values.username.length < 3) { + errors.username = 'Username must be at least 3 characters' + } - return errors; -}; - -function AccountCreation() { - const [isSubmitting, setIsSubmitting] = React.useState(false); - const { data: install, error: error, isLoading } = useSWR(`${getAPIUrl()}install/latest`, swrFetcher); - const router = useRouter( - - ) - const formik = useFormik({ - initialValues: { - org_slug: '', - email: '', - password: '', - confirmPassword: '', - username: '', - }, - validate, - onSubmit: async values => { - - let finalvalueswithoutpasswords = { ...values, password: '', confirmPassword: '', org_slug: install.data[1].slug } - let install_data_without_passwords = { ...install.data, 3: finalvalueswithoutpasswords } - await updateInstall({ ...install_data_without_passwords }, 4) - await createNewUserInstall({email:values.email,username:values.username,password:values.password},install.data[1].slug) - - // await 2 seconds - setTimeout(() => { - setIsSubmitting(false) - }, 2000) - - router.push('/install?step=4') - - }, - }); - - return ( -
- - - - - - - - {/* for password */} - - - - - - - - {/* for confirm password */} - - - - - - - - - {/* for username */} - - - - - - - - - -
- - - {isSubmitting ? - : "Create Admin Account"} - - -
- -
-
- ) + return errors } -export default AccountCreation \ No newline at end of file +function AccountCreation() { + const [isSubmitting, setIsSubmitting] = React.useState(false) + const { + data: install, + error: error, + isLoading, + } = useSWR(`${getAPIUrl()}install/latest`, swrFetcher) + const router = useRouter() + const formik = useFormik({ + initialValues: { + org_slug: '', + email: '', + password: '', + confirmPassword: '', + username: '', + }, + validate, + onSubmit: async (values) => { + let finalvalueswithoutpasswords = { + ...values, + password: '', + confirmPassword: '', + org_slug: install.data[1].slug, + } + let install_data_without_passwords = { + ...install.data, + 3: finalvalueswithoutpasswords, + } + await updateInstall({ ...install_data_without_passwords }, 4) + await createNewUserInstall( + { + email: values.email, + username: values.username, + password: values.password, + }, + install.data[1].slug + ) + + // await 2 seconds + setTimeout(() => { + setIsSubmitting(false) + }, 2000) + + router.push('/install?step=4') + }, + }) + + return ( +
+ + + + + + + + {/* for password */} + + + + + + + + {/* for confirm password */} + + + + + + + + {/* for username */} + + + + + + + + +
+ + + {isSubmitting ? ( + + ) : ( + 'Create Admin Account' + )} + + +
+
+
+ ) +} + +export default AccountCreation diff --git a/apps/web/app/install/steps/default_elements.tsx b/apps/web/app/install/steps/default_elements.tsx index 4387f7d3..53b19190 100644 --- a/apps/web/app/install/steps/default_elements.tsx +++ b/apps/web/app/install/steps/default_elements.tsx @@ -1,45 +1,49 @@ -import { getAPIUrl } from '@services/config/config'; -import { createDefaultElements, updateInstall } from '@services/install/install'; -import { swrFetcher } from '@services/utils/ts/requests'; -import { useRouter } from 'next/navigation'; +import { getAPIUrl } from '@services/config/config' +import { createDefaultElements, updateInstall } from '@services/install/install' +import { swrFetcher } from '@services/utils/ts/requests' +import { useRouter } from 'next/navigation' import React from 'react' -import useSWR from "swr"; +import useSWR from 'swr' function DefaultElements() { - const { data: install, error: error, isLoading } = useSWR(`${getAPIUrl()}install/latest`, swrFetcher); - const [isSubmitting, setIsSubmitting] = React.useState(false); - const [isSubmitted, setIsSubmitted] = React.useState(false); - const router = useRouter() + const { + data: install, + error: error, + isLoading, + } = useSWR(`${getAPIUrl()}install/latest`, swrFetcher) + const [isSubmitting, setIsSubmitting] = React.useState(false) + const [isSubmitted, setIsSubmitted] = React.useState(false) + const router = useRouter() - function createDefElementsAndUpdateInstall() { - try { - createDefaultElements() - // add an {} to the install.data object + function createDefElementsAndUpdateInstall() { + try { + createDefaultElements() + // add an {} to the install.data object - let install_data = { ...install.data, 2: { status: 'OK' } } - - updateInstall(install_data, 3) - // await 2 seconds - setTimeout(() => { - setIsSubmitting(false) - }, 2000) + let install_data = { ...install.data, 2: { status: 'OK' } } - router.push('/install?step=3') - setIsSubmitted(true) - } - catch (e) { - - } - } + updateInstall(install_data, 3) + // await 2 seconds + setTimeout(() => { + setIsSubmitting(false) + }, 2000) - return ( -
-

Install Default Elements

-
- Install -
-
- ) + router.push('/install?step=3') + setIsSubmitted(true) + } catch (e) {} + } + + return ( +
+

Install Default Elements

+
+ Install +
+
+ ) } -export default DefaultElements \ No newline at end of file +export default DefaultElements diff --git a/apps/web/app/install/steps/disable_install_mode.tsx b/apps/web/app/install/steps/disable_install_mode.tsx index 84acb6f2..c094702f 100644 --- a/apps/web/app/install/steps/disable_install_mode.tsx +++ b/apps/web/app/install/steps/disable_install_mode.tsx @@ -2,18 +2,32 @@ import { Check, Link } from 'lucide-react' import React from 'react' function DisableInstallMode() { - return ( -
-
- -
-

You have reached the end of the Installation process, please don't forget to disable installation mode.

-
+ return ( +
+
+ +
+
+

+ You have reached the end of the Installation process,{' '} + + please don't forget to disable installation mode. + {' '} +

+ - ) +
+
+ ) } -export default DisableInstallMode \ No newline at end of file +export default DisableInstallMode diff --git a/apps/web/app/install/steps/finish.tsx b/apps/web/app/install/steps/finish.tsx index be6bbc0d..8bb09fe3 100644 --- a/apps/web/app/install/steps/finish.tsx +++ b/apps/web/app/install/steps/finish.tsx @@ -1,39 +1,42 @@ -import { getAPIUrl } from '@services/config/config'; -import { updateInstall } from '@services/install/install'; -import { swrFetcher } from '@services/utils/ts/requests'; +import { getAPIUrl } from '@services/config/config' +import { updateInstall } from '@services/install/install' +import { swrFetcher } from '@services/utils/ts/requests' import { Check } from 'lucide-react' -import { useRouter } from 'next/navigation'; +import { useRouter } from 'next/navigation' import React from 'react' -import useSWR from "swr"; +import useSWR from 'swr' const Finish = () => { - const { data: install, error: error, isLoading } = useSWR(`${getAPIUrl()}install/latest`, swrFetcher); + const { + data: install, + error: error, + isLoading, + } = useSWR(`${getAPIUrl()}install/latest`, swrFetcher) const router = useRouter() async function finishInstall() { - let install_data = { ...install.data, 5: { status: 'OK' } } let data = await updateInstall(install_data, 6) if (data) { router.push('/install?step=6') - } - else { - + } else { } } return ( -
+

Installation Complete


-
+
Next Step
- ) } -export default Finish \ No newline at end of file +export default Finish diff --git a/apps/web/app/install/steps/get_started.tsx b/apps/web/app/install/steps/get_started.tsx index 91691249..1c247b97 100644 --- a/apps/web/app/install/steps/get_started.tsx +++ b/apps/web/app/install/steps/get_started.tsx @@ -1,69 +1,80 @@ -import PageLoading from '@components/Objects/Loaders/PageLoading'; -import { getAPIUrl } from '@services/config/config'; -import { swrFetcher } from '@services/utils/ts/requests'; -import { useRouter } from 'next/navigation'; +import PageLoading from '@components/Objects/Loaders/PageLoading' +import { getAPIUrl } from '@services/config/config' +import { swrFetcher } from '@services/utils/ts/requests' +import { useRouter } from 'next/navigation' import React, { useEffect } from 'react' -import useSWR, { mutate } from "swr"; +import useSWR, { mutate } from 'swr' function GetStarted() { - const { data: install, error: error, isLoading } = useSWR(`${getAPIUrl()}install/latest`, swrFetcher); - const router = useRouter() - - async function startInstallation() { - let res = await fetch(`${getAPIUrl()}install/start`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({}) - }) - - if (res.status == 200) { - mutate(`${getAPIUrl()}install/latest`) - router.refresh(); - router.push(`/install?step=1`) - } + const { + data: install, + error: error, + isLoading, + } = useSWR(`${getAPIUrl()}install/latest`, swrFetcher) + const router = useRouter() + async function startInstallation() { + let res = await fetch(`${getAPIUrl()}install/start`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({}), + }) + if (res.status == 200) { + mutate(`${getAPIUrl()}install/latest`) + router.refresh() + router.push(`/install?step=1`) } + } - function redirectToStep() { - const step = install.step - router.push(`/install?step=${step}`) - } + function redirectToStep() { + const step = install.step + router.push(`/install?step=${step}`) + } - - - useEffect(() => { - if (install) { - redirectToStep() - } - }, [install]) - - - if (error) return
-

Start a new installation

-
- Start -
-
- - if (isLoading) return + useEffect(() => { if (install) { - return ( -
-
-

You already started an installation

-
- Continue -
-
- Start -
-
-
- ) + redirectToStep() } + }, [install]) + + if (error) + return ( +
+

Start a new installation

+
+ Start +
+
+ ) + + if (isLoading) return + if (install) { + return ( +
+
+

You already started an installation

+
+ Continue +
+
+ Start +
+
+
+ ) + } } -export default GetStarted \ No newline at end of file +export default GetStarted diff --git a/apps/web/app/install/steps/org_creation.tsx b/apps/web/app/install/steps/org_creation.tsx index 0fbd3996..11ac9810 100644 --- a/apps/web/app/install/steps/org_creation.tsx +++ b/apps/web/app/install/steps/org_creation.tsx @@ -1,137 +1,166 @@ - -import FormLayout, { ButtonBlack, FormField, FormLabelAndMessage, Input } from '@components/StyledElements/Form/Form' -import * as Form from '@radix-ui/react-form'; -import { useFormik } from 'formik'; -import { BarLoader } from 'react-spinners'; +import FormLayout, { + ButtonBlack, + FormField, + FormLabelAndMessage, + Input, +} from '@components/StyledElements/Form/Form' +import * as Form from '@radix-ui/react-form' +import { useFormik } from 'formik' +import { BarLoader } from 'react-spinners' import React from 'react' -import { swrFetcher } from '@services/utils/ts/requests'; -import { getAPIUrl } from '@services/config/config'; -import useSWR from "swr"; -import { createNewOrgInstall, updateInstall } from '@services/install/install'; -import { useRouter } from 'next/navigation'; -import { Check } from 'lucide-react'; +import { swrFetcher } from '@services/utils/ts/requests' +import { getAPIUrl } from '@services/config/config' +import useSWR from 'swr' +import { createNewOrgInstall, updateInstall } from '@services/install/install' +import { useRouter } from 'next/navigation' +import { Check } from 'lucide-react' const validate = (values: any) => { - const errors: any = {}; + const errors: any = {} - if (!values.name) { - errors.name = 'Required'; - } + if (!values.name) { + errors.name = 'Required' + } - if (!values.description) { - errors.description = 'Required'; - } + if (!values.description) { + errors.description = 'Required' + } - if (!values.slug) { - errors.slug = 'Required'; - } + if (!values.slug) { + errors.slug = 'Required' + } - if (!values.email) { - errors.email = 'Required'; - } - else if ( - !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email) - ) { - errors.email = 'Invalid email address'; - } + if (!values.email) { + errors.email = 'Required' + } else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email)) { + errors.email = 'Invalid email address' + } - - - return errors; -}; - -function OrgCreation() { - const { data: install, error: error, isLoading } = useSWR(`${getAPIUrl()}install/latest`, swrFetcher); - const [isSubmitting, setIsSubmitting] = React.useState(false); - const [isSubmitted, setIsSubmitted] = React.useState(false); - const router = useRouter() - - - function createOrgAndUpdateInstall(values: any) { - try { - createNewOrgInstall(values) - install.data = { - 1: values - } - let install_data = { ...install.data, 1: values } - updateInstall(install_data, 2) - // await 2 seconds - setTimeout(() => { - setIsSubmitting(false) - }, 2000) - - router.push('/install?step=2') - setIsSubmitted(true) - } - catch (e) { - - } - - } - - const formik = useFormik({ - initialValues: { - name: '', - description: '', - slug: '', - email: '', - }, - validate, - onSubmit: values => { - createOrgAndUpdateInstall(values) - }, - }); - return ( -
- - - - - - - - - - - - - - - - - - - - - - - - - {/* for username */} - - - - - - - - - -
- - - {isSubmitting ? - : "Create Organization"} - - -
- - {isSubmitted &&
Organization Created Successfully
} - - -
-
- ) + return errors } -export default OrgCreation \ No newline at end of file +function OrgCreation() { + const { + data: install, + error: error, + isLoading, + } = useSWR(`${getAPIUrl()}install/latest`, swrFetcher) + const [isSubmitting, setIsSubmitting] = React.useState(false) + const [isSubmitted, setIsSubmitted] = React.useState(false) + const router = useRouter() + + function createOrgAndUpdateInstall(values: any) { + try { + createNewOrgInstall(values) + install.data = { + 1: values, + } + let install_data = { ...install.data, 1: values } + updateInstall(install_data, 2) + // await 2 seconds + setTimeout(() => { + setIsSubmitting(false) + }, 2000) + + router.push('/install?step=2') + setIsSubmitted(true) + } catch (e) {} + } + + const formik = useFormik({ + initialValues: { + name: '', + description: '', + slug: '', + email: '', + }, + validate, + onSubmit: (values) => { + createOrgAndUpdateInstall(values) + }, + }) + return ( +
+ + + + + + + + + + + + + + + + + + + + + + + + {/* for username */} + + + + + + + + +
+ + + {isSubmitting ? ( + + ) : ( + 'Create Organization' + )} + + +
+ + {isSubmitted && ( +
+ {' '} + Organization Created Successfully +
+ )} +
+
+ ) +} + +export default OrgCreation diff --git a/apps/web/app/install/steps/sample_data.tsx b/apps/web/app/install/steps/sample_data.tsx index 8386002f..7a174283 100644 --- a/apps/web/app/install/steps/sample_data.tsx +++ b/apps/web/app/install/steps/sample_data.tsx @@ -1,43 +1,46 @@ -import { getAPIUrl } from '@services/config/config'; -import { createSampleDataInstall, updateInstall } from '@services/install/install'; -import { swrFetcher } from '@services/utils/ts/requests'; -import { useRouter } from 'next/navigation'; +import { getAPIUrl } from '@services/config/config' +import { + createSampleDataInstall, + updateInstall, +} from '@services/install/install' +import { swrFetcher } from '@services/utils/ts/requests' +import { useRouter } from 'next/navigation' import React from 'react' -import useSWR from "swr"; +import useSWR from 'swr' function SampleData() { - const { data: install, error: error, isLoading } = useSWR(`${getAPIUrl()}install/latest`, swrFetcher); + const { + data: install, + error: error, + isLoading, + } = useSWR(`${getAPIUrl()}install/latest`, swrFetcher) const router = useRouter() function createSampleData() { - try { let username = install.data[3].username let slug = install.data[1].slug - + createSampleDataInstall(username, slug) let install_data = { ...install.data, 4: { status: 'OK' } } updateInstall(install_data, 5) router.push('/install?step=5') - - } - catch (e) { - - } + } catch (e) {} } - - return ( -
+

Install Sample data on your organization

-
+
Start
) } -export default SampleData \ No newline at end of file +export default SampleData diff --git a/apps/web/app/install/steps/steps.tsx b/apps/web/app/install/steps/steps.tsx index 2a55de13..13c2b63c 100644 --- a/apps/web/app/install/steps/steps.tsx +++ b/apps/web/app/install/steps/steps.tsx @@ -1,53 +1,52 @@ -import AccountCreation from "./account_creation"; -import DefaultElements from "./default_elements"; -import DisableInstallMode from "./disable_install_mode"; -import Finish from "./finish"; -import GetStarted from "./get_started"; -import OrgCreation from "./org_creation"; -import SampleData from "./sample_data"; +import AccountCreation from './account_creation' +import DefaultElements from './default_elements' +import DisableInstallMode from './disable_install_mode' +import Finish from './finish' +import GetStarted from './get_started' +import OrgCreation from './org_creation' +import SampleData from './sample_data' export const INSTALL_STEPS = [ { - id: "INSTALL_STATUS", - name: "Get started", + id: 'INSTALL_STATUS', + name: 'Get started', component: , completed: false, }, { - id: "ORGANIZATION_CREATION", - name: "Organization Creation", + id: 'ORGANIZATION_CREATION', + name: 'Organization Creation', component: , completed: false, }, { - id: "DEFAULT_ELEMENTS", - name: "Default Elements", + id: 'DEFAULT_ELEMENTS', + name: 'Default Elements', component: , completed: false, }, { - id: "ACCOUNT_CREATION", - name: "Account Creation", + id: 'ACCOUNT_CREATION', + name: 'Account Creation', component: , completed: false, }, { - id: "SAMPLE_DATA", - name: "Sample Data", + id: 'SAMPLE_DATA', + name: 'Sample Data', component: , completed: false, }, { - id: "FINISH", - name: "Finish", + id: 'FINISH', + name: 'Finish', component: , completed: false, - }, { - id: "DISABLING_INSTALLATION_MODE", - name: "Disabling Installation Mode", + id: 'DISABLING_INSTALLATION_MODE', + name: 'Disabling Installation Mode', component: , completed: false, }, -]; +] diff --git a/apps/web/app/layout.tsx b/apps/web/app/layout.tsx index d476f380..aedda02e 100644 --- a/apps/web/app/layout.tsx +++ b/apps/web/app/layout.tsx @@ -1,15 +1,19 @@ -"use client"; -import "../styles/globals.css"; -import StyledComponentsRegistry from "../components/Utils/libs/styled-registry"; +'use client' +import '../styles/globals.css' +import StyledComponentsRegistry from '../components/Utils/libs/styled-registry' -import { motion } from "framer-motion"; +import { motion } from 'framer-motion' -export default function RootLayout({ children }: { children: React.ReactNode }) { +export default function RootLayout({ + children, +}: { + children: React.ReactNode +}) { const variants = { hidden: { opacity: 0, x: 0, y: 0 }, enter: { opacity: 1, x: 0, y: 0 }, exit: { opacity: 0, x: 0, y: 0 }, - }; + } return ( @@ -20,7 +24,7 @@ export default function RootLayout({ children }: { children: React.ReactNode }) initial="hidden" // Set the initial state to variants.hidden animate="enter" // Animated state to variants.enter exit="exit" // Exit state (used later) to variants.exit - transition={{ type: "linear" }} // Set the transition to linear + transition={{ type: 'linear' }} // Set the transition to linear className="" > {children} @@ -28,5 +32,5 @@ export default function RootLayout({ children }: { children: React.ReactNode }) - ); + ) } diff --git a/apps/web/app/organizations/new/page.tsx b/apps/web/app/organizations/new/page.tsx index 31326904..800bc838 100644 --- a/apps/web/app/organizations/new/page.tsx +++ b/apps/web/app/organizations/new/page.tsx @@ -1,40 +1,47 @@ -"use client"; -import React from "react"; -import { createNewOrganization } from "../../../services/organizations/orgs"; +'use client' +import React from 'react' +import { createNewOrganization } from '../../../services/organizations/orgs' const Organizations = () => { - const [name, setName] = React.useState(""); - const [description, setDescription] = React.useState(""); - const [email, setEmail] = React.useState(""); - const [slug, setSlug] = React.useState(""); + const [name, setName] = React.useState('') + const [description, setDescription] = React.useState('') + const [email, setEmail] = React.useState('') + const [slug, setSlug] = React.useState('') const handleNameChange = (e: any) => { - setName(e.target.value); - }; + setName(e.target.value) + } const handleDescriptionChange = (e: any) => { - setDescription(e.target.value); - }; + setDescription(e.target.value) + } const handleEmailChange = (e: any) => { - setEmail(e.target.value); - }; + setEmail(e.target.value) + } const handleSlugChange = (e: any) => { - setSlug(e.target.value); - }; + setSlug(e.target.value) + } const handleSubmit = async (e: any) => { - e.preventDefault(); - + e.preventDefault() + let logo = '' - const status = await createNewOrganization({ name, description, email, logo, slug, default: false }); - alert(JSON.stringify(status)); - }; + const status = await createNewOrganization({ + name, + description, + email, + logo, + slug, + default: false, + }) + alert(JSON.stringify(status)) + } return (
-
New Organization
+
New Organization
Name:
Description: @@ -45,7 +52,7 @@ const Organizations = () => {
- ); -}; + ) +} -export default Organizations; +export default Organizations diff --git a/apps/web/app/organizations/page.tsx b/apps/web/app/organizations/page.tsx index 00120e03..ae2b9e18 100644 --- a/apps/web/app/organizations/page.tsx +++ b/apps/web/app/organizations/page.tsx @@ -1,23 +1,30 @@ -"use client"; //todo: use server components -import Link from "next/link"; -import React from "react"; -import { deleteOrganizationFromBackend } from "@services/organizations/orgs"; -import useSWR, { mutate } from "swr"; -import { swrFetcher } from "@services/utils/ts/requests"; -import { getAPIUrl, getUriWithOrg } from "@services/config/config"; +'use client' //todo: use server components +import Link from 'next/link' +import React from 'react' +import { deleteOrganizationFromBackend } from '@services/organizations/orgs' +import useSWR, { mutate } from 'swr' +import { swrFetcher } from '@services/utils/ts/requests' +import { getAPIUrl, getUriWithOrg } from '@services/config/config' const Organizations = () => { - const { data: organizations, error } = useSWR(`${getAPIUrl()}orgs/user/page/1/limit/10`, swrFetcher) + const { data: organizations, error } = useSWR( + `${getAPIUrl()}orgs/user/page/1/limit/10`, + swrFetcher + ) async function deleteOrganization(org_id: any) { - const response = await deleteOrganizationFromBackend(org_id); - response && mutate(`${getAPIUrl()}orgs/user/page/1/limit/10`, organizations.filter((org: any) => org.org_id !== org_id)); + const response = await deleteOrganizationFromBackend(org_id) + response && + mutate( + `${getAPIUrl()}orgs/user/page/1/limit/10`, + organizations.filter((org: any) => org.org_id !== org_id) + ) } return ( <>
- Your Organizations{" "} + Your Organizations{' '}
)} - - ); -}; + ) +} -export default Organizations; +export default Organizations diff --git a/apps/web/app/orgs/[orgslug]/(withmenu)/collection/[collectionid]/error.tsx b/apps/web/app/orgs/[orgslug]/(withmenu)/collection/[collectionid]/error.tsx index 8bac23db..d5320406 100644 --- a/apps/web/app/orgs/[orgslug]/(withmenu)/collection/[collectionid]/error.tsx +++ b/apps/web/app/orgs/[orgslug]/(withmenu)/collection/[collectionid]/error.tsx @@ -1,23 +1,23 @@ -'use client'; // Error components must be Client Components +'use client' // Error components must be Client Components + +import ErrorUI from '@components/StyledElements/Error/Error' +import { useEffect } from 'react' -import ErrorUI from '@components/StyledElements/Error/Error'; -import { useEffect } from 'react'; - export default function Error({ error, reset, }: { - error: Error; - reset: () => void; + error: Error + reset: () => void }) { useEffect(() => { // Log the error to an error reporting service - console.error(error); - }, [error]); - + console.error(error) + }, [error]) + return (
- ); -} \ No newline at end of file + ) +} diff --git a/apps/web/app/orgs/[orgslug]/(withmenu)/collection/[collectionid]/loading.tsx b/apps/web/app/orgs/[orgslug]/(withmenu)/collection/[collectionid]/loading.tsx index ec352ab7..58f6f7df 100644 --- a/apps/web/app/orgs/[orgslug]/(withmenu)/collection/[collectionid]/loading.tsx +++ b/apps/web/app/orgs/[orgslug]/(withmenu)/collection/[collectionid]/loading.tsx @@ -1,8 +1,5 @@ -import PageLoading from "@components/Objects/Loaders/PageLoading"; +import PageLoading from '@components/Objects/Loaders/PageLoading' export default function Loading() { - return ( - - ) - -} \ No newline at end of file + return +} diff --git a/apps/web/app/orgs/[orgslug]/(withmenu)/collection/[collectionid]/page.tsx b/apps/web/app/orgs/[orgslug]/(withmenu)/collection/[collectionid]/page.tsx index 1609be04..a93d57d9 100644 --- a/apps/web/app/orgs/[orgslug]/(withmenu)/collection/[collectionid]/page.tsx +++ b/apps/web/app/orgs/[orgslug]/(withmenu)/collection/[collectionid]/page.tsx @@ -1,27 +1,34 @@ -import GeneralWrapperStyled from "@components/StyledElements/Wrappers/GeneralWrapper"; -import { getAccessTokenFromRefreshTokenCookie } from "@services/auth/auth"; -import { getUriWithOrg } from "@services/config/config"; -import { getCollectionByIdWithAuthHeader } from "@services/courses/collections"; -import { getCourseThumbnailMediaDirectory } from "@services/media/media"; -import { getOrganizationContextInfo } from "@services/organizations/orgs"; -import { Metadata } from "next"; -import { cookies } from "next/headers"; -import Link from "next/link"; +import GeneralWrapperStyled from '@components/StyledElements/Wrappers/GeneralWrapper' +import { getAccessTokenFromRefreshTokenCookie } from '@services/auth/auth' +import { getUriWithOrg } from '@services/config/config' +import { getCollectionByIdWithAuthHeader } from '@services/courses/collections' +import { getCourseThumbnailMediaDirectory } from '@services/media/media' +import { getOrganizationContextInfo } from '@services/organizations/orgs' +import { Metadata } from 'next' +import { cookies } from 'next/headers' +import Link from 'next/link' type MetadataProps = { - params: { orgslug: string, courseid: string, collectionid: string }; - searchParams: { [key: string]: string | string[] | undefined }; -}; + params: { orgslug: string; courseid: string; collectionid: string } + searchParams: { [key: string]: string | string[] | undefined } +} -export async function generateMetadata( - { params }: MetadataProps, -): Promise { - const cookieStore = cookies(); +export async function generateMetadata({ + params, +}: MetadataProps): Promise { + const cookieStore = cookies() const access_token = await getAccessTokenFromRefreshTokenCookie(cookieStore) - // Get Org context information - const org = await getOrganizationContextInfo(params.orgslug, { revalidate: 1800, tags: ['organizations'] }); - const col = await getCollectionByIdWithAuthHeader(params.collectionid, access_token ? access_token : null, { revalidate: 0, tags: ['collections'] }); + // Get Org context information + const org = await getOrganizationContextInfo(params.orgslug, { + revalidate: 1800, + tags: ['organizations'], + }) + const col = await getCollectionByIdWithAuthHeader( + params.collectionid, + access_token ? access_token : null, + { revalidate: 0, tags: ['collections'] } + ) // SEO return { @@ -34,48 +41,66 @@ export async function generateMetadata( googleBot: { index: true, follow: true, - "max-image-preview": "large", - } + 'max-image-preview': 'large', + }, }, openGraph: { title: `Collection : ${col.name} — ${org.name}`, description: `${col.description} `, type: 'website', }, - }; + } } const CollectionPage = async (params: any) => { - const cookieStore = cookies(); + const cookieStore = cookies() const access_token = await getAccessTokenFromRefreshTokenCookie(cookieStore) - const org = await getOrganizationContextInfo(params.params.orgslug, { revalidate: 1800, tags: ['organizations'] }); - const orgslug = params.params.orgslug; - const col = await getCollectionByIdWithAuthHeader(params.params.collectionid, access_token ? access_token : null, { revalidate: 0, tags: ['collections'] }); + const org = await getOrganizationContextInfo(params.params.orgslug, { + revalidate: 1800, + tags: ['organizations'], + }) + const orgslug = params.params.orgslug + const col = await getCollectionByIdWithAuthHeader( + params.params.collectionid, + access_token ? access_token : null, + { revalidate: 0, tags: ['collections'] } + ) const removeCoursePrefix = (courseid: string) => { - return courseid.replace("course_", "") + return courseid.replace('course_', '') } + return ( + +

Collection

+

{col.name}

+
+
+ {col.courses.map((course: any) => ( +
+ +
+ +

{course.name}

+
+ ))} +
+
+ ) +} - return -

Collection

-

{col.name}

-
-
- {col.courses.map((course: any) => ( -
- -
-
- -

{course.name}

-
- ))} -
- - - -
; -}; - -export default CollectionPage; \ No newline at end of file +export default CollectionPage diff --git a/apps/web/app/orgs/[orgslug]/(withmenu)/collections/loading.tsx b/apps/web/app/orgs/[orgslug]/(withmenu)/collections/loading.tsx index 3f902486..3da44848 100644 --- a/apps/web/app/orgs/[orgslug]/(withmenu)/collections/loading.tsx +++ b/apps/web/app/orgs/[orgslug]/(withmenu)/collections/loading.tsx @@ -1,9 +1,6 @@ -import PageLoading from "@components/Objects/Loaders/PageLoading"; +import PageLoading from '@components/Objects/Loaders/PageLoading' export default function Loading() { - // Or a custom loading skeleton component - return ( - - ) - -} \ No newline at end of file + // Or a custom loading skeleton component + return +} diff --git a/apps/web/app/orgs/[orgslug]/(withmenu)/collections/new/page.tsx b/apps/web/app/orgs/[orgslug]/(withmenu)/collections/new/page.tsx index b36f368b..77708f79 100644 --- a/apps/web/app/orgs/[orgslug]/(withmenu)/collections/new/page.tsx +++ b/apps/web/app/orgs/[orgslug]/(withmenu)/collections/new/page.tsx @@ -1,37 +1,41 @@ -"use client"; -import { useRouter } from "next/navigation"; -import React, { useState } from "react"; -import { createCollection } from "@services/courses/collections"; -import useSWR from "swr"; -import { getAPIUrl, getUriWithOrg } from "@services/config/config"; -import { revalidateTags, swrFetcher } from "@services/utils/ts/requests"; -import { useOrg } from "@components/Contexts/OrgContext"; +'use client' +import { useRouter } from 'next/navigation' +import React, { useState } from 'react' +import { createCollection } from '@services/courses/collections' +import useSWR from 'swr' +import { getAPIUrl, getUriWithOrg } from '@services/config/config' +import { revalidateTags, swrFetcher } from '@services/utils/ts/requests' +import { useOrg } from '@components/Contexts/OrgContext' function NewCollection(params: any) { - const org = useOrg() as any; - const orgslug = params.params.orgslug; - const [name, setName] = React.useState(""); - const [description, setDescription] = React.useState(""); - const [selectedCourses, setSelectedCourses] = React.useState([]) as any; - const router = useRouter(); - const { data: courses, error: error } = useSWR(`${getAPIUrl()}courses/org_slug/${orgslug}/page/1/limit/10`, swrFetcher); - const [isPublic, setIsPublic] = useState('true'); + const org = useOrg() as any + const orgslug = params.params.orgslug + const [name, setName] = React.useState('') + const [description, setDescription] = React.useState('') + const [selectedCourses, setSelectedCourses] = React.useState([]) as any + const router = useRouter() + const { data: courses, error: error } = useSWR( + `${getAPIUrl()}courses/org_slug/${orgslug}/page/1/limit/10`, + swrFetcher + ) + const [isPublic, setIsPublic] = useState('true') const handleVisibilityChange = (e: React.ChangeEvent) => { - setIsPublic(e.target.value); - }; - + setIsPublic(e.target.value) + } const handleNameChange = (event: React.ChangeEvent) => { - setName(event.target.value); - }; + setName(event.target.value) + } - const handleDescriptionChange = (event: React.ChangeEvent) => { - setDescription(event.target.value); - }; + const handleDescriptionChange = ( + event: React.ChangeEvent + ) => { + setDescription(event.target.value) + } const handleSubmit = async (e: any) => { - e.preventDefault(); + e.preventDefault() const collection = { name: name, @@ -39,19 +43,17 @@ function NewCollection(params: any) { courses: selectedCourses, public: isPublic, org_id: org.id, - }; - await createCollection(collection); - await revalidateTags(["collections"], org.slug); + } + await createCollection(collection) + await revalidateTags(['collections'], org.slug) // reload the page - router.refresh(); + router.refresh() // wait for 2s before reloading the page setTimeout(() => { - router.push(getUriWithOrg(orgslug, "/collections")); - } - , 1000); - }; - + router.push(getUriWithOrg(orgslug, '/collections')) + }, 1000) + } return ( <> @@ -75,36 +77,46 @@ function NewCollection(params: any) { - {!courses ? ( -

Loading...

-) : ( -
-

Courses

- {courses.map((course: any) => ( -
+

Loading...

+ ) : ( +
+

Courses

+ {courses.map((course: any) => ( +
+ { + if (e.target.checked) { + setSelectedCourses([...selectedCourses, course.id]) + } else { + setSelectedCourses( + selectedCourses.filter( + (course_uuid: any) => + course_uuid !== course.course_uuid + ) + ) + } + }} + className="text-blue-500 rounded focus:ring-2 focus:ring-blue-500" + /> - { - if (e.target.checked) { - setSelectedCourses([...selectedCourses, course.id]); - } - else { - setSelectedCourses(selectedCourses.filter((course_uuid: any) => course_uuid !== course.course_uuid)); - } - }} - className="text-blue-500 rounded focus:ring-2 focus:ring-blue-500" - /> - - -
- ))} -
-)} + +
+ ))} +
+ )}
- - ); + ) } -export default NewCollection; +export default NewCollection diff --git a/apps/web/app/orgs/[orgslug]/(withmenu)/collections/page.tsx b/apps/web/app/orgs/[orgslug]/(withmenu)/collections/page.tsx index 7a65ca2c..a6c14011 100644 --- a/apps/web/app/orgs/[orgslug]/(withmenu)/collections/page.tsx +++ b/apps/web/app/orgs/[orgslug]/(withmenu)/collections/page.tsx @@ -1,103 +1,151 @@ -import AuthenticatedClientElement from "@components/Security/AuthenticatedClientElement"; -import TypeOfContentTitle from "@components/StyledElements/Titles/TypeOfContentTitle"; -import GeneralWrapperStyled from "@components/StyledElements/Wrappers/GeneralWrapper"; -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 { getAccessTokenFromRefreshTokenCookie } from "@services/auth/auth"; -import CollectionThumbnail from "@components/Objects/Thumbnails/CollectionThumbnail"; -import NewCollectionButton from "@components/StyledElements/Buttons/NewCollectionButton"; +import AuthenticatedClientElement from '@components/Security/AuthenticatedClientElement' +import TypeOfContentTitle from '@components/StyledElements/Titles/TypeOfContentTitle' +import GeneralWrapperStyled from '@components/StyledElements/Wrappers/GeneralWrapper' +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 { getAccessTokenFromRefreshTokenCookie } from '@services/auth/auth' +import CollectionThumbnail from '@components/Objects/Thumbnails/CollectionThumbnail' +import NewCollectionButton from '@components/StyledElements/Buttons/NewCollectionButton' type MetadataProps = { - params: { orgslug: string, courseid: string }; - searchParams: { [key: string]: string | string[] | undefined }; -}; + params: { orgslug: string; courseid: string } + searchParams: { [key: string]: string | string[] | undefined } +} -export async function generateMetadata( - { params }: MetadataProps, -): Promise { - // Get Org context information - const org = await getOrganizationContextInfo(params.orgslug, { revalidate: 1800, tags: ['organizations'] }); +export async function generateMetadata({ + params, +}: MetadataProps): Promise { + // Get Org context information + const org = await getOrganizationContextInfo(params.orgslug, { + revalidate: 1800, + tags: ['organizations'], + }) - // SEO - return { - title: `Collections — ${org.name}`, - description: `Collections of courses from ${org.name}`, - robots: { - index: true, - follow: true, - nocache: true, - googleBot: { - index: true, - follow: true, - "max-image-preview": "large", - } - }, - openGraph: { - title: `Collections — ${org.name}`, - description: `Collections of courses from ${org.name}`, - type: 'website', - }, - }; + // SEO + return { + title: `Collections — ${org.name}`, + description: `Collections of courses from ${org.name}`, + robots: { + index: true, + follow: true, + nocache: true, + googleBot: { + index: true, + follow: true, + 'max-image-preview': 'large', + }, + }, + openGraph: { + title: `Collections — ${org.name}`, + description: `Collections of courses from ${org.name}`, + type: 'website', + }, + } } const CollectionsPage = async (params: any) => { - const cookieStore = cookies(); - const access_token = await getAccessTokenFromRefreshTokenCookie(cookieStore) - const orgslug = params.params.orgslug; - const org = await getOrganizationContextInfo(orgslug, { revalidate: 1800, tags: ['organizations'] }); - const org_id = org.id; - const collections = await getOrgCollectionsWithAuthHeader(org_id, access_token ? access_token : null, { revalidate: 0, tags: ['collections'] }); + const cookieStore = cookies() + const access_token = await getAccessTokenFromRefreshTokenCookie(cookieStore) + const orgslug = params.params.orgslug + const org = await getOrganizationContextInfo(orgslug, { + revalidate: 1800, + tags: ['organizations'], + }) + const org_id = org.id + const collections = await getOrgCollectionsWithAuthHeader( + org_id, + access_token ? access_token : null, + { revalidate: 0, tags: ['collections'] } + ) - return ( - -
- - - - - - + return ( + +
+ + + + + + +
+
+ {collections.map((collection: any) => ( +
+ +
+ ))} + {collections.length == 0 && ( +
+
+
+ + + + +
+
+

+ No collections yet +

+

+ Create a collection to group courses together +

+
+ + + + +
-
- {collections.map((collection: any) => ( -
- -
- ))} - {collections.length == 0 && -
-
-
- - - - -
-
-

No collections yet

-

Create a collection to group courses together

-
- - - - - -
-
- } -
- - ); +
+ )} +
+
+ ) } -export default CollectionsPage \ No newline at end of file +export default CollectionsPage diff --git a/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/activity.tsx b/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/activity.tsx index 631039fb..f7c91833 100644 --- a/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/activity.tsx +++ b/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/activity.tsx @@ -1,53 +1,50 @@ -"use client"; -import Link from "next/link"; -import { getUriWithOrg } from "@services/config/config"; -import Canva from "@components/Objects/Activities/DynamicCanva/DynamicCanva"; -import VideoActivity from "@components/Objects/Activities/Video/Video"; -import { Check, MoreVertical } from "lucide-react"; -import { markActivityAsComplete } from "@services/courses/activity"; -import DocumentPdfActivity from "@components/Objects/Activities/DocumentPdf/DocumentPdf"; -import ActivityIndicators from "@components/Pages/Courses/ActivityIndicators"; -import GeneralWrapperStyled from "@components/StyledElements/Wrappers/GeneralWrapper"; -import { useRouter } from "next/navigation"; -import AuthenticatedClientElement from "@components/Security/AuthenticatedClientElement"; -import { getCourseThumbnailMediaDirectory } from "@services/media/media"; -import { useOrg } from "@components/Contexts/OrgContext"; -import { CourseProvider } from "@components/Contexts/CourseContext"; -import AIActivityAsk from "@components/Objects/Activities/AI/AIActivityAsk"; -import AIChatBotProvider from "@components/Contexts/AI/AIChatBotContext"; +'use client' +import Link from 'next/link' +import { getUriWithOrg } from '@services/config/config' +import Canva from '@components/Objects/Activities/DynamicCanva/DynamicCanva' +import VideoActivity from '@components/Objects/Activities/Video/Video' +import { Check, MoreVertical } from 'lucide-react' +import { markActivityAsComplete } from '@services/courses/activity' +import DocumentPdfActivity from '@components/Objects/Activities/DocumentPdf/DocumentPdf' +import ActivityIndicators from '@components/Pages/Courses/ActivityIndicators' +import GeneralWrapperStyled from '@components/StyledElements/Wrappers/GeneralWrapper' +import { useRouter } from 'next/navigation' +import AuthenticatedClientElement from '@components/Security/AuthenticatedClientElement' +import { getCourseThumbnailMediaDirectory } from '@services/media/media' +import { useOrg } from '@components/Contexts/OrgContext' +import { CourseProvider } from '@components/Contexts/CourseContext' +import AIActivityAsk from '@components/Objects/Activities/AI/AIActivityAsk' +import AIChatBotProvider from '@components/Contexts/AI/AIChatBotContext' interface ActivityClientProps { - activityid: string; - courseuuid: string; - orgslug: string; - activity: any; - course: any; + activityid: string + courseuuid: string + orgslug: string + activity: any + course: any } - function ActivityClient(props: ActivityClientProps) { - const activityid = props.activityid; - const courseuuid = props.courseuuid; - const orgslug = props.orgslug; - const activity = props.activity; - const course = props.course; - const org = useOrg() as any; + const activityid = props.activityid + const courseuuid = props.courseuuid + const orgslug = props.orgslug + const activity = props.activity + const course = props.course + const org = useOrg() as any function getChapterNameByActivityId(course: any, activity_id: any) { for (let i = 0; i < course.chapters.length; i++) { - let chapter = course.chapters[i]; + let chapter = course.chapters[i] for (let j = 0; j < chapter.activities.length; j++) { - let activity = chapter.activities[j]; + let activity = chapter.activities[j] if (activity.id === activity_id) { - return chapter.name; + return chapter.name } } } - return null; // return null if no matching activity is found + return null // return null if no matching activity is found } - - return ( <> @@ -56,90 +53,147 @@ function ActivityClient(props: ActivityClientProps) {
- - + +

Course

-

{course.name}

+

+ {course.name} +

- +
-

Chapter : {getChapterNameByActivityId(course, activity.id)}

-

{activity.name}

+

+ Chapter : {getChapterNameByActivityId(course, activity.id)} +

+

+ {activity.name} +

- +
{activity ? ( -
+
- {activity.activity_type == "TYPE_DYNAMIC" && } + {activity.activity_type == 'TYPE_DYNAMIC' && ( + + )} {/* todo : use apis & streams instead of this */} - {activity.activity_type == "TYPE_VIDEO" && } - {activity.activity_type == "TYPE_DOCUMENT" && } + {activity.activity_type == 'TYPE_VIDEO' && ( + + )} + {activity.activity_type == 'TYPE_DOCUMENT' && ( + + )}
- ) : (
)} - {
} + ) : ( +
+ )} + {
}
- ); -} - - - -export function MarkStatus(props: { activity: any, activityid: string, course: any, orgslug: string }) { - const router = useRouter(); - console.log(props.course.trail) - - async function markActivityAsCompleteFront() { - const trail = await markActivityAsComplete(props.orgslug, props.course.course_uuid, 'activity_' + props.activityid); - router.refresh(); - } - - const isActivityCompleted = () => { - let run = props.course.trail.runs.find((run: any) => run.course_id == props.course.id); - if (run) { - return run.steps.find((step: any) => step.activity_id == props.activity.id); - } - } - - console.log('isActivityCompleted', isActivityCompleted()); - - return ( - <>{isActivityCompleted() ? ( -
- - - {" "} - Already completed -
- ) : ( -
- {" "} - - - {" "} - Mark as complete -
- )} ) } +export function MarkStatus(props: { + activity: any + activityid: string + course: any + orgslug: string +}) { + const router = useRouter() + console.log(props.course.trail) + async function markActivityAsCompleteFront() { + const trail = await markActivityAsComplete( + props.orgslug, + props.course.course_uuid, + 'activity_' + props.activityid + ) + router.refresh() + } -export default ActivityClient; + const isActivityCompleted = () => { + let run = props.course.trail.runs.find( + (run: any) => run.course_id == props.course.id + ) + if (run) { + return run.steps.find( + (step: any) => step.activity_id == props.activity.id + ) + } + } + + console.log('isActivityCompleted', isActivityCompleted()) + + return ( + <> + {isActivityCompleted() ? ( +
+ + + {' '} + Already completed +
+ ) : ( +
+ {' '} + + + {' '} + Mark as complete +
+ )} + + ) +} + +export default ActivityClient diff --git a/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/error.tsx b/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/error.tsx index 8bac23db..d5320406 100644 --- a/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/error.tsx +++ b/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/error.tsx @@ -1,23 +1,23 @@ -'use client'; // Error components must be Client Components +'use client' // Error components must be Client Components + +import ErrorUI from '@components/StyledElements/Error/Error' +import { useEffect } from 'react' -import ErrorUI from '@components/StyledElements/Error/Error'; -import { useEffect } from 'react'; - export default function Error({ error, reset, }: { - error: Error; - reset: () => void; + error: Error + reset: () => void }) { useEffect(() => { // Log the error to an error reporting service - console.error(error); - }, [error]); - + console.error(error) + }, [error]) + return (
- ); -} \ No newline at end of file + ) +} diff --git a/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/loading.tsx b/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/loading.tsx index 3f902486..3da44848 100644 --- a/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/loading.tsx +++ b/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/loading.tsx @@ -1,9 +1,6 @@ -import PageLoading from "@components/Objects/Loaders/PageLoading"; +import PageLoading from '@components/Objects/Loaders/PageLoading' export default function Loading() { - // Or a custom loading skeleton component - return ( - - ) - -} \ No newline at end of file + // Or a custom loading skeleton component + return +} diff --git a/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/page.tsx b/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/page.tsx index f81abeb7..1cf87b7f 100644 --- a/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/page.tsx +++ b/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/page.tsx @@ -1,71 +1,90 @@ -import { getActivityWithAuthHeader } from "@services/courses/activities"; -import { getCourseMetadataWithAuthHeader } from "@services/courses/courses"; -import { cookies } from "next/headers"; -import ActivityClient from "./activity"; -import { getOrganizationContextInfo } from "@services/organizations/orgs"; -import { Metadata } from "next"; -import { getAccessTokenFromRefreshTokenCookie } from "@services/auth/auth"; - +import { getActivityWithAuthHeader } from '@services/courses/activities' +import { getCourseMetadataWithAuthHeader } from '@services/courses/courses' +import { cookies } from 'next/headers' +import ActivityClient from './activity' +import { getOrganizationContextInfo } from '@services/organizations/orgs' +import { Metadata } from 'next' +import { getAccessTokenFromRefreshTokenCookie } from '@services/auth/auth' type MetadataProps = { - params: { orgslug: string, courseuuid: string, activityid: string }; - searchParams: { [key: string]: string | string[] | undefined }; -}; + params: { orgslug: string; courseuuid: string; activityid: string } + searchParams: { [key: string]: string | string[] | undefined } +} -export async function generateMetadata( - { params }: MetadataProps, -): Promise { - const cookieStore = cookies(); - const access_token = await getAccessTokenFromRefreshTokenCookie(cookieStore) +export async function generateMetadata({ + params, +}: MetadataProps): Promise { + const cookieStore = cookies() + const access_token = await getAccessTokenFromRefreshTokenCookie(cookieStore) - // Get Org context information - const org = await getOrganizationContextInfo(params.orgslug, { revalidate: 1800, tags: ['organizations'] }); - const course_meta = await getCourseMetadataWithAuthHeader(params.courseuuid, { revalidate: 0, tags: ['courses'] }, access_token ? access_token : null) - const activity = await getActivityWithAuthHeader(params.activityid, { revalidate: 0, tags: ['activities'] }, access_token ? access_token : null) + // Get Org context information + const org = await getOrganizationContextInfo(params.orgslug, { + revalidate: 1800, + tags: ['organizations'], + }) + const course_meta = await getCourseMetadataWithAuthHeader( + params.courseuuid, + { revalidate: 0, tags: ['courses'] }, + access_token ? access_token : null + ) + const activity = await getActivityWithAuthHeader( + params.activityid, + { revalidate: 0, tags: ['activities'] }, + access_token ? access_token : null + ) - // SEO - return { - title: activity.name + ` — ${course_meta.name} Course`, - description: course_meta.description, - keywords: course_meta.learnings, - robots: { - index: true, - follow: true, - nocache: true, - googleBot: { - index: true, - follow: true, - "max-image-preview": "large", - } - }, - openGraph: { - title: activity.name + ` — ${course_meta.name} Course`, - description: course_meta.description, - publishedTime: course_meta.creation_date, - tags: course_meta.learnings, - }, - }; + // SEO + return { + title: activity.name + ` — ${course_meta.name} Course`, + description: course_meta.description, + keywords: course_meta.learnings, + robots: { + index: true, + follow: true, + nocache: true, + googleBot: { + index: true, + follow: true, + 'max-image-preview': 'large', + }, + }, + openGraph: { + title: activity.name + ` — ${course_meta.name} Course`, + description: course_meta.description, + publishedTime: course_meta.creation_date, + tags: course_meta.learnings, + }, + } } const ActivityPage = async (params: any) => { - const cookieStore = cookies(); - const access_token = await getAccessTokenFromRefreshTokenCookie(cookieStore) - const activityid = params.params.activityid; - const courseuuid = params.params.courseuuid; - const orgslug = params.params.orgslug; + const cookieStore = cookies() + const access_token = await getAccessTokenFromRefreshTokenCookie(cookieStore) + const activityid = params.params.activityid + const courseuuid = params.params.courseuuid + const orgslug = params.params.orgslug - const course_meta = await getCourseMetadataWithAuthHeader(courseuuid, { revalidate: 0, tags: ['courses'] }, access_token ? access_token : null) - const activity = await getActivityWithAuthHeader(activityid, { revalidate: 0, tags: ['activities'] }, access_token ? access_token : null) - return ( - <> - - ) + const course_meta = await getCourseMetadataWithAuthHeader( + courseuuid, + { revalidate: 0, tags: ['courses'] }, + access_token ? access_token : null + ) + const activity = await getActivityWithAuthHeader( + activityid, + { revalidate: 0, tags: ['activities'] }, + access_token ? access_token : null + ) + return ( + <> + + + ) } -export default ActivityPage \ No newline at end of file +export default ActivityPage diff --git a/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/course.tsx b/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/course.tsx index a95fe4c0..3890ee6d 100644 --- a/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/course.tsx +++ b/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/course.tsx @@ -1,63 +1,66 @@ -"use client"; -import { removeCourse, startCourse } from "@services/courses/activity"; -import Link from "next/link"; -import React, { useEffect, useState } from "react"; -import { getUriWithOrg } from "@services/config/config"; -import PageLoading from "@components/Objects/Loaders/PageLoading"; -import { revalidateTags } from "@services/utils/ts/requests"; -import ActivityIndicators from "@components/Pages/Courses/ActivityIndicators"; -import { useRouter } from "next/navigation"; -import GeneralWrapperStyled from "@components/StyledElements/Wrappers/GeneralWrapper"; -import { getCourseThumbnailMediaDirectory, getUserAvatarMediaDirectory } from "@services/media/media"; -import { ArrowRight, Check, File, Sparkles, Video } from "lucide-react"; -import { useOrg } from "@components/Contexts/OrgContext"; -import UserAvatar from "@components/Objects/UserAvatar"; +'use client' +import { removeCourse, startCourse } from '@services/courses/activity' +import Link from 'next/link' +import React, { useEffect, useState } from 'react' +import { getUriWithOrg } from '@services/config/config' +import PageLoading from '@components/Objects/Loaders/PageLoading' +import { revalidateTags } from '@services/utils/ts/requests' +import ActivityIndicators from '@components/Pages/Courses/ActivityIndicators' +import { useRouter } from 'next/navigation' +import GeneralWrapperStyled from '@components/StyledElements/Wrappers/GeneralWrapper' +import { + getCourseThumbnailMediaDirectory, + getUserAvatarMediaDirectory, +} from '@services/media/media' +import { ArrowRight, Check, File, Sparkles, Video } from 'lucide-react' +import { useOrg } from '@components/Contexts/OrgContext' +import UserAvatar from '@components/Objects/UserAvatar' const CourseClient = (props: any) => { - const [user, setUser] = useState({}); - const [learnings, setLearnings] = useState([]); - const courseuuid = props.courseuuid; - const orgslug = props.orgslug; - const course = props.course; - const org = useOrg() as any; - const router = useRouter(); + const [user, setUser] = useState({}) + const [learnings, setLearnings] = useState([]) + const courseuuid = props.courseuuid + const orgslug = props.orgslug + const course = props.course + const org = useOrg() as any + const router = useRouter() function getLearningTags() { // create array of learnings from a string object (comma separated) - let learnings = course?.learnings ? course?.learnings.split(",") : []; - setLearnings(learnings); - + let learnings = course?.learnings ? course?.learnings.split(',') : [] + setLearnings(learnings) } - async function startCourseUI() { // Create activity - await startCourse("course_" + courseuuid, orgslug); - await revalidateTags(['courses'], orgslug); - router.refresh(); + await startCourse('course_' + courseuuid, orgslug) + await revalidateTags(['courses'], orgslug) + router.refresh() // refresh page (FIX for Next.js BUG) // window.location.reload(); } function isCourseStarted() { - const runs = course.trail?.runs; - if (!runs) return false; - return runs.some((run: any) => run.status === "STATUS_IN_PROGRESS" && run.course_id === course.id); + const runs = course.trail?.runs + if (!runs) return false + return runs.some( + (run: any) => + run.status === 'STATUS_IN_PROGRESS' && run.course_id === course.id + ) } async function quitCourse() { // Close activity - let activity = await removeCourse("course_" + courseuuid, orgslug); + let activity = await removeCourse('course_' + courseuuid, orgslug) // Mutate course - await revalidateTags(['courses'], orgslug); - router.refresh(); + await revalidateTags(['courses'], orgslug) + router.refresh() } useEffect(() => { - getLearningTags(); - } - , [org, course]); + getLearningTags() + }, [org, course]) return ( <> @@ -67,20 +70,35 @@ const CourseClient = (props: any) => {

Course

-

- {course.name} -

+

{course.name}

- {props.course?.thumbnail_image && org ? -
-
- : -
-
- } + {props.course?.thumbnail_image && org ? ( +
+ ) : ( +
+ )} - +
@@ -89,143 +107,223 @@ const CourseClient = (props: any) => {

{course.description}

- {learnings.length > 0 && learnings[0] !== "null" && + {learnings.length > 0 && learnings[0] !== 'null' && (
-

What you will learn

+

+ What you will learn +

{learnings.map((learning: any) => { return ( -
+

{learning}

- ); - } - )} + ) + })}
- } + )}

Course Lessons

{course.chapters.map((chapter: any) => { return ( -
+

{chapter.name}

{chapter.activities.length} Activities

-
{chapter.activities.map((activity: any) => { - return ( - <> -

- -

-
-
- {activity.activity_type === "TYPE_DYNAMIC" && -
- -
- } - {activity.activity_type === "TYPE_VIDEO" && -
-
- } - {activity.activity_type === "TYPE_DOCUMENT" && -
- -
- } - +
+ {chapter.activities.map((activity: any) => { + return ( + <> +

+
+
+ {activity.activity_type === + 'TYPE_DYNAMIC' && ( +
+ +
+ )} + {activity.activity_type === 'TYPE_VIDEO' && ( +
+
+ )} + {activity.activity_type === + 'TYPE_DOCUMENT' && ( +
+ +
+ )} +
+ +

{activity.name}

+ +
+ {activity.activity_type === + 'TYPE_DYNAMIC' && ( + <> + +
+

Page

+ +
+ + + )} + {activity.activity_type === 'TYPE_VIDEO' && ( + <> + +
+

Video

+ +
+ + + )} + {activity.activity_type === + 'TYPE_DOCUMENT' && ( + <> + +
+

Document

+ +
+ + + )} +
- -

{activity.name}

- -
- {activity.activity_type === "TYPE_DYNAMIC" && - <> - -
-

Page

-
- - - } - {activity.activity_type === "TYPE_VIDEO" && - <> - -
-

Video

-
- - - } - {activity.activity_type === "TYPE_DOCUMENT" && - <> - -
-

Document

-
- - - } -
-
- - ); - })}
+ + ) + })} +
- ); + ) })}
-
- {user && + {user && (
- +
-
Author
+
+ Author +
- {course.authors[0].first_name && course.authors[0].last_name && ( -
-

{course.authors[0].first_name + ' ' + course.authors[0].last_name}

@{course.authors[0].username} -
)} - {!course.authors[0].first_name && !course.authors[0].last_name && ( -
-

@{course.authors[0].username}

-
)} + {course.authors[0].first_name && + course.authors[0].last_name && ( +
+

+ {course.authors[0].first_name + + ' ' + + course.authors[0].last_name} +

+ + {' '} + @{course.authors[0].username} + +
+ )} + {!course.authors[0].first_name && + !course.authors[0].last_name && ( +
+

@{course.authors[0].username}

+
+ )}
- } + )} {isCourseStarted() ? ( - ) : ( - + )}
)} - ); -}; + ) +} - -export default CourseClient; +export default CourseClient diff --git a/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/error.tsx b/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/error.tsx index 8bac23db..d5320406 100644 --- a/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/error.tsx +++ b/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/error.tsx @@ -1,23 +1,23 @@ -'use client'; // Error components must be Client Components +'use client' // Error components must be Client Components + +import ErrorUI from '@components/StyledElements/Error/Error' +import { useEffect } from 'react' -import ErrorUI from '@components/StyledElements/Error/Error'; -import { useEffect } from 'react'; - export default function Error({ error, reset, }: { - error: Error; - reset: () => void; + error: Error + reset: () => void }) { useEffect(() => { // Log the error to an error reporting service - console.error(error); - }, [error]); - + console.error(error) + }, [error]) + return (
- ); -} \ No newline at end of file + ) +} diff --git a/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/loading.tsx b/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/loading.tsx index 3f902486..3da44848 100644 --- a/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/loading.tsx +++ b/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/loading.tsx @@ -1,9 +1,6 @@ -import PageLoading from "@components/Objects/Loaders/PageLoading"; +import PageLoading from '@components/Objects/Loaders/PageLoading' export default function Loading() { - // Or a custom loading skeleton component - return ( - - ) - -} \ No newline at end of file + // Or a custom loading skeleton component + return +} diff --git a/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/page.tsx b/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/page.tsx index 7a659988..ff19b0d3 100644 --- a/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/page.tsx +++ b/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/page.tsx @@ -1,65 +1,78 @@ import React from 'react' import CourseClient from './course' -import { cookies } from 'next/headers'; -import { getCourseMetadataWithAuthHeader } from '@services/courses/courses'; -import { getOrganizationContextInfo } from '@services/organizations/orgs'; -import { Metadata } from 'next'; -import { getAccessTokenFromRefreshTokenCookie } from '@services/auth/auth'; +import { cookies } from 'next/headers' +import { getCourseMetadataWithAuthHeader } from '@services/courses/courses' +import { getOrganizationContextInfo } from '@services/organizations/orgs' +import { Metadata } from 'next' +import { getAccessTokenFromRefreshTokenCookie } from '@services/auth/auth' type MetadataProps = { - params: { orgslug: string, courseuuid: string }; - searchParams: { [key: string]: string | string[] | undefined }; -}; - -export async function generateMetadata( - { params }: MetadataProps, -): Promise { - const cookieStore = cookies(); - const access_token = await getAccessTokenFromRefreshTokenCookie(cookieStore) - - // Get Org context information - const org = await getOrganizationContextInfo(params.orgslug, { revalidate: 1800, tags: ['organizations'] }); - const course_meta = await getCourseMetadataWithAuthHeader(params.courseuuid, { revalidate: 0, tags: ['courses'] }, access_token ? access_token : null) - - - // SEO - return { - title: course_meta.name + ` — ${org.name}`, - description: course_meta.description, - keywords: course_meta.learnings, - robots: { - index: true, - follow: true, - nocache: true, - googleBot: { - index: true, - follow: true, - "max-image-preview": "large", - } - }, - openGraph: { - title: course_meta.name + ` — ${org.name}`, - description: course_meta.description ? course_meta.description : '', - type: 'article', - publishedTime: course_meta.creation_date ? course_meta.creation_date : '', - tags: course_meta.learnings ? course_meta.learnings : [], - }, - }; + params: { orgslug: string; courseuuid: string } + searchParams: { [key: string]: string | string[] | undefined } } +export async function generateMetadata({ + params, +}: MetadataProps): Promise { + const cookieStore = cookies() + const access_token = await getAccessTokenFromRefreshTokenCookie(cookieStore) + + // Get Org context information + const org = await getOrganizationContextInfo(params.orgslug, { + revalidate: 1800, + tags: ['organizations'], + }) + const course_meta = await getCourseMetadataWithAuthHeader( + params.courseuuid, + { revalidate: 0, tags: ['courses'] }, + access_token ? access_token : null + ) + + // SEO + return { + title: course_meta.name + ` — ${org.name}`, + description: course_meta.description, + keywords: course_meta.learnings, + robots: { + index: true, + follow: true, + nocache: true, + googleBot: { + index: true, + follow: true, + 'max-image-preview': 'large', + }, + }, + openGraph: { + title: course_meta.name + ` — ${org.name}`, + description: course_meta.description ? course_meta.description : '', + type: 'article', + publishedTime: course_meta.creation_date ? course_meta.creation_date : '', + tags: course_meta.learnings ? course_meta.learnings : [], + }, + } +} const CoursePage = async (params: any) => { - const cookieStore = cookies(); - const courseuuid = params.params.courseuuid - const orgslug = params.params.orgslug; - const access_token = await getAccessTokenFromRefreshTokenCookie(cookieStore) - const course_meta = await getCourseMetadataWithAuthHeader(courseuuid, { revalidate: 0, tags: ['courses'] }, access_token ? access_token : null) + const cookieStore = cookies() + const courseuuid = params.params.courseuuid + const orgslug = params.params.orgslug + const access_token = await getAccessTokenFromRefreshTokenCookie(cookieStore) + const course_meta = await getCourseMetadataWithAuthHeader( + courseuuid, + { revalidate: 0, tags: ['courses'] }, + access_token ? access_token : null + ) - return ( -
- -
- ) + return ( +
+ +
+ ) } -export default CoursePage \ No newline at end of file +export default CoursePage diff --git a/apps/web/app/orgs/[orgslug]/(withmenu)/courses/courses.tsx b/apps/web/app/orgs/[orgslug]/(withmenu)/courses/courses.tsx index 0cab8203..4e431ef3 100644 --- a/apps/web/app/orgs/[orgslug]/(withmenu)/courses/courses.tsx +++ b/apps/web/app/orgs/[orgslug]/(withmenu)/courses/courses.tsx @@ -1,113 +1,138 @@ -'use client'; -import CreateCourseModal from '@components/Objects/Modals/Course/Create/CreateCourse'; -import Modal from '@components/StyledElements/Modal/Modal'; +'use client' +import CreateCourseModal from '@components/Objects/Modals/Course/Create/CreateCourse' +import Modal from '@components/StyledElements/Modal/Modal' import React from 'react' -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 CourseThumbnail from '@components/Objects/Thumbnails/CourseThumbnail'; -import NewCourseButton from '@components/StyledElements/Buttons/NewCourseButton'; +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 CourseThumbnail from '@components/Objects/Thumbnails/CourseThumbnail' +import NewCourseButton from '@components/StyledElements/Buttons/NewCourseButton' interface CourseProps { - orgslug: string; - courses: any; - org_id: string; + orgslug: string + courses: any + org_id: string } function Courses(props: CourseProps) { - const orgslug = props.orgslug; - const courses = props.courses; - const searchParams = useSearchParams(); - const isCreatingCourse = searchParams.get('new') ? true : false; - const [newCourseModal, setNewCourseModal] = React.useState(isCreatingCourse); + const orgslug = props.orgslug + const courses = props.courses + const searchParams = useSearchParams() + const isCreatingCourse = searchParams.get('new') ? true : false + const [newCourseModal, setNewCourseModal] = React.useState(isCreatingCourse) - async function closeNewCourseModal() { - setNewCourseModal(false); - } + async function closeNewCourseModal() { + setNewCourseModal(false) + } - return ( -
- - -
- - - } - dialogTitle="Create Course" - dialogDescription="Create a new course" - dialogTrigger={ - - } - /> - -
- - - -
- {courses.map((course: any) => ( -
- -
- ))} - {courses.length == 0 && -
-
-
- - - - -
-
-

No courses yet

-

Create a course to add content

-
- - } - dialogTitle="Create Course" - dialogDescription="Create a new course" - dialogTrigger={ - } - /> - -
-
- } -
- - -
+ return ( +
+ +
+ + + + } + dialogTitle="Create Course" + dialogDescription="Create a new course" + dialogTrigger={ + + } + /> +
- ) + +
+ {courses.map((course: any) => ( +
+ +
+ ))} + {courses.length == 0 && ( +
+
+
+ + + + +
+
+

+ No courses yet +

+

+ Create a course to add content +

+
+ + + } + dialogTitle="Create Course" + dialogDescription="Create a new course" + dialogTrigger={ + + } + /> + +
+
+ )} +
+
+
+ ) } - - - -export default Courses \ No newline at end of file +export default Courses diff --git a/apps/web/app/orgs/[orgslug]/(withmenu)/courses/error.tsx b/apps/web/app/orgs/[orgslug]/(withmenu)/courses/error.tsx index 8bac23db..d5320406 100644 --- a/apps/web/app/orgs/[orgslug]/(withmenu)/courses/error.tsx +++ b/apps/web/app/orgs/[orgslug]/(withmenu)/courses/error.tsx @@ -1,23 +1,23 @@ -'use client'; // Error components must be Client Components +'use client' // Error components must be Client Components + +import ErrorUI from '@components/StyledElements/Error/Error' +import { useEffect } from 'react' -import ErrorUI from '@components/StyledElements/Error/Error'; -import { useEffect } from 'react'; - export default function Error({ error, reset, }: { - error: Error; - reset: () => void; + error: Error + reset: () => void }) { useEffect(() => { // Log the error to an error reporting service - console.error(error); - }, [error]); - + console.error(error) + }, [error]) + return (
- ); -} \ No newline at end of file + ) +} diff --git a/apps/web/app/orgs/[orgslug]/(withmenu)/courses/loading.tsx b/apps/web/app/orgs/[orgslug]/(withmenu)/courses/loading.tsx index 3f902486..3da44848 100644 --- a/apps/web/app/orgs/[orgslug]/(withmenu)/courses/loading.tsx +++ b/apps/web/app/orgs/[orgslug]/(withmenu)/courses/loading.tsx @@ -1,9 +1,6 @@ -import PageLoading from "@components/Objects/Loaders/PageLoading"; +import PageLoading from '@components/Objects/Loaders/PageLoading' export default function Loading() { - // Or a custom loading skeleton component - return ( - - ) - -} \ No newline at end of file + // Or a custom loading skeleton component + return +} diff --git a/apps/web/app/orgs/[orgslug]/(withmenu)/courses/page.tsx b/apps/web/app/orgs/[orgslug]/(withmenu)/courses/page.tsx index 301a2a3c..d7c8baca 100644 --- a/apps/web/app/orgs/[orgslug]/(withmenu)/courses/page.tsx +++ b/apps/web/app/orgs/[orgslug]/(withmenu)/courses/page.tsx @@ -1,27 +1,28 @@ - -import React from "react"; -import Courses from "./courses"; -import { getOrgCoursesWithAuthHeader } from "@services/courses/courses"; -import { Metadata } from "next"; -import { getOrganizationContextInfo } from "@services/organizations/orgs"; -import { cookies } from "next/headers"; -import { getAccessTokenFromRefreshTokenCookie } from "@services/auth/auth"; +import React from 'react' +import Courses from './courses' +import { getOrgCoursesWithAuthHeader } from '@services/courses/courses' +import { Metadata } from 'next' +import { getOrganizationContextInfo } from '@services/organizations/orgs' +import { cookies } from 'next/headers' +import { getAccessTokenFromRefreshTokenCookie } from '@services/auth/auth' type MetadataProps = { - params: { orgslug: string }; - searchParams: { [key: string]: string | string[] | undefined }; -}; + params: { orgslug: string } + searchParams: { [key: string]: string | string[] | undefined } +} -export async function generateMetadata( - { params }: MetadataProps, -): Promise { - - // Get Org context information - const org = await getOrganizationContextInfo(params.orgslug, { revalidate: 1800, tags: ['organizations'] }); +export async function generateMetadata({ + params, +}: MetadataProps): Promise { + // Get Org context information + const org = await getOrganizationContextInfo(params.orgslug, { + revalidate: 1800, + tags: ['organizations'], + }) // SEO return { - title: "Courses — " + org.name, + title: 'Courses — ' + org.name, description: org.description, keywords: `${org.name}, ${org.description}, courses, learning, education, online learning, edu, online courses, ${org.name} courses`, robots: { @@ -31,30 +32,36 @@ export async function generateMetadata( googleBot: { index: true, follow: true, - "max-image-preview": "large", - } + 'max-image-preview': 'large', + }, }, openGraph: { - title: "Courses — " + org.name, + title: 'Courses — ' + org.name, description: org.description, type: 'website', }, - }; + } } const CoursesPage = async (params: any) => { - const orgslug = params.params.orgslug; - const org = await getOrganizationContextInfo(orgslug, { revalidate: 1800, tags: ['organizations'] }); - const cookieStore = cookies(); + const orgslug = params.params.orgslug + const org = await getOrganizationContextInfo(orgslug, { + revalidate: 1800, + tags: ['organizations'], + }) + const cookieStore = cookies() const access_token = await getAccessTokenFromRefreshTokenCookie(cookieStore) - const courses = await getOrgCoursesWithAuthHeader(orgslug, { revalidate: 0, tags: ['courses'] }, access_token ? access_token : null); + const courses = await getOrgCoursesWithAuthHeader( + orgslug, + { revalidate: 0, tags: ['courses'] }, + access_token ? access_token : null + ) return (
- ); -}; - -export default CoursesPage; + ) +} +export default CoursesPage diff --git a/apps/web/app/orgs/[orgslug]/(withmenu)/error.tsx b/apps/web/app/orgs/[orgslug]/(withmenu)/error.tsx index 52120114..d5320406 100644 --- a/apps/web/app/orgs/[orgslug]/(withmenu)/error.tsx +++ b/apps/web/app/orgs/[orgslug]/(withmenu)/error.tsx @@ -1,23 +1,23 @@ -'use client'; // Error components must be Client Components +'use client' // Error components must be Client Components + +import ErrorUI from '@components/StyledElements/Error/Error' +import { useEffect } from 'react' -import ErrorUI from '@components/StyledElements/Error/Error'; -import { useEffect } from 'react'; - export default function Error({ error, reset, }: { - error: Error; - reset: () => void; + error: Error + reset: () => void }) { useEffect(() => { // Log the error to an error reporting service - console.error(error); - }, [error]); - + console.error(error) + }, [error]) + return (
- +
- ); -} \ No newline at end of file + ) +} diff --git a/apps/web/app/orgs/[orgslug]/(withmenu)/layout.tsx b/apps/web/app/orgs/[orgslug]/(withmenu)/layout.tsx index 94b966fa..00ca27ac 100644 --- a/apps/web/app/orgs/[orgslug]/(withmenu)/layout.tsx +++ b/apps/web/app/orgs/[orgslug]/(withmenu)/layout.tsx @@ -1,8 +1,14 @@ -import "@styles/globals.css"; -import { Menu } from "@components/Objects/Menu/Menu"; -import SessionProvider from "@components/Contexts/SessionContext"; +import '@styles/globals.css' +import { Menu } from '@components/Objects/Menu/Menu' +import SessionProvider from '@components/Contexts/SessionContext' -export default function RootLayout({ children, params }: { children: React.ReactNode , params :any}) { +export default function RootLayout({ + children, + params, +}: { + children: React.ReactNode + params: any +}) { return ( <> @@ -10,5 +16,5 @@ export default function RootLayout({ children, params }: { children: React.React {children} - ); + ) } diff --git a/apps/web/app/orgs/[orgslug]/(withmenu)/loading.tsx b/apps/web/app/orgs/[orgslug]/(withmenu)/loading.tsx index ec352ab7..58f6f7df 100644 --- a/apps/web/app/orgs/[orgslug]/(withmenu)/loading.tsx +++ b/apps/web/app/orgs/[orgslug]/(withmenu)/loading.tsx @@ -1,8 +1,5 @@ -import PageLoading from "@components/Objects/Loaders/PageLoading"; +import PageLoading from '@components/Objects/Loaders/PageLoading' export default function Loading() { - return ( - - ) - -} \ No newline at end of file + return +} diff --git a/apps/web/app/orgs/[orgslug]/(withmenu)/page.tsx b/apps/web/app/orgs/[orgslug]/(withmenu)/page.tsx index 9196ca21..70495d96 100644 --- a/apps/web/app/orgs/[orgslug]/(withmenu)/page.tsx +++ b/apps/web/app/orgs/[orgslug]/(withmenu)/page.tsx @@ -1,30 +1,33 @@ -export const dynamic = 'force-dynamic'; -import { Metadata } from 'next'; -import { getUriWithOrg } from "@services/config/config"; -import { getOrgCoursesWithAuthHeader } from "@services/courses/courses"; -import Link from "next/link"; -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 { getAccessTokenFromRefreshTokenCookie } from '@services/auth/auth'; -import CourseThumbnail from '@components/Objects/Thumbnails/CourseThumbnail'; -import CollectionThumbnail from '@components/Objects/Thumbnails/CollectionThumbnail'; -import AuthenticatedClientElement from '@components/Security/AuthenticatedClientElement'; -import NewCourseButton from '@components/StyledElements/Buttons/NewCourseButton'; -import NewCollectionButton from '@components/StyledElements/Buttons/NewCollectionButton'; +export const dynamic = 'force-dynamic' +import { Metadata } from 'next' +import { getUriWithOrg } from '@services/config/config' +import { getOrgCoursesWithAuthHeader } from '@services/courses/courses' +import Link from 'next/link' +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 { getAccessTokenFromRefreshTokenCookie } from '@services/auth/auth' +import CourseThumbnail from '@components/Objects/Thumbnails/CourseThumbnail' +import CollectionThumbnail from '@components/Objects/Thumbnails/CollectionThumbnail' +import AuthenticatedClientElement from '@components/Security/AuthenticatedClientElement' +import NewCourseButton from '@components/StyledElements/Buttons/NewCourseButton' +import NewCollectionButton from '@components/StyledElements/Buttons/NewCollectionButton' type MetadataProps = { - params: { orgslug: string }; - searchParams: { [key: string]: string | string[] | undefined }; -}; + params: { orgslug: string } + searchParams: { [key: string]: string | string[] | undefined } +} -export async function generateMetadata( - { params }: MetadataProps, -): Promise { - // Get Org context information - const org = await getOrganizationContextInfo(params.orgslug, { revalidate: 1800, tags: ['organizations'] }); +export async function generateMetadata({ + params, +}: MetadataProps): Promise { + // Get Org context information + const org = await getOrganizationContextInfo(params.orgslug, { + revalidate: 1800, + tags: ['organizations'], + }) // SEO return { @@ -37,83 +40,127 @@ export async function generateMetadata( googleBot: { index: true, follow: true, - "max-image-preview": "large", - } + 'max-image-preview': 'large', + }, }, openGraph: { title: `Home — ${org.name}`, description: org.description, type: 'website', }, - }; + } } const OrgHomePage = async (params: any) => { - const orgslug = params.params.orgslug; - const cookieStore = cookies(); + const orgslug = params.params.orgslug + const cookieStore = cookies() 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.id; - const collections = await getOrgCollectionsWithAuthHeader(org.id, access_token ? access_token : null, { revalidate: 0, tags: ['courses'] }); + 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.id + const collections = await getOrgCollectionsWithAuthHeader( + org.id, + access_token ? access_token : null, + { revalidate: 0, tags: ['courses'] } + ) return (
{/* Collections */} -
-
+
+
- + checkMethod="roles" + ressourceType="collections" + action="create" + orgId={org_id} + > +
{collections.map((collection: any) => ( -
- +
+
))} - {collections.length == 0 && + {collections.length == 0 && (
-
- - - +
+ + +
-

No collections yet

-

Create a collection to group courses together

+

+ No collections yet +

+

+ Create a collection to group courses together +

- } + )}
{/* Courses */} -
-
-
+
+
+
- + ressourceType="courses" + action="create" + checkMethod="roles" + orgId={org_id} + > + @@ -124,30 +171,52 @@ const OrgHomePage = async (params: any) => {
))} - {courses.length == 0 && + {courses.length == 0 && (
-
- - - +
+ + +
-

No courses yet

-

Create a course to add content

+

+ No courses yet +

+

+ Create a course to add content +

- } + )}
+ ) +} - ); -}; - - -export default OrgHomePage; +export default OrgHomePage diff --git a/apps/web/app/orgs/[orgslug]/(withmenu)/trail/page.tsx b/apps/web/app/orgs/[orgslug]/(withmenu)/trail/page.tsx index 2eea9a82..2a327ddd 100644 --- a/apps/web/app/orgs/[orgslug]/(withmenu)/trail/page.tsx +++ b/apps/web/app/orgs/[orgslug]/(withmenu)/trail/page.tsx @@ -1,33 +1,36 @@ -import React from "react"; -import { Metadata } from "next"; -import { getOrganizationContextInfo } from "@services/organizations/orgs"; -import Trail from "./trail"; +import React from 'react' +import { Metadata } from 'next' +import { getOrganizationContextInfo } from '@services/organizations/orgs' +import Trail from './trail' type MetadataProps = { - params: { orgslug: string }; - searchParams: { [key: string]: string | string[] | undefined }; -}; + params: { orgslug: string } + searchParams: { [key: string]: string | string[] | undefined } +} -export async function generateMetadata( - { params }: MetadataProps, -): Promise { - - // Get Org context information - const org = await getOrganizationContextInfo(params.orgslug, { revalidate: 1800, tags: ['organizations'] }); - return { - title: "Trail — " + org.name, - description: 'Check your progress using trail and easily navigate through your courses.', - }; +export async function generateMetadata({ + params, +}: MetadataProps): Promise { + // Get Org context information + const org = await getOrganizationContextInfo(params.orgslug, { + revalidate: 1800, + tags: ['organizations'], + }) + return { + title: 'Trail — ' + org.name, + description: + 'Check your progress using trail and easily navigate through your courses.', + } } const TrailPage = async (params: any) => { - let orgslug = params.params.orgslug; + let orgslug = params.params.orgslug - return ( -
- -
- ); -}; + return ( +
+ +
+ ) +} -export default TrailPage; \ No newline at end of file +export default TrailPage diff --git a/apps/web/app/orgs/[orgslug]/(withmenu)/trail/trail.tsx b/apps/web/app/orgs/[orgslug]/(withmenu)/trail/trail.tsx index 6f684dfc..8cbfcf93 100644 --- a/apps/web/app/orgs/[orgslug]/(withmenu)/trail/trail.tsx +++ b/apps/web/app/orgs/[orgslug]/(withmenu)/trail/trail.tsx @@ -1,23 +1,24 @@ -"use client"; -import { useOrg } from "@components/Contexts/OrgContext"; -import PageLoading from "@components/Objects/Loaders/PageLoading"; -import TrailCourseElement from "@components/Pages/Trail/TrailCourseElement"; -import TypeOfContentTitle from "@components/StyledElements/Titles/TypeOfContentTitle"; -import GeneralWrapperStyled from "@components/StyledElements/Wrappers/GeneralWrapper"; -import { getAPIUrl } from "@services/config/config"; -import { swrFetcher } from "@services/utils/ts/requests"; -import React, { useEffect } from "react"; -import useSWR from "swr"; +'use client' +import { useOrg } from '@components/Contexts/OrgContext' +import PageLoading from '@components/Objects/Loaders/PageLoading' +import TrailCourseElement from '@components/Pages/Trail/TrailCourseElement' +import TypeOfContentTitle from '@components/StyledElements/Titles/TypeOfContentTitle' +import GeneralWrapperStyled from '@components/StyledElements/Wrappers/GeneralWrapper' +import { getAPIUrl } from '@services/config/config' +import { swrFetcher } from '@services/utils/ts/requests' +import React, { useEffect } from 'react' +import useSWR from 'swr' function Trail(params: any) { - let orgslug = params.orgslug; - const org = useOrg() as any; - const orgID = org?.id; - const { data: trail, error: error } = useSWR(`${getAPIUrl()}trail/org/${orgID}/trail`, swrFetcher); + let orgslug = params.orgslug + const org = useOrg() as any + const orgID = org?.id + const { data: trail, error: error } = useSWR( + `${getAPIUrl()}trail/org/${orgID}/trail`, + swrFetcher + ) - useEffect(() => { - } - , [trail,org]); + useEffect(() => {}, [trail, org]) return ( @@ -28,19 +29,17 @@ function Trail(params: any) {
{trail.runs.map((run: any) => ( <> - + - ))} -
)}
- ); + ) } -export default Trail; - - - - +export default Trail diff --git a/apps/web/app/orgs/[orgslug]/dash/courses/client.tsx b/apps/web/app/orgs/[orgslug]/dash/courses/client.tsx index c2308527..cce3a585 100644 --- a/apps/web/app/orgs/[orgslug]/dash/courses/client.tsx +++ b/apps/web/app/orgs/[orgslug]/dash/courses/client.tsx @@ -1,108 +1,140 @@ -'use client'; +'use client' import BreadCrumbs from '@components/Dashboard/UI/BreadCrumbs' -import CreateCourseModal from '@components/Objects/Modals/Course/Create/CreateCourse'; -import CourseThumbnail from '@components/Objects/Thumbnails/CourseThumbnail'; -import AuthenticatedClientElement from '@components/Security/AuthenticatedClientElement'; -import NewCourseButton from '@components/StyledElements/Buttons/NewCourseButton'; -import Modal from '@components/StyledElements/Modal/Modal'; -import { useSearchParams } from 'next/navigation'; +import CreateCourseModal from '@components/Objects/Modals/Course/Create/CreateCourse' +import CourseThumbnail from '@components/Objects/Thumbnails/CourseThumbnail' +import AuthenticatedClientElement from '@components/Security/AuthenticatedClientElement' +import NewCourseButton from '@components/StyledElements/Buttons/NewCourseButton' +import Modal from '@components/StyledElements/Modal/Modal' +import { useSearchParams } from 'next/navigation' import React from 'react' type CourseProps = { - orgslug: string; - courses: any; - org_id: string; + orgslug: string + courses: any + org_id: string } function CoursesHome(params: CourseProps) { - const searchParams = useSearchParams(); - const isCreatingCourse = searchParams.get('new') ? true : false; - const [newCourseModal, setNewCourseModal] = React.useState(isCreatingCourse); - const orgslug = params.orgslug; - const courses = params.courses; + const searchParams = useSearchParams() + const isCreatingCourse = searchParams.get('new') ? true : false + const [newCourseModal, setNewCourseModal] = React.useState(isCreatingCourse) + const orgslug = params.orgslug + const courses = params.courses + async function closeNewCourseModal() { + setNewCourseModal(false) + } - async function closeNewCourseModal() { - setNewCourseModal(false); - } + return ( +
+
+
+ - return ( -
-
-
- - -
-
Courses
- - } - dialogTitle="Create Course" - dialogDescription="Create a new course" - dialogTrigger={ - - } - /> - -
-
-
-
- {courses.map((course: any) => ( -
- -
- ))} - {courses.length == 0 && -
-
-
- - - - -
-
-

No courses yet

-

Create a course to add content

-
- - } - dialogTitle="Create Course" - dialogDescription="Create a new course" - dialogTrigger={ - } - /> - -
-
+
+
Courses
+ + } -
+ dialogTitle="Create Course" + dialogDescription="Create a new course" + dialogTrigger={ + + } + /> + +
- ) +
+
+ {courses.map((course: any) => ( +
+ +
+ ))} + {courses.length == 0 && ( +
+
+
+ + + + +
+
+

+ No courses yet +

+

+ Create a course to add content +

+
+ + + } + dialogTitle="Create Course" + dialogDescription="Create a new course" + dialogTrigger={ + + } + /> + +
+
+ )} +
+
+ ) } -export default CoursesHome \ No newline at end of file +export default CoursesHome diff --git a/apps/web/app/orgs/[orgslug]/dash/courses/course/[courseuuid]/[subpage]/page.tsx b/apps/web/app/orgs/[orgslug]/dash/courses/course/[courseuuid]/[subpage]/page.tsx index 36482263..6cfe4c83 100644 --- a/apps/web/app/orgs/[orgslug]/dash/courses/course/[courseuuid]/[subpage]/page.tsx +++ b/apps/web/app/orgs/[orgslug]/dash/courses/course/[courseuuid]/[subpage]/page.tsx @@ -1,72 +1,93 @@ -'use client'; +'use client' import EditCourseStructure from '../../../../../../../../components/Dashboard/Course/EditCourseStructure/EditCourseStructure' -import { getUriWithOrg } from '@services/config/config'; +import { getUriWithOrg } from '@services/config/config' import React from 'react' -import { CourseProvider } from '../../../../../../../../components/Contexts/CourseContext'; -import Link from 'next/link'; -import { CourseOverviewTop } from '@components/Dashboard/UI/CourseOverviewTop'; -import { motion } from 'framer-motion'; -import EditCourseGeneral from '@components/Dashboard/Course/EditCourseGeneral/EditCourseGeneral'; -import { GalleryVerticalEnd, Info } from 'lucide-react'; +import { CourseProvider } from '../../../../../../../../components/Contexts/CourseContext' +import Link from 'next/link' +import { CourseOverviewTop } from '@components/Dashboard/UI/CourseOverviewTop' +import { motion } from 'framer-motion' +import EditCourseGeneral from '@components/Dashboard/Course/EditCourseGeneral/EditCourseGeneral' +import { GalleryVerticalEnd, Info } from 'lucide-react' export type CourseOverviewParams = { - orgslug: string, - courseuuid: string, - subpage: string + orgslug: string + courseuuid: string + subpage: string } - - function CourseOverviewPage({ params }: { params: CourseOverviewParams }) { + function getEntireCourseUUID(courseuuid: string) { + // add course_ to uuid + return `course_${courseuuid}` + } - function getEntireCourseUUID(courseuuid: string) { - // add course_ to uuid - return `course_${courseuuid}` - } - - return ( -
- -
- -
- -
- -
- -
General
-
-
- - -
-
- -
Content
-
- -
- -
+ return ( +
+ +
+ +
+ +
+
+ +
General
- - {params.subpage == 'content' ? : ''} - {params.subpage == 'general' ? : ''} - - +
+ + +
+
+ +
Content
+
+
+ +
- ) + + {params.subpage == 'content' ? ( + + ) : ( + '' + )} + {params.subpage == 'general' ? ( + + ) : ( + '' + )} + +
+
+ ) } - - - - -export default CourseOverviewPage \ No newline at end of file +export default CourseOverviewPage diff --git a/apps/web/app/orgs/[orgslug]/dash/courses/page.tsx b/apps/web/app/orgs/[orgslug]/dash/courses/page.tsx index adb477a6..5704e9e9 100644 --- a/apps/web/app/orgs/[orgslug]/dash/courses/page.tsx +++ b/apps/web/app/orgs/[orgslug]/dash/courses/page.tsx @@ -1,57 +1,63 @@ -import { getAccessTokenFromRefreshTokenCookie } from '@services/auth/auth'; -import { getOrgCoursesWithAuthHeader } from '@services/courses/courses'; -import { getOrganizationContextInfo } from '@services/organizations/orgs'; -import { Metadata } from 'next'; -import { cookies } from 'next/headers'; +import { getAccessTokenFromRefreshTokenCookie } from '@services/auth/auth' +import { getOrgCoursesWithAuthHeader } from '@services/courses/courses' +import { getOrganizationContextInfo } from '@services/organizations/orgs' +import { Metadata } from 'next' +import { cookies } from 'next/headers' import React from 'react' -import CoursesHome from './client'; +import CoursesHome from './client' type MetadataProps = { - params: { orgslug: string }; - searchParams: { [key: string]: string | string[] | undefined }; -}; + params: { orgslug: string } + searchParams: { [key: string]: string | string[] | undefined } +} -export async function generateMetadata( - { params }: MetadataProps, -): Promise { +export async function generateMetadata({ + params, +}: MetadataProps): Promise { + // Get Org context information + const org = await getOrganizationContextInfo(params.orgslug, { + revalidate: 1800, + tags: ['organizations'], + }) - // Get Org context information - const org = await getOrganizationContextInfo(params.orgslug, { revalidate: 1800, tags: ['organizations'] }); - - // SEO - return { - title: "Courses — " + org.name, - description: org.description, - keywords: `${org.name}, ${org.description}, courses, learning, education, online learning, edu, online courses, ${org.name} courses`, - robots: { - index: true, - follow: true, - nocache: true, - googleBot: { - index: true, - follow: true, - "max-image-preview": "large", - } - }, - openGraph: { - title: "Courses — " + org.name, - description: org.description, - type: 'website', - }, - }; + // SEO + return { + title: 'Courses — ' + org.name, + description: org.description, + keywords: `${org.name}, ${org.description}, courses, learning, education, online learning, edu, online courses, ${org.name} courses`, + robots: { + index: true, + follow: true, + nocache: true, + googleBot: { + index: true, + follow: true, + 'max-image-preview': 'large', + }, + }, + openGraph: { + title: 'Courses — ' + org.name, + description: org.description, + type: 'website', + }, + } } async function CoursesPage(params: any) { - const orgslug = params.params.orgslug; - const org = await getOrganizationContextInfo(orgslug, { revalidate: 1800, tags: ['organizations'] }); - const cookieStore = cookies(); - const access_token = await getAccessTokenFromRefreshTokenCookie(cookieStore) - const courses = await getOrgCoursesWithAuthHeader(orgslug, { revalidate: 0, tags: ['courses'] }, access_token ? access_token : null); + const orgslug = params.params.orgslug + const org = await getOrganizationContextInfo(orgslug, { + revalidate: 1800, + tags: ['organizations'], + }) + const cookieStore = cookies() + const access_token = await getAccessTokenFromRefreshTokenCookie(cookieStore) + const courses = await getOrgCoursesWithAuthHeader( + orgslug, + { revalidate: 0, tags: ['courses'] }, + access_token ? access_token : null + ) - - return ( - - ) + return } -export default CoursesPage \ No newline at end of file +export default CoursesPage diff --git a/apps/web/app/orgs/[orgslug]/dash/layout.tsx b/apps/web/app/orgs/[orgslug]/dash/layout.tsx index cbb45810..7c847dcd 100644 --- a/apps/web/app/orgs/[orgslug]/dash/layout.tsx +++ b/apps/web/app/orgs/[orgslug]/dash/layout.tsx @@ -3,21 +3,25 @@ import LeftMenu from '@components/Dashboard/UI/LeftMenu' import AdminAuthorization from '@components/Security/AdminAuthorization' import React from 'react' -function DashboardLayout({ children, params }: { children: React.ReactNode, params: any }) { - return ( - <> - - -
- -
- {children} -
-
-
-
- - ) +function DashboardLayout({ + children, + params, +}: { + children: React.ReactNode + params: any +}) { + return ( + <> + + +
+ +
{children}
+
+
+
+ + ) } -export default DashboardLayout \ No newline at end of file +export default DashboardLayout diff --git a/apps/web/app/orgs/[orgslug]/dash/org/settings/[subpage]/page.tsx b/apps/web/app/orgs/[orgslug]/dash/org/settings/[subpage]/page.tsx index d5128970..ee6a9479 100644 --- a/apps/web/app/orgs/[orgslug]/dash/org/settings/[subpage]/page.tsx +++ b/apps/web/app/orgs/[orgslug]/dash/org/settings/[subpage]/page.tsx @@ -1,4 +1,4 @@ -'use client'; +'use client' import BreadCrumbs from '@components/Dashboard/UI/BreadCrumbs' import { getUriWithOrg } from '@services/config/config' import { Info } from 'lucide-react' @@ -8,44 +8,54 @@ import { motion } from 'framer-motion' import OrgEditGeneral from '@components/Dashboard/Org/OrgEditGeneral/OrgEditGeneral' export type OrgParams = { - subpage: string - orgslug: string + subpage: string + orgslug: string } function OrgPage({ params }: { params: OrgParams }) { - return ( -
-
- -
-
-
Organization Settings
-
-
-
- -
- -
- -
General
-
-
- - -
+ return ( +
+
+ +
+
+
+ Organization Settings
-
- - {params.subpage == 'general' ? : ''} - +
- ) +
+ +
+
+ +
General
+
+
+ +
+
+
+ + {params.subpage == 'general' ? : ''} + +
+ ) } -export default OrgPage \ No newline at end of file +export default OrgPage diff --git a/apps/web/app/orgs/[orgslug]/dash/page.tsx b/apps/web/app/orgs/[orgslug]/dash/page.tsx index 861c9f0d..75e551c5 100644 --- a/apps/web/app/orgs/[orgslug]/dash/page.tsx +++ b/apps/web/app/orgs/[orgslug]/dash/page.tsx @@ -6,59 +6,89 @@ import Link from 'next/link' import AdminAuthorization from '@components/Security/AdminAuthorization' function DashboardHome() { - return ( -
-
- learnhouse logo + return ( +
+
+ learnhouse logo +
+ +
+ +
+ +
Courses
+

+ Create and manage courses, chapters and ativities{' '} +

- -
- -
- -
Courses
-

Create and manage courses, chapters and ativities

-
- - -
- -
Organization
-

Configure your Organization general settings

-
- - -
- -
Users
-

Manage your Organization's users, roles

-
- - -
-
-
- -
-
- - -
Learn LearnHouse
- -
-
-
- - -
- -
Account Settings
-

Configure your personal settings, passwords, email

-
- + + +
+ +
+ Organization +
+

+ Configure your Organization general settings{' '} +

+ + +
+ +
Users
+

+ Manage your Organization's users, roles{' '} +

+
+
- ) + +
+ +
+
+ + +
+ Learn LearnHouse +
+ +
+
+
+ + +
+ +
Account Settings
+

+ Configure your personal settings, passwords, email +

+
+ +
+
+ ) } -export default DashboardHome \ No newline at end of file +export default DashboardHome diff --git a/apps/web/app/orgs/[orgslug]/dash/user-account/settings/[subpage]/page.tsx b/apps/web/app/orgs/[orgslug]/dash/user-account/settings/[subpage]/page.tsx index f1ef8bcf..5a8d0d72 100644 --- a/apps/web/app/orgs/[orgslug]/dash/user-account/settings/[subpage]/page.tsx +++ b/apps/web/app/orgs/[orgslug]/dash/user-account/settings/[subpage]/page.tsx @@ -1,70 +1,90 @@ -'use client'; +'use client' import React, { useEffect } from 'react' -import { motion } from 'framer-motion'; -import UserEditGeneral from '@components/Dashboard/UserAccount/UserEditGeneral/UserEditGeneral'; -import UserEditPassword from '@components/Dashboard/UserAccount/UserEditPassword/UserEditPassword'; -import Link from 'next/link'; -import { getUriWithOrg } from '@services/config/config'; -import { Info, Lock } from 'lucide-react'; -import BreadCrumbs from '@components/Dashboard/UI/BreadCrumbs'; -import { useSession } from '@components/Contexts/SessionContext'; +import { motion } from 'framer-motion' +import UserEditGeneral from '@components/Dashboard/UserAccount/UserEditGeneral/UserEditGeneral' +import UserEditPassword from '@components/Dashboard/UserAccount/UserEditPassword/UserEditPassword' +import Link from 'next/link' +import { getUriWithOrg } from '@services/config/config' +import { Info, Lock } from 'lucide-react' +import BreadCrumbs from '@components/Dashboard/UI/BreadCrumbs' +import { useSession } from '@components/Contexts/SessionContext' export type SettingsParams = { - subpage: string - orgslug: string + subpage: string + orgslug: string } function SettingsPage({ params }: { params: SettingsParams }) { - const session = useSession() as any; + const session = useSession() as any + useEffect(() => {}, [session]) - useEffect(() => { - } - , [session]) - - return ( -
-
- -
-
-
Account Settings
-
-
-
- -
- -
- -
General
-
-
- - -
-
- -
Password
-
- -
- -
-
-
- - {params.subpage == 'general' ? : ''} - {params.subpage == 'security' ? : ''} - + return ( +
+
+ +
+
+
Account Settings
+
- ) +
+ +
+
+ +
General
+
+
+ + +
+
+ +
Password
+
+
+ +
+
+
+ + {params.subpage == 'general' ? : ''} + {params.subpage == 'security' ? : ''} + +
+ ) } -export default SettingsPage \ No newline at end of file +export default SettingsPage diff --git a/apps/web/app/orgs/[orgslug]/dash/users/settings/[subpage]/page.tsx b/apps/web/app/orgs/[orgslug]/dash/users/settings/[subpage]/page.tsx index 656793ab..16bc5c5e 100644 --- a/apps/web/app/orgs/[orgslug]/dash/users/settings/[subpage]/page.tsx +++ b/apps/web/app/orgs/[orgslug]/dash/users/settings/[subpage]/page.tsx @@ -1,101 +1,128 @@ -'use client'; +'use client' import React, { useEffect } from 'react' -import { motion } from 'framer-motion'; -import Link from 'next/link'; -import { getUriWithOrg } from '@services/config/config'; -import { ScanEye, UserPlus, Users } from 'lucide-react'; -import BreadCrumbs from '@components/Dashboard/UI/BreadCrumbs'; -import { useSession } from '@components/Contexts/SessionContext'; -import { useOrg } from '@components/Contexts/OrgContext'; -import OrgUsers from '@components/Dashboard/Users/OrgUsers/OrgUsers'; -import OrgAccess from '@components/Dashboard/Users/OrgAccess/OrgAccess'; +import { motion } from 'framer-motion' +import Link from 'next/link' +import { getUriWithOrg } from '@services/config/config' +import { ScanEye, UserPlus, Users } from 'lucide-react' +import BreadCrumbs from '@components/Dashboard/UI/BreadCrumbs' +import { useSession } from '@components/Contexts/SessionContext' +import { useOrg } from '@components/Contexts/OrgContext' +import OrgUsers from '@components/Dashboard/Users/OrgUsers/OrgUsers' +import OrgAccess from '@components/Dashboard/Users/OrgAccess/OrgAccess' export type SettingsParams = { - subpage: string - orgslug: string + subpage: string + orgslug: string } function UsersSettingsPage({ params }: { params: SettingsParams }) { - const session = useSession() as any; - const org = useOrg() as any; - const [H1Label, setH1Label] = React.useState('') - const [H2Label, setH2Label] = React.useState('') + const session = useSession() as any + const org = useOrg() as any + const [H1Label, setH1Label] = React.useState('') + const [H2Label, setH2Label] = React.useState('') - function handleLabels() { - if (params.subpage == 'users') { - setH1Label('Users') - setH2Label('Manage your organization users, assign roles and permissions') - } - if (params.subpage == 'signups') { - setH1Label('Signup Access') - setH2Label('Choose from where users can join your organization') - } - if (params.subpage == 'add') { - setH1Label('Invite users') - setH2Label('Invite users to join your organization') - } + function handleLabels() { + if (params.subpage == 'users') { + setH1Label('Users') + setH2Label('Manage your organization users, assign roles and permissions') } - - - - - - useEffect(() => { - handleLabels() + if (params.subpage == 'signups') { + setH1Label('Signup Access') + setH2Label('Choose from where users can join your organization') } - , [session, org, params.subpage, params]) + if (params.subpage == 'add') { + setH1Label('Invite users') + setH2Label('Invite users to join your organization') + } + } - return ( -
-
- -
-
-
{H1Label}
-
{H2Label}
-
-
-
- -
+ useEffect(() => { + handleLabels() + }, [session, org, params.subpage, params]) -
- -
Users
-
-
- - -
-
- -
Invite users
-
-
- - -
-
- -
Signup Access
-
-
- - -
+ return ( +
+
+ +
+
+
+ {H1Label}
- - {params.subpage == 'users' ? : ''} - {params.subpage == 'signups' ? : ''} - +
+ {H2Label}{' '} +
+
- ) +
+ +
+
+ +
Users
+
+
+ + +
+
+ +
Invite users
+
+
+ + +
+
+ +
Signup Access
+
+
+ +
+
+ + {params.subpage == 'users' ? : ''} + {params.subpage == 'signups' ? : ''} + +
+ ) } -export default UsersSettingsPage \ No newline at end of file +export default UsersSettingsPage diff --git a/apps/web/app/orgs/[orgslug]/layout.tsx b/apps/web/app/orgs/[orgslug]/layout.tsx index e9b5b4a9..a00e1e77 100644 --- a/apps/web/app/orgs/[orgslug]/layout.tsx +++ b/apps/web/app/orgs/[orgslug]/layout.tsx @@ -1,17 +1,20 @@ -'use client'; -import { OrgProvider } from "@components/Contexts/OrgContext"; -import SessionProvider from "@components/Contexts/SessionContext"; -import "@styles/globals.css"; - -export default function RootLayout({ children, params }: { children: React.ReactNode, params: any }) { +'use client' +import { OrgProvider } from '@components/Contexts/OrgContext' +import SessionProvider from '@components/Contexts/SessionContext' +import '@styles/globals.css' +export default function RootLayout({ + children, + params, +}: { + children: React.ReactNode + params: any +}) { return (
- - {children} - + {children}
- ); + ) } diff --git a/apps/web/app/orgs/[orgslug]/login/login.tsx b/apps/web/app/orgs/[orgslug]/login/login.tsx index b5bf3c0c..4bfb1c35 100644 --- a/apps/web/app/orgs/[orgslug]/login/login.tsx +++ b/apps/web/app/orgs/[orgslug]/login/login.tsx @@ -1,138 +1,174 @@ -"use client";; -import learnhouseIcon from "public/learnhouse_bigicon_1.png"; -import FormLayout, { FormField, FormLabelAndMessage, Input } from '@components/StyledElements/Form/Form'; -import Image from 'next/image'; -import * as Form from '@radix-ui/react-form'; -import { useFormik } from 'formik'; -import { getOrgLogoMediaDirectory } from "@services/media/media"; -import React from "react"; -import { loginAndGetToken } from "@services/auth/auth"; -import { AlertTriangle } from "lucide-react"; -import { useRouter } from "next/navigation"; -import Link from "next/link"; -import { getUriWithOrg } from "@services/config/config"; +'use client' +import learnhouseIcon from 'public/learnhouse_bigicon_1.png' +import FormLayout, { + FormField, + FormLabelAndMessage, + Input, +} from '@components/StyledElements/Form/Form' +import Image from 'next/image' +import * as Form from '@radix-ui/react-form' +import { useFormik } from 'formik' +import { getOrgLogoMediaDirectory } from '@services/media/media' +import React from 'react' +import { loginAndGetToken } from '@services/auth/auth' +import { AlertTriangle } from 'lucide-react' +import { useRouter } from 'next/navigation' +import Link from 'next/link' +import { getUriWithOrg } from '@services/config/config' interface LoginClientProps { - org: any; + org: any } const validate = (values: any) => { - const errors: any = {}; + const errors: any = {} - if (!values.email) { - errors.email = 'Required'; - } - else if ( - !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email) - ) { - errors.email = 'Invalid email address'; - } + if (!values.email) { + errors.email = 'Required' + } else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email)) { + errors.email = 'Invalid email address' + } - if (!values.password) { - errors.password = 'Required'; - } - else if (values.password.length < 8) { - errors.password = 'Password must be at least 8 characters'; - } + if (!values.password) { + errors.password = 'Required' + } else if (values.password.length < 8) { + errors.password = 'Password must be at least 8 characters' + } - return errors; -}; + return errors +} const LoginClient = (props: LoginClientProps) => { - const [isSubmitting, setIsSubmitting] = React.useState(false); - const router = useRouter(); - const [error, setError] = React.useState(''); - const formik = useFormik({ - initialValues: { - email: '', - password: '', - }, - validate, - onSubmit: async values => { - setIsSubmitting(true); - let res = await loginAndGetToken(values.email, values.password); - let message = await res.json(); - if (res.status == 200) { - router.push(`/`); - setIsSubmitting(false); - } - else if (res.status == 401 || res.status == 400 || res.status == 404 || res.status == 409) { - setError(message.detail); - setIsSubmitting(false); - } - else { - setError("Something went wrong"); - setIsSubmitting(false); - } - - }, - }); - return ( -
-
-
- - -
-
-
-
Login to
-
- {props.org?.logo_image ? ( - Learnhouse - ) : ( - - )} -
-
{props.org?.name}
-
-
-
-
-
- {error && ( -
- -
{error}
-
- )} - - - - - - - - {/* for password */} - - - - - - - - - -
- - - -
- -
-
-
+ const [isSubmitting, setIsSubmitting] = React.useState(false) + const router = useRouter() + const [error, setError] = React.useState('') + const formik = useFormik({ + initialValues: { + email: '', + password: '', + }, + validate, + onSubmit: async (values) => { + setIsSubmitting(true) + let res = await loginAndGetToken(values.email, values.password) + let message = await res.json() + if (res.status == 200) { + router.push(`/`) + setIsSubmitting(false) + } else if ( + res.status == 401 || + res.status == 400 || + res.status == 404 || + res.status == 409 + ) { + setError(message.detail) + setIsSubmitting(false) + } else { + setError('Something went wrong') + setIsSubmitting(false) + } + }, + }) + return ( +
+
+
+ + +
- ); -}; +
+
+
Login to
+
+ {props.org?.logo_image ? ( + Learnhouse + ) : ( + + )} +
+
{props.org?.name}
+
+
+
+
+
+ {error && ( +
+ +
{error}
+
+ )} + + + + + + + + {/* for password */} + + + + + + + + +
+ + + +
+
+
+
+
+ ) +} export default LoginClient - diff --git a/apps/web/app/orgs/[orgslug]/login/page.tsx b/apps/web/app/orgs/[orgslug]/login/page.tsx index faf71cc8..dce15e8b 100644 --- a/apps/web/app/orgs/[orgslug]/login/page.tsx +++ b/apps/web/app/orgs/[orgslug]/login/page.tsx @@ -1,35 +1,39 @@ -import { getOrganizationContextInfo } from "@services/organizations/orgs"; -import LoginClient from "./login"; -import { Metadata } from 'next'; +import { getOrganizationContextInfo } from '@services/organizations/orgs' +import LoginClient from './login' +import { Metadata } from 'next' type MetadataProps = { - params: { orgslug: string, courseid: string }; - searchParams: { [key: string]: string | string[] | undefined }; -}; + params: { orgslug: string; courseid: string } + searchParams: { [key: string]: string | string[] | undefined } +} -export async function generateMetadata( - { params }: MetadataProps, -): Promise { - const orgslug = params.orgslug; - // Get Org context information - const org = await getOrganizationContextInfo(orgslug, { revalidate: 0, tags: ['organizations'] }); +export async function generateMetadata({ + params, +}: MetadataProps): Promise { + const orgslug = params.orgslug + // Get Org context information + const org = await getOrganizationContextInfo(orgslug, { + revalidate: 0, + tags: ['organizations'], + }) return { title: 'Login' + ` — ${org.name}`, - }; + } } const Login = async (params: any) => { - const orgslug = params.params.orgslug; - const org = await getOrganizationContextInfo(orgslug, { revalidate: 0, tags: ['organizations'] }); + const orgslug = params.params.orgslug + const org = await getOrganizationContextInfo(orgslug, { + revalidate: 0, + tags: ['organizations'], + }) return (
- ); -}; + ) +} - - -export default Login; +export default Login diff --git a/apps/web/app/orgs/[orgslug]/signup/InviteOnlySignUp.tsx b/apps/web/app/orgs/[orgslug]/signup/InviteOnlySignUp.tsx index 1f554fd2..0e9f93c8 100644 --- a/apps/web/app/orgs/[orgslug]/signup/InviteOnlySignUp.tsx +++ b/apps/web/app/orgs/[orgslug]/signup/InviteOnlySignUp.tsx @@ -1,166 +1,186 @@ -"use client"; -import { useFormik } from 'formik'; -import { useRouter } from 'next/navigation'; +'use client' +import { useFormik } from 'formik' +import { useRouter } from 'next/navigation' import React, { useEffect } from 'react' -import FormLayout, { FormField, FormLabelAndMessage, Input, Textarea } from '@components/StyledElements/Form/Form'; -import * as Form from '@radix-ui/react-form'; -import { AlertTriangle, Check, User } from 'lucide-react'; -import Link from 'next/link'; -import { signUpWithInviteCode } from '@services/auth/auth'; -import { useOrg } from '@components/Contexts/OrgContext'; - - - +import FormLayout, { + FormField, + FormLabelAndMessage, + Input, + Textarea, +} from '@components/StyledElements/Form/Form' +import * as Form from '@radix-ui/react-form' +import { AlertTriangle, Check, User } from 'lucide-react' +import Link from 'next/link' +import { signUpWithInviteCode } from '@services/auth/auth' +import { useOrg } from '@components/Contexts/OrgContext' const validate = (values: any) => { - const errors: any = {}; + const errors: any = {} - if (!values.email) { - errors.email = 'Required'; - } - else if ( - !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email) - ) { - errors.email = 'Invalid email address'; - } + if (!values.email) { + errors.email = 'Required' + } else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email)) { + errors.email = 'Invalid email address' + } - if (!values.password) { - errors.password = 'Required'; - } - else if (values.password.length < 8) { - errors.password = 'Password must be at least 8 characters'; - } + if (!values.password) { + errors.password = 'Required' + } else if (values.password.length < 8) { + errors.password = 'Password must be at least 8 characters' + } - if (!values.username) { - errors.username = 'Required'; - } + if (!values.username) { + errors.username = 'Required' + } - if (!values.username || values.username.length < 4) { - errors.username = 'Username must be at least 4 characters'; - } + if (!values.username || values.username.length < 4) { + errors.username = 'Username must be at least 4 characters' + } - if (!values.bio) { - errors.bio = 'Required'; - } + if (!values.bio) { + errors.bio = 'Required' + } - - return errors; -}; + return errors +} interface InviteOnlySignUpProps { - inviteCode: string; + inviteCode: string } -function InviteOnlySignUpComponent(props : InviteOnlySignUpProps) { - const [isSubmitting, setIsSubmitting] = React.useState(false); - const org = useOrg() as any; - const router = useRouter(); - const [error, setError] = React.useState(''); - const [message, setMessage] = React.useState(''); - const formik = useFormik({ - initialValues: { - org_slug: org?.slug, - org_id: org?.id, - email: '', - password: '', - username: '', - bio: '', - first_name: '', - last_name: '', - }, - validate, - onSubmit: async values => { - setError('') - setMessage('') - setIsSubmitting(true); - let res = await signUpWithInviteCode(values, props.inviteCode); - let message = await res.json(); - if (res.status == 200) { - //router.push(`/login`); - setMessage('Your account was successfully created') - setIsSubmitting(false); - } - else if (res.status == 401 || res.status == 400 || res.status == 404 || res.status == 409) { - setError(message.detail); - setIsSubmitting(false); - - } - else { - setError("Something went wrong"); - setIsSubmitting(false); - } +function InviteOnlySignUpComponent(props: InviteOnlySignUpProps) { + const [isSubmitting, setIsSubmitting] = React.useState(false) + const org = useOrg() as any + const router = useRouter() + const [error, setError] = React.useState('') + const [message, setMessage] = React.useState('') + const formik = useFormik({ + initialValues: { + org_slug: org?.slug, + org_id: org?.id, + email: '', + password: '', + username: '', + bio: '', + first_name: '', + last_name: '', + }, + validate, + onSubmit: async (values) => { + setError('') + setMessage('') + setIsSubmitting(true) + let res = await signUpWithInviteCode(values, props.inviteCode) + let message = await res.json() + if (res.status == 200) { + //router.push(`/login`); + setMessage('Your account was successfully created') + setIsSubmitting(false) + } else if ( + res.status == 401 || + res.status == 400 || + res.status == 404 || + res.status == 409 + ) { + setError(message.detail) + setIsSubmitting(false) + } else { + setError('Something went wrong') + setIsSubmitting(false) + } + }, + }) - }, - }); + useEffect(() => {}, [org]) - useEffect(() => { - - } - , [org]); + return ( +
+ {error && ( +
+ +
{error}
+
+ )} + {message && ( +
+
+ +
{message}
+
+
+ +
Login
+ +
+ )} + + + + + + + + {/* for password */} + + - return ( -
- {error && ( -
- -
{error}
-
- )} - {message && ( -
-
- -
{message}
-
-
-
Login
-
- )} - - - - - - - - {/* for password */} - - + + + + + {/* for username */} + + - - - - - {/* for username */} - - + + + + - - - - + {/* for bio */} + + - {/* for bio */} - - + +