diff --git a/apps/api/src/security/rbac/rbac.py b/apps/api/src/security/rbac/rbac.py
index 2e92ff09..d7055a79 100644
--- a/apps/api/src/security/rbac/rbac.py
+++ b/apps/api/src/security/rbac/rbac.py
@@ -33,19 +33,18 @@ async def authorization_verify_if_element_is_public(
detail="User rights : You don't have the right to perform this action",
)
- if element_nature == "collections" and action == "read":
-
- statement = select(Collection).where(
- Collection.public == True, Collection.collection_uuid == element_uuid
+ if element_nature == "collections" and action == "read":
+ statement = select(Collection).where(
+ Collection.public == True, Collection.collection_uuid == element_uuid
+ )
+ collection = db_session.exec(statement).first()
+ if collection:
+ return True
+ else:
+ raise HTTPException(
+ status_code=status.HTTP_403_FORBIDDEN,
+ detail="User rights : You don't have the right to perform this action",
)
- collection = db_session.exec(statement).first()
- if collection:
- return True
- else:
- raise HTTPException(
- status_code=status.HTTP_403_FORBIDDEN,
- detail="User rights : You don't have the right to perform this action",
- )
else:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
diff --git a/apps/api/src/services/courses/collections.py b/apps/api/src/services/courses/collections.py
index 83f976a7..ac9627b6 100644
--- a/apps/api/src/services/courses/collections.py
+++ b/apps/api/src/services/courses/collections.py
@@ -28,7 +28,7 @@ from fastapi import HTTPException, status, Request
async def get_collection(
request: Request,
collection_uuid: str,
- current_user: PublicUser,
+ current_user: PublicUser | AnonymousUser,
db_session: Session,
) -> CollectionRead:
statement = select(Collection).where(Collection.collection_uuid == collection_uuid)
@@ -48,6 +48,7 @@ async def get_collection(
statement_all = (
select(Course)
.join(CollectionCourse, Course.id == CollectionCourse.course_id)
+ .where(CollectionCourse.org_id == collection.org_id)
.distinct(Course.id)
)
@@ -57,7 +58,7 @@ async def get_collection(
.where(CollectionCourse.org_id == collection.org_id, Course.public == True)
)
- if current_user.id == 0:
+ if current_user.user_uuid == "user_anonymous":
statement = statement_public
else:
statement = statement_all
@@ -88,7 +89,6 @@ async def create_collection(
# Add collection to database
db_session.add(collection)
db_session.commit()
-
db_session.refresh(collection)
# Link courses to collection
@@ -184,6 +184,7 @@ async def update_collection(
statement = (
select(Course)
.join(CollectionCourse, Course.id == CollectionCourse.course_id)
+ .where(Course.org_id == collection.org_id)
.distinct(Course.id)
)
@@ -255,6 +256,7 @@ async def get_collections(
statement_all = (
select(Course)
.join(CollectionCourse, Course.id == CollectionCourse.course_id)
+ .where(CollectionCourse.org_id == collection.org_id)
.distinct(Course.id)
)
statement_public = (
@@ -297,8 +299,10 @@ async def rbac_check(
detail="User rights : You are not allowed to read this collection",
)
else:
- res = await authorization_verify_based_on_roles_and_authorship_and_usergroups(
- request, current_user.id, action, collection_uuid, db_session
+ res = (
+ await authorization_verify_based_on_roles_and_authorship_and_usergroups(
+ request, current_user.id, action, collection_uuid, db_session
+ )
)
return res
else:
diff --git a/apps/web/app/auth/forgot/forgot.tsx b/apps/web/app/auth/forgot/forgot.tsx
index 8b3cb7c2..ecfce06e 100644
--- a/apps/web/app/auth/forgot/forgot.tsx
+++ b/apps/web/app/auth/forgot/forgot.tsx
@@ -42,6 +42,7 @@ function ForgotPasswordClient() {
email: ''
},
validate,
+ validateOnBlur: true,
onSubmit: async (values) => {
setIsSubmitting(true)
let res = await sendResetLink(values.email, org?.id)
diff --git a/apps/web/app/auth/login/login.tsx b/apps/web/app/auth/login/login.tsx
index e766cf51..49dd7161 100644
--- a/apps/web/app/auth/login/login.tsx
+++ b/apps/web/app/auth/login/login.tsx
@@ -51,8 +51,17 @@ const LoginClient = (props: LoginClientProps) => {
password: '',
},
validate,
- onSubmit: async (values) => {
+ validateOnBlur: true,
+ validateOnChange: true,
+ onSubmit: async (values, {validateForm, setErrors, setSubmitting}) => {
setIsSubmitting(true)
+ const errors = await validateForm(values);
+ if (Object.keys(errors).length > 0) {
+ setErrors(errors);
+ setSubmitting(false);
+ return;
+ }
+
const res = await signIn('credentials', {
redirect: false,
email: values.email,
@@ -139,7 +148,7 @@ const LoginClient = (props: LoginClientProps) => {
onChange={formik.handleChange}
value={formik.values.email}
type="email"
- required
+
/>
@@ -155,7 +164,7 @@ const LoginClient = (props: LoginClientProps) => {
onChange={formik.handleChange}
value={formik.values.password}
type="password"
- required
+
/>
@@ -170,7 +179,7 @@ const LoginClient = (props: LoginClientProps) => {
-
+
{isSubmitting ? 'Loading...' : 'Login'}
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 72183f3a..4dca9687 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
@@ -49,6 +49,7 @@ const EditActivity = async (params: any) => {
{ revalidate: 0, tags: ['activities'] },
access_token ? access_token : null
)
+
const org = await getOrganizationContextInfoWithId(courseInfo.org_id, {
revalidate: 180,
tags: ['organizations'],
diff --git a/apps/web/app/orgs/[orgslug]/dash/page.tsx b/apps/web/app/orgs/[orgslug]/dash/page.tsx
index 9f104e12..acc01033 100644
--- a/apps/web/app/orgs/[orgslug]/dash/page.tsx
+++ b/apps/web/app/orgs/[orgslug]/dash/page.tsx
@@ -1,7 +1,7 @@
import Image from 'next/image'
import React from 'react'
import learnhousetextlogo from '../../../../public/learnhouse_logo.png'
-import { BookCopy, School, Settings, Users } from 'lucide-react'
+import { BookCopy, School, Settings, University, Users } from 'lucide-react'
import Link from 'next/link'
import AdminAuthorization from '@components/Security/AdminAuthorization'
@@ -62,12 +62,13 @@ function DashboardHome() {
-
+
- Learn LearnHouse
+ LearnHouse University
diff --git a/apps/web/app/orgs/[orgslug]/layout.tsx b/apps/web/app/orgs/[orgslug]/layout.tsx
index d722fb9f..de924c3d 100644
--- a/apps/web/app/orgs/[orgslug]/layout.tsx
+++ b/apps/web/app/orgs/[orgslug]/layout.tsx
@@ -1,5 +1,6 @@
'use client'
import { OrgProvider } from '@components/Contexts/OrgContext'
+import NextTopLoader from 'nextjs-toploader';
import Toast from '@components/StyledElements/Toast/Toast'
import '@styles/globals.css'
@@ -13,6 +14,7 @@ export default function RootLayout({
return (
+
{children}
diff --git a/apps/web/components/Contexts/CourseContext.tsx b/apps/web/components/Contexts/CourseContext.tsx
index 11d7d5df..f407cd00 100644
--- a/apps/web/components/Contexts/CourseContext.tsx
+++ b/apps/web/components/Contexts/CourseContext.tsx
@@ -4,6 +4,7 @@ import { swrFetcher } from '@services/utils/ts/requests'
import React, { createContext, useContext, useEffect, useReducer } from 'react'
import useSWR from 'swr'
import { useLHSession } from '@components/Contexts/LHSessionContext'
+import PageLoading from '@components/Objects/Loaders/PageLoading'
export const CourseContext = createContext(null)
export const CourseDispatchContext = createContext(null)
@@ -33,15 +34,17 @@ export function CourseProvider({ children, courseuuid }: any) {
}, [courseStructureData]);
if (error) return
Failed to load course structure
;
- if (!courseStructureData) return
Loading...
;
+ if (!courseStructureData) return '';
- return (
-
-
- {children}
-
-
- )
+ if (courseStructureData) {
+ return (
+
+
+ {children}
+
+
+ )
+ }
}
export function useCourse() {
diff --git a/apps/web/components/Contexts/OrgContext.tsx b/apps/web/components/Contexts/OrgContext.tsx
index f434b3f1..d9482fed 100644
--- a/apps/web/components/Contexts/OrgContext.tsx
+++ b/apps/web/components/Contexts/OrgContext.tsx
@@ -30,7 +30,7 @@ export function OrgProvider({ children, orgslug }: { children: React.ReactNode,
const isUserPartOfTheOrg = useMemo(() => orgs?.some((userOrg: any) => userOrg.id === org?.id), [orgs, org?.id])
if (orgError || orgsError) return
- if (!org || !orgs || !session) return
Loading...
+ if (!org || !orgs || !session) return
if (!isOrgActive) return
if (!isUserPartOfTheOrg && session.status == 'authenticated' && !isAllowedPathname) {
return (
diff --git a/apps/web/components/Dashboard/Course/EditCourseAccess/EditCourseAccess.tsx b/apps/web/components/Dashboard/Course/EditCourseAccess/EditCourseAccess.tsx
index 38ec8b3c..eac3c8db 100644
--- a/apps/web/components/Dashboard/Course/EditCourseAccess/EditCourseAccess.tsx
+++ b/apps/web/components/Dashboard/Course/EditCourseAccess/EditCourseAccess.tsx
@@ -7,7 +7,7 @@ import { unLinkResourcesToUserGroup } from '@services/usergroups/usergroups'
import { swrFetcher } from '@services/utils/ts/requests'
import { Globe, SquareUserRound, Users, X } from 'lucide-react'
import { useLHSession } from '@components/Contexts/LHSessionContext'
-import React from 'react'
+import React, { useEffect, useState } from 'react'
import toast from 'react-hot-toast'
import useSWR, { mutate } from 'swr'
@@ -17,132 +17,132 @@ type EditCourseAccessProps = {
}
function EditCourseAccess(props: EditCourseAccessProps) {
- const [error, setError] = React.useState('')
const session = useLHSession() as any;
const access_token = session?.data?.tokens?.access_token;
-
const course = useCourse() as any;
const { isLoading, courseStructure } = course as any;
- const dispatchCourse = useCourseDispatch() as any
- const { data: usergroups } = useSWR(
- courseStructure ? `${getAPIUrl()}usergroups/resource/${courseStructure.course_uuid}` : null,
- (url) => swrFetcher(url, access_token)
- )
- const [isPublic, setIsPublic] = React.useState(courseStructure.public)
+ const dispatchCourse = useCourseDispatch() as any;
+ const { data: usergroups } = useSWR(courseStructure ? `${getAPIUrl()}usergroups/resource/${courseStructure.course_uuid}` : null, (url) => swrFetcher(url, access_token));
+ const [isClientPublic, setIsClientPublic] = useState
(undefined);
- React.useEffect(() => {
- // This code will run whenever form values are updated
- if ((isPublic !== courseStructure.public) && isLoading) {
- dispatchCourse({ type: 'setIsNotSaved' })
- const updatedCourse = {
- ...courseStructure,
- public: isPublic,
- }
- dispatchCourse({ type: 'setCourseStructure', payload: updatedCourse })
+ useEffect(() => {
+ if (!isLoading && courseStructure?.public !== undefined) {
+ setIsClientPublic(courseStructure.public);
}
- }, [course, isPublic])
+ }, [isLoading, courseStructure]);
+
+ useEffect(() => {
+ if (!isLoading && courseStructure?.public !== undefined && isClientPublic !== undefined) {
+ if (isClientPublic !== courseStructure.public) {
+ dispatchCourse({ type: 'setIsNotSaved' });
+ const updatedCourse = {
+ ...courseStructure,
+ public: isClientPublic,
+ };
+ dispatchCourse({ type: 'setCourseStructure', payload: updatedCourse });
+ }
+ }
+ }, [isLoading, isClientPublic, courseStructure, dispatchCourse]);
+
return (
- {' '}
-
-
-
-
Access to the course
-
- {' '}
- Choose if want your course to be publicly available on the internet or only accessible to signed in users{' '}
-
+ {courseStructure && (
+
+
+
+
+
Access to the course
+
+ Choose if you want your course to be publicly available on the internet or only accessible to signed in users
+
+
+
+
+ {isClientPublic && (
+
+ Active
+
+ )}
+
+
+
+ Public
+
+
+ The Course is publicly available on the internet, it is indexed by search engines and can be accessed by anyone
+
+
+
+ }
+ functionToExecute={() => setIsClientPublic(true)}
+ status="info"
+ />
+
+ {!isClientPublic && (
+
+ Active
+
+ )}
+
+
+
+ Users Only
+
+
+ The Course is only accessible to signed in users, additionally you can choose which UserGroups can access this course
+
+
+
+ }
+ functionToExecute={() => setIsClientPublic(false)}
+ status="info"
+ />
+
+ {!isClientPublic &&
}
+
-
-
- {isPublic ? (
-
- Active
-
- ) : null}
-
-
-
- Public
-
-
- The Course is publicly available on the internet, it is indexed by search engines and can be accessed by anyone
-
-
-
-
- }
- functionToExecute={() => {
- setIsPublic(true)
- }}
- status="info"
- >
-
- {!isPublic ? (
-
- Active
-
- ) : null}
-
-
-
- Users Only
-
-
- The Course is only accessible to signed in users, additionaly you can choose which UserGroups can access this course
-
-
-
-
- }
- functionToExecute={() => {
- setIsPublic(false)
- }}
- status="info"
- >
-
- {!isPublic ? (
) : null}
-
+ )}
- )
+ );
}
-
function UserGroupsSection({ usergroups }: { usergroups: any[] }) {
- const course = useCourse() as any
- const [userGroupModal, setUserGroupModal] = React.useState(false)
+ const course = useCourse() as any;
+ const [userGroupModal, setUserGroupModal] = useState(false);
const session = useLHSession() as any;
const access_token = session?.data?.tokens?.access_token;
const removeUserGroupLink = async (usergroup_id: number) => {
- const res = await unLinkResourcesToUserGroup(usergroup_id, course.courseStructure.course_uuid, access_token)
- if (res.status === 200) {
- toast.success('Successfully unliked from usergroup')
- mutate(`${getAPIUrl()}usergroups/resource/${course.courseStructure.course_uuid}`)
+ try {
+ const res = await unLinkResourcesToUserGroup(usergroup_id, course.courseStructure.course_uuid, access_token);
+ if (res.status === 200) {
+ toast.success('Successfully unlinked from usergroup');
+ mutate(`${getAPIUrl()}usergroups/resource/${course.courseStructure.course_uuid}`);
+ } else {
+ toast.error(`Error ${res.status}: ${res.data.detail}`);
+ }
+ } catch (error) {
+ toast.error('An error occurred while unlinking the user group.');
}
- else {
- toast.error('Error ' + res.status + ': ' + res.data.detail)
- }
- }
+ };
return (
<>
-
+
UserGroups
- {' '}
- You can choose to give access to this course to specific groups of users only by linking it to a UserGroup{' '}
+ You can choose to give access to this course to specific groups of users only by linking it to a UserGroup
@@ -152,67 +152,48 @@ function UserGroupsSection({ usergroups }: { usergroups: any[] }) {
Actions
- <>
-
- {usergroups?.map((usergroup: any) => (
-
- {usergroup.name}
-
-
-
- Delete link
-
- }
- functionToExecute={() => {
- removeUserGroupLink(usergroup.id)
- }}
- status="warning"
- >
-
-
- ))}
-
- >
+
+ {usergroups?.map((usergroup: any) => (
+
+ {usergroup.name}
+
+
+
+ Delete link
+
+ }
+ functionToExecute={() => removeUserGroupLink(usergroup.id)}
+ status="warning"
+ />
+
+
+ ))}
+
-
+
- setUserGroupModal(!userGroupModal)
- }
+ isDialogOpen={userGroupModal}
+ onOpenChange={() => setUserGroupModal(!userGroupModal)}
minHeight="no-min"
- minWidth='md'
- dialogContent={
-
-
- }
+ minWidth="md"
+ dialogContent={ }
dialogTitle="Link Course to a UserGroup"
- dialogDescription={
- 'Choose a UserGroup to link this course to, Users from this UserGroup will have access to this course.'
- }
+ dialogDescription="Choose a UserGroup to link this course to. Users from this UserGroup will have access to this course."
dialogTrigger={
-
+
Link to a UserGroup
}
/>
-
>
- )
+ );
}
-export default EditCourseAccess
\ No newline at end of file
+export default EditCourseAccess;
diff --git a/apps/web/components/Dashboard/Course/EditCourseStructure/DraggableElements/ActivityElement.tsx b/apps/web/components/Dashboard/Course/EditCourseStructure/DraggableElements/ActivityElement.tsx
index d001fa06..a76c72e7 100644
--- a/apps/web/components/Dashboard/Course/EditCourseStructure/DraggableElements/ActivityElement.tsx
+++ b/apps/web/components/Dashboard/Course/EditCourseStructure/DraggableElements/ActivityElement.tsx
@@ -5,6 +5,7 @@ import { revalidateTags } from '@services/utils/ts/requests'
import {
Eye,
File,
+ FilePenLine,
MoreVertical,
Pencil,
Save,
@@ -44,7 +45,7 @@ function ActivityElement(props: ActivitiyElementProps) {
const activityUUID = props.activity.activity_uuid
async function deleteActivityUI() {
- await deleteActivity(props.activity.activity_uuid,access_token)
+ await deleteActivity(props.activity.activity_uuid, access_token)
mutate(`${getAPIUrl()}courses/${props.course_uuid}/meta`)
await revalidateTags(['courses'], props.orgslug)
router.refresh()
@@ -63,7 +64,7 @@ function ActivityElement(props: ActivitiyElementProps) {
content: props.activity.content,
}
- await updateActivity(modifiedActivityCopy, activityUUID,access_token)
+ await updateActivity(modifiedActivityCopy, activityUUID, access_token)
mutate(`${getAPIUrl()}courses/${props.course_uuid}/meta`)
await revalidateTags(['courses'], props.orgslug)
router.refresh()
@@ -141,10 +142,13 @@ function ActivityElement(props: ActivitiyElementProps) {
''
)}/edit`
}
+ prefetch
className=" hover:cursor-pointer p-1 px-3 bg-sky-700 rounded-md items-center"
- rel="noopener noreferrer"
+ target='_blank' // hotfix for an editor prosemirror bug
>
-
Edit
+
+ Edit Page
+
>
)}
@@ -159,10 +163,12 @@ function ActivityElement(props: ActivitiyElementProps) {
''
)}`
}
- className=" hover:cursor-pointer p-1 px-3 bg-gray-200 rounded-md"
+ prefetch
+ className=" hover:cursor-pointer p-1 px-3 bg-gray-200 rounded-md font-bold text-xs flex items-center space-x-1"
rel="noopener noreferrer"
>
-
+
+
Preview
{/* Delete Button */}
diff --git a/apps/web/components/Objects/Editor/Editor.tsx b/apps/web/components/Objects/Editor/Editor.tsx
index d66d92d5..185c8907 100644
--- a/apps/web/components/Objects/Editor/Editor.tsx
+++ b/apps/web/components/Objects/Editor/Editor.tsx
@@ -47,6 +47,7 @@ import useGetAIFeatures from '@components/AI/Hooks/useGetAIFeatures'
import Collaboration from '@tiptap/extension-collaboration'
import CollaborationCursor from '@tiptap/extension-collaboration-cursor'
import ActiveAvatars from './ActiveAvatars'
+import { getUriWithOrg } from '@services/config/config'
interface Editor {
content: string
@@ -182,11 +183,11 @@ function Editor(props: Editor) {
diff --git a/apps/web/components/Objects/Editor/EditorWrapper.tsx b/apps/web/components/Objects/Editor/EditorWrapper.tsx
index aa0c2364..6353a297 100644
--- a/apps/web/components/Objects/Editor/EditorWrapper.tsx
+++ b/apps/web/components/Objects/Editor/EditorWrapper.tsx
@@ -25,7 +25,7 @@ interface EditorWrapperProps {
function EditorWrapper(props: EditorWrapperProps): JSX.Element {
const session = useLHSession() as any
- const access_token = session?.data?.tokens?.access_token;
+ const access_token = session?.data?.tokens?.access_token;
// Define provider in the state
const [provider, setProvider] = React.useState
(null);
const [thisPageColor, setThisPageColor] = useState(randomColor({ luminosity: 'light' }) as string)
@@ -51,7 +51,7 @@ function EditorWrapper(props: EditorWrapperProps): JSX.Element {
}, 10);
};
-
+
// Store the Y document in the browser
new IndexeddbPersistence(props.activity.activity_uuid, doc)
@@ -80,7 +80,7 @@ function EditorWrapper(props: EditorWrapperProps): JSX.Element {
}
});
- toast.promise(updateActivity(activity, activity.activity_uuid,access_token), {
+ toast.promise(updateActivity(activity, activity.activity_uuid, access_token), {
loading: 'Saving...',
success: Activity saved! ,
error: Could not save. ,
diff --git a/apps/web/components/Objects/Menu/MenuLinks.tsx b/apps/web/components/Objects/Menu/MenuLinks.tsx
index d8fa3ebe..3566ff34 100644
--- a/apps/web/components/Objects/Menu/MenuLinks.tsx
+++ b/apps/web/components/Objects/Menu/MenuLinks.tsx
@@ -1,12 +1,13 @@
import AuthenticatedClientElement from '@components/Security/AuthenticatedClientElement'
import { getUriWithOrg } from '@services/config/config'
+import { BookCopy, Signpost, SquareLibrary } from 'lucide-react'
import Link from 'next/link'
import React from 'react'
function MenuLinks(props: { orgslug: string }) {
return (
-
-
+
+
{
const orgslug = props.orgslug
return (
-
+
{props.type == 'courses' && (
<>
-
-
-
+ {' '}
Courses
>
)}
{props.type == 'collections' && (
<>
-
-
-
+ {' '}
Collections
>
)}
{props.type == 'trail' && (
<>
-
-
-
+ {' '}
Trail
>
)}
diff --git a/apps/web/components/Objects/Modals/Activities/Create/NewActivityModal/DynamicCanva.tsx b/apps/web/components/Objects/Modals/Activities/Create/NewActivityModal/DynamicCanva.tsx
index faff1760..7d6082ab 100644
--- a/apps/web/components/Objects/Modals/Activities/Create/NewActivityModal/DynamicCanva.tsx
+++ b/apps/web/components/Objects/Modals/Activities/Create/NewActivityModal/DynamicCanva.tsx
@@ -59,7 +59,7 @@ function DynamicCanvaModal({ submitActivity, chapterId, course }: any) {
-
+
diff --git a/apps/web/components/Objects/Modals/Dash/EditCourseAccess/LinkToUserGroup.tsx b/apps/web/components/Objects/Modals/Dash/EditCourseAccess/LinkToUserGroup.tsx
index cc4b8470..867b03eb 100644
--- a/apps/web/components/Objects/Modals/Dash/EditCourseAccess/LinkToUserGroup.tsx
+++ b/apps/web/components/Objects/Modals/Dash/EditCourseAccess/LinkToUserGroup.tsx
@@ -2,10 +2,11 @@
import { useCourse } from '@components/Contexts/CourseContext';
import { useLHSession } from '@components/Contexts/LHSessionContext';
import { useOrg } from '@components/Contexts/OrgContext';
-import { getAPIUrl } from '@services/config/config';
+import { getAPIUrl, getUriWithOrg } from '@services/config/config';
import { linkResourcesToUserGroup } from '@services/usergroups/usergroups';
import { swrFetcher } from '@services/utils/ts/requests';
import { Info } from 'lucide-react';
+import Link from 'next/link';
import React, { useEffect } from 'react'
import toast from 'react-hot-toast';
import useSWR, { mutate } from 'swr'
@@ -24,7 +25,7 @@ function LinkToUserGroup(props: LinkToUserGroupProps) {
const { data: usergroups } = useSWR(
courseStructure && org ? `${getAPIUrl()}usergroups/org/${org.id}` : null,
- swrFetcher
+ (url) => swrFetcher(url, access_token)
)
const [selectedUserGroup, setSelectedUserGroup] = React.useState(null) as any
@@ -55,19 +56,26 @@ function LinkToUserGroup(props: LinkToUserGroupProps) {
Users that are not part of the UserGroup will no longer have access to this course
+ {usergroups?.length >= 1 &&
+
+
UserGroup Name
-
- UserGroup Name
- setSelectedUserGroup(e.target.value)}
- defaultValue={selectedUserGroup}
- >
- {usergroups && usergroups.map((group: any) => (
- {group.name}
- ))}
+ setSelectedUserGroup(e.target.value)}
+ defaultValue={selectedUserGroup}
+ >
+ {usergroups && usergroups.map((group: any) => (
+ {group.name}
+ ))}
-
-
+
+
+
}
+ {usergroups?.length == 0 &&
+
+ No UserGroups available
+ Create a UserGroup
+
}
{ handleLink() }} className='bg-green-700 text-white font-bold px-4 py-2 rounded-md shadow'>Link
diff --git a/apps/web/components/Objects/Modals/Dash/OrgAccess/OrgInviteCodeGenerate.tsx b/apps/web/components/Objects/Modals/Dash/OrgAccess/OrgInviteCodeGenerate.tsx
index ce67f16a..6e202626 100644
--- a/apps/web/components/Objects/Modals/Dash/OrgAccess/OrgInviteCodeGenerate.tsx
+++ b/apps/web/components/Objects/Modals/Dash/OrgAccess/OrgInviteCodeGenerate.tsx
@@ -1,5 +1,5 @@
import { useOrg } from '@components/Contexts/OrgContext'
-import { getAPIUrl } from '@services/config/config'
+import { getAPIUrl, getUriWithOrg } from '@services/config/config'
import { createInviteCode, createInviteCodeWithUserGroup } from '@services/organizations/invites'
import { swrFetcher } from '@services/utils/ts/requests'
import { Ticket } from 'lucide-react'
@@ -7,6 +7,7 @@ import { useLHSession } from '@components/Contexts/LHSessionContext'
import React, { useEffect } from 'react'
import toast from 'react-hot-toast'
import useSWR, { mutate } from 'swr'
+import Link from 'next/link'
type OrgInviteCodeGenerateProps = {
setInvitesModal: any
@@ -17,9 +18,10 @@ function OrgInviteCodeGenerate(props: OrgInviteCodeGenerateProps) {
const session = useLHSession() as any
const access_token = session?.data?.tokens?.access_token;
const [usergroup_id, setUsergroup_id] = React.useState(0);
+
const { data: usergroups } = useSWR(
org ? `${getAPIUrl()}usergroups/org/${org.id}` : null,
- swrFetcher
+ (url) => swrFetcher(url, access_token)
)
async function createInviteWithUserGroup() {
@@ -55,24 +57,34 @@ function OrgInviteCodeGenerate(props: OrgInviteCodeGenerateProps) {
Invite Code linked to a UserGroup
On Signup, Users will be automatically linked to a UserGroup of your choice
-
- {usergroups?.map((usergroup: any) => (
-
- {usergroup.name}
-
- ))}
-
-
-
-
- Generate
-
-
+ {usergroups?.length >= 1 &&
+
+
+ {usergroups?.map((usergroup: any) => (
+
+ {usergroup.name}
+
+ ))}
+
+
+
+
+
+
+ Generate
+
+
+
}
+ {usergroups?.length == 0 &&
+
+ No UserGroups available
+ Create a UserGroup
+
}
diff --git a/apps/web/components/Objects/Modals/Dash/OrgUserGroups/AddUserGroup.tsx b/apps/web/components/Objects/Modals/Dash/OrgUserGroups/AddUserGroup.tsx
index 9429cd08..9325e264 100644
--- a/apps/web/components/Objects/Modals/Dash/OrgUserGroups/AddUserGroup.tsx
+++ b/apps/web/components/Objects/Modals/Dash/OrgUserGroups/AddUserGroup.tsx
@@ -4,6 +4,7 @@ import FormLayout, {
Flex,
FormField,
FormLabel,
+ FormLabelAndMessage,
FormMessage,
Input,
} from '@components/StyledElements/Form/Form'
@@ -15,86 +16,84 @@ import { createUserGroup } from '@services/usergroups/usergroups'
import { mutate } from 'swr'
import { getAPIUrl } from '@services/config/config'
import { useLHSession } from '@components/Contexts/LHSessionContext'
+import { useFormik } from 'formik'
type AddUserGroupProps = {
setCreateUserGroupModal: any
}
+const validate = (values: any) => {
+ const errors: any = {}
+
+ if (!values.name) {
+ errors.name = 'Name is Required'
+ }
+
+ return errors
+}
function AddUserGroup(props: AddUserGroupProps) {
const org = useOrg() as any;
const session = useLHSession() as any
const access_token = session?.data?.tokens?.access_token;
- const [userGroupName, setUserGroupName] = React.useState('')
- const [userGroupDescription, setUserGroupDescription] = React.useState('')
const [isSubmitting, setIsSubmitting] = React.useState(false)
- const handleNameChange = (event: React.ChangeEvent) => {
- setUserGroupName(event.target.value)
- }
-
- const handleDescriptionChange = (event: React.ChangeEvent) => {
- setUserGroupDescription(event.target.value)
- }
-
- const handleSubmit = async (event: React.FormEvent) => {
- event.preventDefault()
- setIsSubmitting(true)
-
- const obj = {
- name: userGroupName,
- description: userGroupDescription,
+ const formik = useFormik({
+ initialValues: {
+ name: '',
+ description: '',
org_id: org.id
- }
- const res = await createUserGroup(obj, access_token)
- if (res.status == 200) {
- setIsSubmitting(false)
- mutate(`${getAPIUrl()}usergroups/org/${org.id}`)
- props.setCreateUserGroupModal(false)
+ },
+ validate,
+ onSubmit: async (values) => {
+ setIsSubmitting(true)
+ const res = await createUserGroup(values, access_token)
+ if (res.status == 200) {
+ setIsSubmitting(false)
+ mutate(`${getAPIUrl()}usergroups/org/${org.id}`)
+ props.setCreateUserGroupModal(false)
- } else {
- setIsSubmitting(false)
- }
- }
+ } else {
+ setIsSubmitting(false)
+ }
+ },
+ })
return (
-
+
-
- Name
-
- Please provide a ug name
-
-
+
-
+
-
- Description
-
- Please provide a ug description
-
-
+
-
+
-
+
-
- {isSubmitting ? (
-
- ) : (
- 'Create UserGroup'
- )}
-
+
+ {isSubmitting ? 'Loading...' : 'Create a UserGroup'}
+
-
+
)
}
diff --git a/apps/web/components/Objects/Modals/Dash/OrgUserGroups/ManageUsers.tsx b/apps/web/components/Objects/Modals/Dash/OrgUserGroups/ManageUsers.tsx
index f47f9cf1..3e41c8de 100644
--- a/apps/web/components/Objects/Modals/Dash/OrgUserGroups/ManageUsers.tsx
+++ b/apps/web/components/Objects/Modals/Dash/OrgUserGroups/ManageUsers.tsx
@@ -16,14 +16,14 @@ type ManageUsersProps = {
function ManageUsers(props: ManageUsersProps) {
const org = useOrg() as any
const session = useLHSession() as any
- const access_token = session?.data?.tokens?.access_token;
+ const access_token = session?.data?.tokens?.access_token;
const { data: OrgUsers } = useSWR(
org ? `${getAPIUrl()}orgs/${org.id}/users` : null,
- swrFetcher
+ (url) => swrFetcher(url, access_token)
)
const { data: UGusers } = useSWR(
org ? `${getAPIUrl()}usergroups/${props.usergroup_id}/users` : null,
- swrFetcher
+ (url) => swrFetcher(url, access_token)
)
const isUserPartOfGroup = (user_id: any) => {
@@ -34,7 +34,7 @@ function ManageUsers(props: ManageUsersProps) {
}
const handleLinkUser = async (user_id: any) => {
- const res = await linkUserToUserGroup(props.usergroup_id, user_id,access_token)
+ const res = await linkUserToUserGroup(props.usergroup_id, user_id, access_token)
if (res.status === 200) {
toast.success('User linked successfully')
mutate(`${getAPIUrl()}usergroups/${props.usergroup_id}/users`)
@@ -44,7 +44,7 @@ function ManageUsers(props: ManageUsersProps) {
}
const handleUnlinkUser = async (user_id: any) => {
- const res = await unLinkUserToUserGroup(props.usergroup_id, user_id,access_token)
+ const res = await unLinkUserToUserGroup(props.usergroup_id, user_id, access_token)
if (res.status === 200) {
toast.success('User unlinked successfully')
mutate(`${getAPIUrl()}usergroups/${props.usergroup_id}/users`)
diff --git a/apps/web/components/Objects/Thumbnails/CourseThumbnail.tsx b/apps/web/components/Objects/Thumbnails/CourseThumbnail.tsx
index 174b63ae..995daf4a 100644
--- a/apps/web/components/Objects/Thumbnails/CourseThumbnail.tsx
+++ b/apps/web/components/Objects/Thumbnails/CourseThumbnail.tsx
@@ -6,7 +6,7 @@ import { getUriWithOrg } from '@services/config/config'
import { deleteCourseFromBackend } from '@services/courses/courses'
import { getCourseThumbnailMediaDirectory } from '@services/media/media'
import { revalidateTags } from '@services/utils/ts/requests'
-import { Settings, X } from 'lucide-react'
+import { BookMinus, FilePenLine, Settings, Settings2, X, EllipsisVertical } from 'lucide-react'
import { useLHSession } from '@components/Contexts/LHSessionContext'
import Link from 'next/link'
import { useRouter } from 'next/navigation'
@@ -71,7 +71,10 @@ function CourseThumbnail(props: PropsType) {
/>
)}
- {props.course.name}
+
+
{props.course.name}
+ {props.course.description}
+
)
}
@@ -89,7 +92,24 @@ const AdminEditsArea = (props: {
checkMethod="roles"
orgId={props.course.org_id}
>
-
+
}
functionToExecute={() => props.deleteCourses(props.courseId)}
diff --git a/apps/web/components/Security/HeaderProfileBox.tsx b/apps/web/components/Security/HeaderProfileBox.tsx
index ca0b9c50..7c1bb394 100644
--- a/apps/web/components/Security/HeaderProfileBox.tsx
+++ b/apps/web/components/Security/HeaderProfileBox.tsx
@@ -36,7 +36,7 @@ export const HeaderProfileBox = () => {
-
{session.data.user.username}
+
{session.data.user.username}
{isUserAdmin.isAdmin &&
ADMIN
}
diff --git a/apps/web/package.json b/apps/web/package.json
index 9d8dc990..44deefd7 100644
--- a/apps/web/package.json
+++ b/apps/web/package.json
@@ -39,8 +39,9 @@
"katex": "^0.16.10",
"lowlight": "^3.1.0",
"lucide-react": "^0.363.0",
- "next": "14.2.3",
+ "next": "14.2.4",
"next-auth": "^4.24.7",
+ "nextjs-toploader": "^1.6.12",
"prosemirror-state": "^1.4.3",
"randomcolor": "^0.6.2",
"re-resizable": "^6.9.17",
@@ -59,7 +60,7 @@
"tailwind-scrollbar": "^3.1.0",
"uuid": "^9.0.1",
"y-indexeddb": "^9.0.12",
- "y-prosemirror": "^1.2.6",
+ "y-prosemirror": "^1.2.8",
"y-webrtc": "^10.3.0",
"yjs": "^13.6.16"
},
diff --git a/apps/web/pnpm-lock.yaml b/apps/web/pnpm-lock.yaml
index e39fc0e6..5d924813 100644
--- a/apps/web/pnpm-lock.yaml
+++ b/apps/web/pnpm-lock.yaml
@@ -43,10 +43,10 @@ importers:
version: 2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))(@tiptap/extension-code-block@2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))(@tiptap/pm@2.4.0))(@tiptap/pm@2.4.0)
'@tiptap/extension-collaboration':
specifier: ^2.4.0
- version: 2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))(@tiptap/pm@2.4.0)(y-prosemirror@1.2.6(prosemirror-model@1.21.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.7)(y-protocols@1.0.6(yjs@13.6.16))(yjs@13.6.16))
+ version: 2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))(@tiptap/pm@2.4.0)(y-prosemirror@1.2.8(prosemirror-model@1.21.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.7)(y-protocols@1.0.6(yjs@13.6.16))(yjs@13.6.16))
'@tiptap/extension-collaboration-cursor':
specifier: ^2.4.0
- version: 2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))(y-prosemirror@1.2.6(prosemirror-model@1.21.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.7)(y-protocols@1.0.6(yjs@13.6.16))(yjs@13.6.16))
+ version: 2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))(y-prosemirror@1.2.8(prosemirror-model@1.21.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.7)(y-protocols@1.0.6(yjs@13.6.16))(yjs@13.6.16))
'@tiptap/extension-youtube':
specifier: ^2.4.0
version: 2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))
@@ -93,11 +93,14 @@ importers:
specifier: ^0.363.0
version: 0.363.0(react@18.3.1)
next:
- specifier: 14.2.3
- version: 14.2.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ specifier: 14.2.4
+ version: 14.2.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
next-auth:
specifier: ^4.24.7
- version: 4.24.7(next@14.2.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ version: 4.24.7(next@14.2.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ nextjs-toploader:
+ specifier: ^1.6.12
+ version: 1.6.12(next@14.2.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
prosemirror-state:
specifier: ^1.4.3
version: 1.4.3
@@ -153,8 +156,8 @@ importers:
specifier: ^9.0.12
version: 9.0.12(yjs@13.6.16)
y-prosemirror:
- specifier: ^1.2.6
- version: 1.2.6(prosemirror-model@1.21.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.7)(y-protocols@1.0.6(yjs@13.6.16))(yjs@13.6.16)
+ specifier: ^1.2.8
+ version: 1.2.8(prosemirror-model@1.21.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.7)(y-protocols@1.0.6(yjs@13.6.16))(yjs@13.6.16)
y-webrtc:
specifier: ^10.3.0
version: 10.3.0(yjs@13.6.16)
@@ -427,62 +430,62 @@ packages:
'@lifeomic/attempt@3.1.0':
resolution: {integrity: sha512-QZqem4QuAnAyzfz+Gj5/+SLxqwCAw2qmt7732ZXodr6VDWGeYLG6w1i/vYLa55JQM9wRuBKLmXmiZ2P0LtE5rw==}
- '@next/env@14.2.3':
- resolution: {integrity: sha512-W7fd7IbkfmeeY2gXrzJYDx8D2lWKbVoTIj1o1ScPHNzvp30s1AuoEFSdr39bC5sjxJaxTtq3OTCZboNp0lNWHA==}
+ '@next/env@14.2.4':
+ resolution: {integrity: sha512-3EtkY5VDkuV2+lNmKlbkibIJxcO4oIHEhBWne6PaAp+76J9KoSsGvNikp6ivzAT8dhhBMYrm6op2pS1ApG0Hzg==}
'@next/eslint-plugin-next@14.2.3':
resolution: {integrity: sha512-L3oDricIIjgj1AVnRdRor21gI7mShlSwU/1ZGHmqM3LzHhXXhdkrfeNY5zif25Bi5Dd7fiJHsbhoZCHfXYvlAw==}
- '@next/swc-darwin-arm64@14.2.3':
- resolution: {integrity: sha512-3pEYo/RaGqPP0YzwnlmPN2puaF2WMLM3apt5jLW2fFdXD9+pqcoTzRk+iZsf8ta7+quAe4Q6Ms0nR0SFGFdS1A==}
+ '@next/swc-darwin-arm64@14.2.4':
+ resolution: {integrity: sha512-AH3mO4JlFUqsYcwFUHb1wAKlebHU/Hv2u2kb1pAuRanDZ7pD/A/KPD98RHZmwsJpdHQwfEc/06mgpSzwrJYnNg==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [darwin]
- '@next/swc-darwin-x64@14.2.3':
- resolution: {integrity: sha512-6adp7waE6P1TYFSXpY366xwsOnEXM+y1kgRpjSRVI2CBDOcbRjsJ67Z6EgKIqWIue52d2q/Mx8g9MszARj8IEA==}
+ '@next/swc-darwin-x64@14.2.4':
+ resolution: {integrity: sha512-QVadW73sWIO6E2VroyUjuAxhWLZWEpiFqHdZdoQ/AMpN9YWGuHV8t2rChr0ahy+irKX5mlDU7OY68k3n4tAZTg==}
engines: {node: '>= 10'}
cpu: [x64]
os: [darwin]
- '@next/swc-linux-arm64-gnu@14.2.3':
- resolution: {integrity: sha512-cuzCE/1G0ZSnTAHJPUT1rPgQx1w5tzSX7POXSLaS7w2nIUJUD+e25QoXD/hMfxbsT9rslEXugWypJMILBj/QsA==}
+ '@next/swc-linux-arm64-gnu@14.2.4':
+ resolution: {integrity: sha512-KT6GUrb3oyCfcfJ+WliXuJnD6pCpZiosx2X3k66HLR+DMoilRb76LpWPGb4tZprawTtcnyrv75ElD6VncVamUQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
- '@next/swc-linux-arm64-musl@14.2.3':
- resolution: {integrity: sha512-0D4/oMM2Y9Ta3nGuCcQN8jjJjmDPYpHX9OJzqk42NZGJocU2MqhBq5tWkJrUQOQY9N+In9xOdymzapM09GeiZw==}
+ '@next/swc-linux-arm64-musl@14.2.4':
+ resolution: {integrity: sha512-Alv8/XGSs/ytwQcbCHwze1HmiIkIVhDHYLjczSVrf0Wi2MvKn/blt7+S6FJitj3yTlMwMxII1gIJ9WepI4aZ/A==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
- '@next/swc-linux-x64-gnu@14.2.3':
- resolution: {integrity: sha512-ENPiNnBNDInBLyUU5ii8PMQh+4XLr4pG51tOp6aJ9xqFQ2iRI6IH0Ds2yJkAzNV1CfyagcyzPfROMViS2wOZ9w==}
+ '@next/swc-linux-x64-gnu@14.2.4':
+ resolution: {integrity: sha512-ze0ShQDBPCqxLImzw4sCdfnB3lRmN3qGMB2GWDRlq5Wqy4G36pxtNOo2usu/Nm9+V2Rh/QQnrRc2l94kYFXO6Q==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
- '@next/swc-linux-x64-musl@14.2.3':
- resolution: {integrity: sha512-BTAbq0LnCbF5MtoM7I/9UeUu/8ZBY0i8SFjUMCbPDOLv+un67e2JgyN4pmgfXBwy/I+RHu8q+k+MCkDN6P9ViQ==}
+ '@next/swc-linux-x64-musl@14.2.4':
+ resolution: {integrity: sha512-8dwC0UJoc6fC7PX70csdaznVMNr16hQrTDAMPvLPloazlcaWfdPogq+UpZX6Drqb1OBlwowz8iG7WR0Tzk/diQ==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
- '@next/swc-win32-arm64-msvc@14.2.3':
- resolution: {integrity: sha512-AEHIw/dhAMLNFJFJIJIyOFDzrzI5bAjI9J26gbO5xhAKHYTZ9Or04BesFPXiAYXDNdrwTP2dQceYA4dL1geu8A==}
+ '@next/swc-win32-arm64-msvc@14.2.4':
+ resolution: {integrity: sha512-jxyg67NbEWkDyvM+O8UDbPAyYRZqGLQDTPwvrBBeOSyVWW/jFQkQKQ70JDqDSYg1ZDdl+E3nkbFbq8xM8E9x8A==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [win32]
- '@next/swc-win32-ia32-msvc@14.2.3':
- resolution: {integrity: sha512-vga40n1q6aYb0CLrM+eEmisfKCR45ixQYXuBXxOOmmoV8sYST9k7E3US32FsY+CkkF7NtzdcebiFT4CHuMSyZw==}
+ '@next/swc-win32-ia32-msvc@14.2.4':
+ resolution: {integrity: sha512-twrmN753hjXRdcrZmZttb/m5xaCBFa48Dt3FbeEItpJArxriYDunWxJn+QFXdJ3hPkm4u7CKxncVvnmgQMY1ag==}
engines: {node: '>= 10'}
cpu: [ia32]
os: [win32]
- '@next/swc-win32-x64-msvc@14.2.3':
- resolution: {integrity: sha512-Q1/zm43RWynxrO7lW4ehciQVj+5ePBhOK+/K2P7pLFX3JaJ/IZVC69SHidrmZSOkqz7ECIOhhy7XhAFG4JYyHA==}
+ '@next/swc-win32-x64-msvc@14.2.4':
+ resolution: {integrity: sha512-tkLrjBzqFTP8DVrAAQmZelEahfR9OxWpFR++vAI9FBhCiIxtwHwBHC23SBHCTURBtwB4kc/x44imVOnkKGNVGg==}
engines: {node: '>= 10'}
cpu: [x64]
os: [win32]
@@ -2082,8 +2085,8 @@ packages:
nodemailer:
optional: true
- next@14.2.3:
- resolution: {integrity: sha512-dowFkFTR8v79NPJO4QsBUtxv0g9BrS/phluVpMAt2ku7H+cbcBJlopXjkWlwxrk/xGqMemr7JkGPGemPrLLX7A==}
+ next@14.2.4:
+ resolution: {integrity: sha512-R8/V7vugY+822rsQGQCjoLhMuC9oFj9SOi4Cl4b2wjDrseD0LRZ10W7R6Czo4w9ZznVSshKjuIomsRjvm9EKJQ==}
engines: {node: '>=18.17.0'}
hasBin: true
peerDependencies:
@@ -2100,6 +2103,13 @@ packages:
sass:
optional: true
+ nextjs-toploader@1.6.12:
+ resolution: {integrity: sha512-nbun5lvVjlKnxLQlahzZ55nELVEduqoEXT03KCHnsEYJnFpI/3BaIzpMyq/v8C7UGU2NfxQmjq6ldZ310rsDqA==}
+ peerDependencies:
+ next: '>= 6.0.0'
+ react: '>= 16.0.0'
+ react-dom: '>= 16.0.0'
+
node-releases@2.0.14:
resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==}
@@ -2111,6 +2121,9 @@ packages:
resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==}
engines: {node: '>=0.10.0'}
+ nprogress@0.2.0:
+ resolution: {integrity: sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==}
+
oauth@0.9.15:
resolution: {integrity: sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA==}
@@ -2891,8 +2904,8 @@ packages:
peerDependencies:
yjs: ^13.0.0
- y-prosemirror@1.2.6:
- resolution: {integrity: sha512-rGz8kX4v/uFJrLaqZvsezY1JGN/zTDSPMO76zRbNcpE63OEiw2PBCEQi9ZlfbEwgCMoeJLUT+otNyO/Oj73TGQ==}
+ y-prosemirror@1.2.8:
+ resolution: {integrity: sha512-xNDOEe9ViBXck0qwcTvzGgj832ecoz8GQSppoh6PwUokbXoEBDbAH76Qs15HOiatjZkSODHRGdpYlLBBkJPiGA==}
engines: {node: '>=16.0.0', npm: '>=8.0.0'}
peerDependencies:
prosemirror-model: ^1.7.1
@@ -3137,37 +3150,37 @@ snapshots:
'@lifeomic/attempt@3.1.0': {}
- '@next/env@14.2.3': {}
+ '@next/env@14.2.4': {}
'@next/eslint-plugin-next@14.2.3':
dependencies:
glob: 10.3.10
- '@next/swc-darwin-arm64@14.2.3':
+ '@next/swc-darwin-arm64@14.2.4':
optional: true
- '@next/swc-darwin-x64@14.2.3':
+ '@next/swc-darwin-x64@14.2.4':
optional: true
- '@next/swc-linux-arm64-gnu@14.2.3':
+ '@next/swc-linux-arm64-gnu@14.2.4':
optional: true
- '@next/swc-linux-arm64-musl@14.2.3':
+ '@next/swc-linux-arm64-musl@14.2.4':
optional: true
- '@next/swc-linux-x64-gnu@14.2.3':
+ '@next/swc-linux-x64-gnu@14.2.4':
optional: true
- '@next/swc-linux-x64-musl@14.2.3':
+ '@next/swc-linux-x64-musl@14.2.4':
optional: true
- '@next/swc-win32-arm64-msvc@14.2.3':
+ '@next/swc-win32-arm64-msvc@14.2.4':
optional: true
- '@next/swc-win32-ia32-msvc@14.2.3':
+ '@next/swc-win32-ia32-msvc@14.2.4':
optional: true
- '@next/swc-win32-x64-msvc@14.2.3':
+ '@next/swc-win32-x64-msvc@14.2.4':
optional: true
'@nodelib/fs.scandir@2.1.5':
@@ -3536,16 +3549,16 @@ snapshots:
dependencies:
'@tiptap/core': 2.4.0(@tiptap/pm@2.4.0)
- '@tiptap/extension-collaboration-cursor@2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))(y-prosemirror@1.2.6(prosemirror-model@1.21.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.7)(y-protocols@1.0.6(yjs@13.6.16))(yjs@13.6.16))':
+ '@tiptap/extension-collaboration-cursor@2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))(y-prosemirror@1.2.8(prosemirror-model@1.21.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.7)(y-protocols@1.0.6(yjs@13.6.16))(yjs@13.6.16))':
dependencies:
'@tiptap/core': 2.4.0(@tiptap/pm@2.4.0)
- y-prosemirror: 1.2.6(prosemirror-model@1.21.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.7)(y-protocols@1.0.6(yjs@13.6.16))(yjs@13.6.16)
+ y-prosemirror: 1.2.8(prosemirror-model@1.21.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.7)(y-protocols@1.0.6(yjs@13.6.16))(yjs@13.6.16)
- '@tiptap/extension-collaboration@2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))(@tiptap/pm@2.4.0)(y-prosemirror@1.2.6(prosemirror-model@1.21.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.7)(y-protocols@1.0.6(yjs@13.6.16))(yjs@13.6.16))':
+ '@tiptap/extension-collaboration@2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))(@tiptap/pm@2.4.0)(y-prosemirror@1.2.8(prosemirror-model@1.21.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.7)(y-protocols@1.0.6(yjs@13.6.16))(yjs@13.6.16))':
dependencies:
'@tiptap/core': 2.4.0(@tiptap/pm@2.4.0)
'@tiptap/pm': 2.4.0
- y-prosemirror: 1.2.6(prosemirror-model@1.21.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.7)(y-protocols@1.0.6(yjs@13.6.16))(yjs@13.6.16)
+ y-prosemirror: 1.2.8(prosemirror-model@1.21.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.7)(y-protocols@1.0.6(yjs@13.6.16))(yjs@13.6.16)
'@tiptap/extension-document@2.4.0(@tiptap/core@2.4.0(@tiptap/pm@2.4.0))':
dependencies:
@@ -4237,7 +4250,7 @@ snapshots:
eslint: 8.57.0
eslint-import-resolver-node: 0.3.9
eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.4))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0)
- eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.4))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
+ eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.4))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.4))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0)
eslint-plugin-jsx-a11y: 6.8.0(eslint@8.57.0)
eslint-plugin-react: 7.34.2(eslint@8.57.0)
eslint-plugin-react-hooks: 4.6.2(eslint@8.57.0)
@@ -4261,7 +4274,7 @@ snapshots:
enhanced-resolve: 5.17.0
eslint: 8.57.0
eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.4))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0)
- eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.4))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
+ eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.4))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.4))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0)
fast-glob: 3.3.2
get-tsconfig: 4.7.5
is-core-module: 2.13.1
@@ -4283,7 +4296,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
- eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.4))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0):
+ eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.4))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.4))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0):
dependencies:
array-includes: 3.1.8
array.prototype.findlastindex: 1.2.5
@@ -4928,13 +4941,13 @@ snapshots:
natural-compare@1.4.0: {}
- next-auth@4.24.7(next@14.2.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
+ next-auth@4.24.7(next@14.2.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
'@babel/runtime': 7.24.7
'@panva/hkdf': 1.1.1
cookie: 0.5.0
jose: 4.15.5
- next: 14.2.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ next: 14.2.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
oauth: 0.9.15
openid-client: 5.6.5
preact: 10.22.0
@@ -4943,9 +4956,9 @@ snapshots:
react-dom: 18.3.1(react@18.3.1)
uuid: 8.3.2
- next@14.2.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
+ next@14.2.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
- '@next/env': 14.2.3
+ '@next/env': 14.2.4
'@swc/helpers': 0.5.5
busboy: 1.6.0
caniuse-lite: 1.0.30001632
@@ -4955,25 +4968,35 @@ snapshots:
react-dom: 18.3.1(react@18.3.1)
styled-jsx: 5.1.1(react@18.3.1)
optionalDependencies:
- '@next/swc-darwin-arm64': 14.2.3
- '@next/swc-darwin-x64': 14.2.3
- '@next/swc-linux-arm64-gnu': 14.2.3
- '@next/swc-linux-arm64-musl': 14.2.3
- '@next/swc-linux-x64-gnu': 14.2.3
- '@next/swc-linux-x64-musl': 14.2.3
- '@next/swc-win32-arm64-msvc': 14.2.3
- '@next/swc-win32-ia32-msvc': 14.2.3
- '@next/swc-win32-x64-msvc': 14.2.3
+ '@next/swc-darwin-arm64': 14.2.4
+ '@next/swc-darwin-x64': 14.2.4
+ '@next/swc-linux-arm64-gnu': 14.2.4
+ '@next/swc-linux-arm64-musl': 14.2.4
+ '@next/swc-linux-x64-gnu': 14.2.4
+ '@next/swc-linux-x64-musl': 14.2.4
+ '@next/swc-win32-arm64-msvc': 14.2.4
+ '@next/swc-win32-ia32-msvc': 14.2.4
+ '@next/swc-win32-x64-msvc': 14.2.4
transitivePeerDependencies:
- '@babel/core'
- babel-plugin-macros
+ nextjs-toploader@1.6.12(next@14.2.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
+ dependencies:
+ next: 14.2.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ nprogress: 0.2.0
+ prop-types: 15.8.1
+ react: 18.3.1
+ react-dom: 18.3.1(react@18.3.1)
+
node-releases@2.0.14: {}
normalize-path@3.0.0: {}
normalize-range@0.1.2: {}
+ nprogress@0.2.0: {}
+
oauth@0.9.15: {}
object-assign@4.1.1: {}
@@ -5880,7 +5903,7 @@ snapshots:
lib0: 0.2.94
yjs: 13.6.16
- y-prosemirror@1.2.6(prosemirror-model@1.21.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.7)(y-protocols@1.0.6(yjs@13.6.16))(yjs@13.6.16):
+ y-prosemirror@1.2.8(prosemirror-model@1.21.1)(prosemirror-state@1.4.3)(prosemirror-view@1.33.7)(y-protocols@1.0.6(yjs@13.6.16))(yjs@13.6.16):
dependencies:
lib0: 0.2.94
prosemirror-model: 1.21.1
diff --git a/apps/web/services/config/config.ts b/apps/web/services/config/config.ts
index c9ec36d0..b7ac9d56 100644
--- a/apps/web/services/config/config.ts
+++ b/apps/web/services/config/config.ts
@@ -51,3 +51,5 @@ export const getDefaultOrg = () => {
export const getCollaborationServerUrl = () => {
return `${LEARNHOUSE_COLLABORATION_WS_URL}`
}
+
+