diff --git a/apps/collaboration/pnpm-lock.yaml b/apps/collaboration/pnpm-lock.yaml
index 867e9b80..47fd3b6f 100644
--- a/apps/collaboration/pnpm-lock.yaml
+++ b/apps/collaboration/pnpm-lock.yaml
@@ -10,7 +10,7 @@ importers:
dependencies:
'@hocuspocus/server':
specifier: ^2.11.3
- version: 2.11.3(y-protocols@1.0.6)(yjs@13.6.14)
+ version: 2.11.3(y-protocols@1.0.6(yjs@13.6.14))(yjs@13.6.14)
bun:
specifier: ^1.0.36
version: 1.1.1
@@ -133,7 +133,7 @@ snapshots:
dependencies:
lib0: 0.2.93
- '@hocuspocus/server@2.11.3(y-protocols@1.0.6)(yjs@13.6.14)':
+ '@hocuspocus/server@2.11.3(y-protocols@1.0.6(yjs@13.6.14))(yjs@13.6.14)':
dependencies:
'@hocuspocus/common': 2.11.3
async-lock: 1.4.1
diff --git a/apps/web/app/auth/options.ts b/apps/web/app/auth/options.ts
index fe82d753..6559887d 100644
--- a/apps/web/app/auth/options.ts
+++ b/apps/web/app/auth/options.ts
@@ -42,7 +42,7 @@ export const nextAuthOptions = {
}),
],
callbacks: {
- async jwt({ token, user, account }) {
+ async jwt({ token, user, account }: any) {
// First sign in with Credentials provider
if (account?.provider == 'credentials' && user) {
token.user = user
@@ -78,7 +78,7 @@ export const nextAuthOptions = {
}
return token
},
- async session({ session, token }) {
+ async session({ session, token }: any) {
// Include user information in the session
if (token.user) {
let api_SESSION = await getUserSession(token.user.tokens.access_token)
diff --git a/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/loading.tsx b/apps/web/app/editor/course/[courseid]/activity/[activityuuid]/edit/loading.tsx
similarity index 98%
rename from apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/loading.tsx
rename to apps/web/app/editor/course/[courseid]/activity/[activityuuid]/edit/loading.tsx
index 3da44848..a6338cbf 100644
--- a/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/loading.tsx
+++ b/apps/web/app/editor/course/[courseid]/activity/[activityuuid]/edit/loading.tsx
@@ -3,4 +3,4 @@ import PageLoading from '@components/Objects/Loaders/PageLoading'
export default function Loading() {
// Or a custom loading skeleton component
return
-}
+}
\ No newline at end of file
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 9cad3186..b8e36ade 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,13 +1,13 @@
import { default as React } from 'react'
import dynamic from 'next/dynamic'
-import { getCourseMetadataWithAuthHeader } from '@services/courses/courses'
-import { cookies } from 'next/headers'
+import { getCourseMetadata } from '@services/courses/courses'
import { Metadata } from 'next'
import { getActivityWithAuthHeader } from '@services/courses/activities'
-import { getAccessTokenFromRefreshTokenCookie } from '@services/auth/auth'
import { getOrganizationContextInfoWithId } from '@services/organizations/orgs'
import EditorOptionsProvider from '@components/Contexts/Editor/EditorContext'
import AIEditorProvider from '@components/Contexts/AI/AIEditorContext'
+import { nextAuthOptions } from 'app/auth/options'
+import { getServerSession } from 'next-auth'
const EditorWrapper = dynamic(() => import('@components/Objects/Editor/EditorWrapper'), { ssr: false })
@@ -19,10 +19,10 @@ type MetadataProps = {
export async function generateMetadata({
params,
}: MetadataProps): Promise {
- const cookieStore = cookies()
- const access_token = await getAccessTokenFromRefreshTokenCookie(cookieStore)
+ const session = await getServerSession(nextAuthOptions)
+ const access_token = session?.tokens?.access_token
// Get Org context information
- const course_meta = await getCourseMetadataWithAuthHeader(
+ const course_meta = await getCourseMetadata(
params.courseid,
{ revalidate: 0, tags: ['courses'] },
access_token ? access_token : null
@@ -35,11 +35,11 @@ export async function generateMetadata({
}
const EditActivity = async (params: any) => {
- const cookieStore = cookies()
- const access_token = await getAccessTokenFromRefreshTokenCookie(cookieStore)
+ const session = await getServerSession(nextAuthOptions)
+ const access_token = session?.tokens?.access_token
const activityuuid = params.params.activityuuid
const courseid = params.params.courseid
- const courseInfo = await getCourseMetadataWithAuthHeader(
+ const courseInfo = await getCourseMetadata(
courseid,
{ revalidate: 0, tags: ['courses'] },
access_token ? access_token : null
diff --git a/apps/web/app/install/steps/account_creation.tsx b/apps/web/app/install/steps/account_creation.tsx
index 98cc1760..1a8d8531 100644
--- a/apps/web/app/install/steps/account_creation.tsx
+++ b/apps/web/app/install/steps/account_creation.tsx
@@ -10,6 +10,7 @@ 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 { useLHSession } from '@components/Contexts/LHSessionContext'
import { useRouter } from 'next/navigation'
import React from 'react'
import { BarLoader } from 'react-spinners'
@@ -47,11 +48,13 @@ const validate = (values: any) => {
function AccountCreation() {
const [isSubmitting, setIsSubmitting] = React.useState(false)
+ const session = useLHSession() as any;
+ const access_token = session?.data?.tokens?.access_token;
const {
data: install,
error: error,
isLoading,
- } = useSWR(`${getAPIUrl()}install/latest`, swrFetcher)
+ } = useSWR(`${getAPIUrl()}install/latest`, (url) => swrFetcher(url, access_token))
const router = useRouter()
const formik = useFormik({
initialValues: {
diff --git a/apps/web/app/install/steps/default_elements.tsx b/apps/web/app/install/steps/default_elements.tsx
index 53b19190..b5f54bb6 100644
--- a/apps/web/app/install/steps/default_elements.tsx
+++ b/apps/web/app/install/steps/default_elements.tsx
@@ -1,16 +1,19 @@
import { getAPIUrl } from '@services/config/config'
import { createDefaultElements, updateInstall } from '@services/install/install'
import { swrFetcher } from '@services/utils/ts/requests'
+import { useLHSession } from '@components/Contexts/LHSessionContext'
import { useRouter } from 'next/navigation'
import React from 'react'
import useSWR from 'swr'
function DefaultElements() {
+ const session = useLHSession() as any;
+ const access_token = session?.data?.tokens?.access_token;
const {
data: install,
error: error,
isLoading,
- } = useSWR(`${getAPIUrl()}install/latest`, swrFetcher)
+ } = useSWR(`${getAPIUrl()}install/latest`, (url) => swrFetcher(url, access_token))
const [isSubmitting, setIsSubmitting] = React.useState(false)
const [isSubmitted, setIsSubmitted] = React.useState(false)
const router = useRouter()
diff --git a/apps/web/app/install/steps/finish.tsx b/apps/web/app/install/steps/finish.tsx
index 8bb09fe3..853908ec 100644
--- a/apps/web/app/install/steps/finish.tsx
+++ b/apps/web/app/install/steps/finish.tsx
@@ -2,16 +2,19 @@ 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 { useLHSession } from '@components/Contexts/LHSessionContext'
import { useRouter } from 'next/navigation'
import React from 'react'
import useSWR from 'swr'
const Finish = () => {
+ const session = useLHSession() as any;
+ const access_token = session?.data?.tokens?.access_token;
const {
data: install,
error: error,
isLoading,
- } = useSWR(`${getAPIUrl()}install/latest`, swrFetcher)
+ } = useSWR(`${getAPIUrl()}install/latest`, (url) => swrFetcher(url, access_token))
const router = useRouter()
async function finishInstall() {
diff --git a/apps/web/app/install/steps/get_started.tsx b/apps/web/app/install/steps/get_started.tsx
index 1c247b97..75483613 100644
--- a/apps/web/app/install/steps/get_started.tsx
+++ b/apps/web/app/install/steps/get_started.tsx
@@ -1,16 +1,19 @@
import PageLoading from '@components/Objects/Loaders/PageLoading'
import { getAPIUrl } from '@services/config/config'
import { swrFetcher } from '@services/utils/ts/requests'
+import { useLHSession } from '@components/Contexts/LHSessionContext'
import { useRouter } from 'next/navigation'
import React, { useEffect } from 'react'
import useSWR, { mutate } from 'swr'
function GetStarted() {
+ const session = useLHSession() as any;
+ const access_token = session?.data?.tokens?.access_token;
const {
data: install,
error: error,
isLoading,
- } = useSWR(`${getAPIUrl()}install/latest`, swrFetcher)
+ } = useSWR(`${getAPIUrl()}install/latest`, (url) => swrFetcher(url, access_token))
const router = useRouter()
async function startInstallation() {
diff --git a/apps/web/app/install/steps/org_creation.tsx b/apps/web/app/install/steps/org_creation.tsx
index 11ac9810..5efd2c93 100644
--- a/apps/web/app/install/steps/org_creation.tsx
+++ b/apps/web/app/install/steps/org_creation.tsx
@@ -14,6 +14,7 @@ import useSWR from 'swr'
import { createNewOrgInstall, updateInstall } from '@services/install/install'
import { useRouter } from 'next/navigation'
import { Check } from 'lucide-react'
+import { useLHSession } from '@components/Contexts/LHSessionContext'
const validate = (values: any) => {
const errors: any = {}
@@ -40,11 +41,13 @@ const validate = (values: any) => {
}
function OrgCreation() {
+ const session = useLHSession() as any;
+ const access_token = session?.data?.tokens?.access_token;
const {
data: install,
error: error,
isLoading,
- } = useSWR(`${getAPIUrl()}install/latest`, swrFetcher)
+ } = useSWR(`${getAPIUrl()}install/latest`, (url) => swrFetcher(url, access_token))
const [isSubmitting, setIsSubmitting] = React.useState(false)
const [isSubmitted, setIsSubmitted] = React.useState(false)
const router = useRouter()
diff --git a/apps/web/app/install/steps/sample_data.tsx b/apps/web/app/install/steps/sample_data.tsx
index 7a174283..217cc547 100644
--- a/apps/web/app/install/steps/sample_data.tsx
+++ b/apps/web/app/install/steps/sample_data.tsx
@@ -4,16 +4,19 @@ import {
updateInstall,
} from '@services/install/install'
import { swrFetcher } from '@services/utils/ts/requests'
+import { useLHSession } from '@components/Contexts/LHSessionContext'
import { useRouter } from 'next/navigation'
import React from 'react'
import useSWR from 'swr'
function SampleData() {
+ const session = useLHSession() as any;
+ const access_token = session?.data?.tokens?.access_token;
const {
data: install,
error: error,
isLoading,
- } = useSWR(`${getAPIUrl()}install/latest`, swrFetcher)
+ } = useSWR(`${getAPIUrl()}install/latest`, (url) => swrFetcher(url, access_token))
const router = useRouter()
function createSampleData() {
diff --git a/apps/web/app/layout.tsx b/apps/web/app/layout.tsx
index e22e22f2..93dcdc2d 100644
--- a/apps/web/app/layout.tsx
+++ b/apps/web/app/layout.tsx
@@ -3,6 +3,7 @@ import '../styles/globals.css'
import StyledComponentsRegistry from '../components/Utils/libs/styled-registry'
import { motion } from 'framer-motion'
import { SessionProvider } from 'next-auth/react'
+import LHSessionProvider from '@components/Contexts/LHSessionContext'
export default function RootLayout({
children,
@@ -19,18 +20,20 @@ export default function RootLayout({
-
-
- {children}
-
-
+
+
+
+ {children}
+
+
+
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 a93d57d9..f2182c38 100644
--- a/apps/web/app/orgs/[orgslug]/(withmenu)/collection/[collectionid]/page.tsx
+++ b/apps/web/app/orgs/[orgslug]/(withmenu)/collection/[collectionid]/page.tsx
@@ -1,10 +1,11 @@
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 { getCollectionById } from '@services/courses/collections'
import { getCourseThumbnailMediaDirectory } from '@services/media/media'
import { getOrganizationContextInfo } from '@services/organizations/orgs'
+import { nextAuthOptions } from 'app/auth/options'
import { Metadata } from 'next'
+import { getServerSession } from 'next-auth'
import { cookies } from 'next/headers'
import Link from 'next/link'
@@ -16,15 +17,15 @@ type MetadataProps = {
export async function generateMetadata({
params,
}: MetadataProps): Promise {
- const cookieStore = cookies()
- const access_token = await getAccessTokenFromRefreshTokenCookie(cookieStore)
+ const session = await getServerSession(nextAuthOptions)
+ const access_token = session?.tokens?.access_token
// Get Org context information
const org = await getOrganizationContextInfo(params.orgslug, {
revalidate: 1800,
tags: ['organizations'],
})
- const col = await getCollectionByIdWithAuthHeader(
+ const col = await getCollectionById(
params.collectionid,
access_token ? access_token : null,
{ revalidate: 0, tags: ['collections'] }
@@ -53,14 +54,14 @@ export async function generateMetadata({
}
const CollectionPage = async (params: any) => {
- const cookieStore = cookies()
- const access_token = await getAccessTokenFromRefreshTokenCookie(cookieStore)
+ const session = await getServerSession(nextAuthOptions)
+ const access_token = session?.tokens?.access_token
const org = await getOrganizationContextInfo(params.params.orgslug, {
revalidate: 1800,
tags: ['organizations'],
})
const orgslug = params.params.orgslug
- const col = await getCollectionByIdWithAuthHeader(
+ const col = await getCollectionById(
params.params.collectionid,
access_token ? access_token : null,
{ revalidate: 0, tags: ['collections'] }
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 77708f79..be8cbd01 100644
--- a/apps/web/app/orgs/[orgslug]/(withmenu)/collections/new/page.tsx
+++ b/apps/web/app/orgs/[orgslug]/(withmenu)/collections/new/page.tsx
@@ -6,9 +6,12 @@ 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'
+import { useLHSession } from '@components/Contexts/LHSessionContext'
function NewCollection(params: any) {
const org = useOrg() as any
+ const session = useLHSession() as any;
+ const access_token = session?.data?.tokens?.access_token;
const orgslug = params.params.orgslug
const [name, setName] = React.useState('')
const [description, setDescription] = React.useState('')
@@ -16,7 +19,7 @@ function NewCollection(params: any) {
const router = useRouter()
const { data: courses, error: error } = useSWR(
`${getAPIUrl()}courses/org_slug/${orgslug}/page/1/limit/10`,
- swrFetcher
+ (url) => swrFetcher(url, access_token)
)
const [isPublic, setIsPublic] = useState('true')
@@ -44,7 +47,7 @@ function NewCollection(params: any) {
public: isPublic,
org_id: org.id,
}
- await createCollection(collection)
+ await createCollection(collection, session.data?.tokens?.access_token)
await revalidateTags(['collections'], org.slug)
// reload the page
router.refresh()
diff --git a/apps/web/app/orgs/[orgslug]/(withmenu)/collections/page.tsx b/apps/web/app/orgs/[orgslug]/(withmenu)/collections/page.tsx
index aaed61cf..50f02a06 100644
--- a/apps/web/app/orgs/[orgslug]/(withmenu)/collections/page.tsx
+++ b/apps/web/app/orgs/[orgslug]/(withmenu)/collections/page.tsx
@@ -2,7 +2,6 @@ import AuthenticatedClientElement from '@components/Security/AuthenticatedClient
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'
@@ -11,6 +10,9 @@ import { getAccessTokenFromRefreshTokenCookie } from '@services/auth/auth'
import CollectionThumbnail from '@components/Objects/Thumbnails/CollectionThumbnail'
import NewCollectionButton from '@components/StyledElements/Buttons/NewCollectionButton'
import ContentPlaceHolderIfUserIsNotAdmin from '@components/ContentPlaceHolder'
+import { nextAuthOptions } from 'app/auth/options'
+import { getServerSession } from 'next-auth'
+import { getOrgCollections } from '@services/courses/collections'
type MetadataProps = {
params: { orgslug: string; courseid: string }
@@ -49,15 +51,15 @@ export async function generateMetadata({
}
const CollectionsPage = async (params: any) => {
- const cookieStore = cookies()
- const access_token = await getAccessTokenFromRefreshTokenCookie(cookieStore)
+ const session = await getServerSession(nextAuthOptions)
+ const access_token = session?.tokens?.access_token
const orgslug = params.params.orgslug
const org = await getOrganizationContextInfo(orgslug, {
revalidate: 1800,
tags: ['organizations'],
})
const org_id = org.id
- const collections = await getOrgCollectionsWithAuthHeader(
+ const collections = await getOrgCollections(
org_id,
access_token ? access_token : null,
{ revalidate: 0, tags: ['collections'] }
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 f7c91833..aa2641eb 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
@@ -15,6 +15,7 @@ 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'
+import { useLHSession } from '@components/Contexts/LHSessionContext'
interface ActivityClientProps {
activityid: string
@@ -106,11 +107,10 @@ function ActivityClient(props: ActivityClientProps) {
{activity ? (
{activity.activity_type == 'TYPE_DYNAMIC' && (
@@ -147,13 +147,15 @@ export function MarkStatus(props: {
orgslug: string
}) {
const router = useRouter()
+ const session = useLHSession()
console.log(props.course.trail)
async function markActivityAsCompleteFront() {
const trail = await markActivityAsComplete(
props.orgslug,
props.course.course_uuid,
- 'activity_' + props.activityid
+ 'activity_' + props.activityid,
+ session.data?.tokens?.access_token
)
router.refresh()
}
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 1cf87b7f..b834eae6 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,10 +1,12 @@
import { getActivityWithAuthHeader } from '@services/courses/activities'
-import { getCourseMetadataWithAuthHeader } from '@services/courses/courses'
+import { getCourseMetadata } 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 { getServerSession } from 'next-auth'
+import { nextAuthOptions } from 'app/auth/options'
type MetadataProps = {
params: { orgslug: string; courseuuid: string; activityid: string }
@@ -14,15 +16,15 @@ type MetadataProps = {
export async function generateMetadata({
params,
}: MetadataProps): Promise
{
- const cookieStore = cookies()
- const access_token = await getAccessTokenFromRefreshTokenCookie(cookieStore)
+ const session = await getServerSession(nextAuthOptions)
+ const access_token = session?.tokens?.access_token
// Get Org context information
const org = await getOrganizationContextInfo(params.orgslug, {
revalidate: 1800,
tags: ['organizations'],
})
- const course_meta = await getCourseMetadataWithAuthHeader(
+ const course_meta = await getCourseMetadata(
params.courseuuid,
{ revalidate: 0, tags: ['courses'] },
access_token ? access_token : null
@@ -58,13 +60,13 @@ export async function generateMetadata({
}
const ActivityPage = async (params: any) => {
- const cookieStore = cookies()
- const access_token = await getAccessTokenFromRefreshTokenCookie(cookieStore)
+ const session = await getServerSession(nextAuthOptions)
+ const access_token = session?.tokens?.access_token
const activityid = params.params.activityid
const courseuuid = params.params.courseuuid
const orgslug = params.params.orgslug
- const course_meta = await getCourseMetadataWithAuthHeader(
+ const course_meta = await getCourseMetadata(
courseuuid,
{ revalidate: 0, tags: ['courses'] },
access_token ? access_token : null
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 fd58842b..d7c48e59 100644
--- a/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/course.tsx
+++ b/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/course.tsx
@@ -17,10 +17,12 @@ import { useOrg } from '@components/Contexts/OrgContext'
import UserAvatar from '@components/Objects/UserAvatar'
import CourseUpdates from '@components/Objects/CourseUpdates/CourseUpdates'
import { CourseProvider } from '@components/Contexts/CourseContext'
+import { useLHSession } from '@components/Contexts/LHSessionContext'
const CourseClient = (props: any) => {
const [user, setUser] = useState({})
const [learnings, setLearnings] = useState([])
+ const session = useLHSession()
const courseuuid = props.courseuuid
const orgslug = props.orgslug
const course = props.course
@@ -35,7 +37,7 @@ const CourseClient = (props: any) => {
async function startCourseUI() {
// Create activity
- await startCourse('course_' + courseuuid, orgslug)
+ await startCourse('course_' + courseuuid, orgslug, session.data?.tokens?.access_token)
await revalidateTags(['courses'], orgslug)
router.refresh()
@@ -54,7 +56,7 @@ const CourseClient = (props: any) => {
async function quitCourse() {
// Close activity
- let activity = await removeCourse('course_' + courseuuid, orgslug)
+ let activity = await removeCourse('course_' + courseuuid, orgslug, session.data?.tokens?.access_token)
// Mutate course
await revalidateTags(['courses'], orgslug)
router.refresh()
@@ -277,7 +279,7 @@ const CourseClient = (props: any) => {
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 f26b7caa..ae96404e 100644
--- a/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/page.tsx
+++ b/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/page.tsx
@@ -1,11 +1,13 @@
import React from 'react'
import CourseClient from './course'
import { cookies } from 'next/headers'
-import { getCourseMetadataWithAuthHeader } from '@services/courses/courses'
+import { getCourseMetadata } from '@services/courses/courses'
import { getOrganizationContextInfo } from '@services/organizations/orgs'
import { Metadata } from 'next'
import { getAccessTokenFromRefreshTokenCookie } from '@services/auth/auth'
import { getCourseThumbnailMediaDirectory } from '@services/media/media'
+import { nextAuthOptions } from 'app/auth/options'
+import { getServerSession } from 'next-auth'
type MetadataProps = {
params: { orgslug: string; courseuuid: string }
@@ -15,15 +17,15 @@ type MetadataProps = {
export async function generateMetadata({
params,
}: MetadataProps): Promise
{
- const cookieStore = cookies()
- const access_token = await getAccessTokenFromRefreshTokenCookie(cookieStore)
+ const session = await getServerSession(nextAuthOptions)
+ const access_token = session?.tokens?.access_token
// Get Org context information
const org = await getOrganizationContextInfo(params.orgslug, {
revalidate: 1800,
tags: ['organizations'],
})
- const course_meta = await getCourseMetadataWithAuthHeader(
+ const course_meta = await getCourseMetadata(
params.courseuuid,
{ revalidate: 0, tags: ['courses'] },
access_token ? access_token : null
@@ -67,11 +69,11 @@ export async function generateMetadata({
}
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(
+ const session = await getServerSession(nextAuthOptions)
+ const access_token = session?.tokens?.access_token
+ const course_meta = await getCourseMetadata(
courseuuid,
{ revalidate: 0, tags: ['courses'] },
access_token ? access_token : null
diff --git a/apps/web/app/orgs/[orgslug]/(withmenu)/courses/page.tsx b/apps/web/app/orgs/[orgslug]/(withmenu)/courses/page.tsx
index d7c8baca..6f15306d 100644
--- a/apps/web/app/orgs/[orgslug]/(withmenu)/courses/page.tsx
+++ b/apps/web/app/orgs/[orgslug]/(withmenu)/courses/page.tsx
@@ -1,10 +1,12 @@
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 { nextAuthOptions } from 'app/auth/options'
+import { getServerSession } from 'next-auth'
+import { getOrgCourses } from '@services/courses/courses'
type MetadataProps = {
params: { orgslug: string }
@@ -49,9 +51,10 @@ const CoursesPage = async (params: any) => {
revalidate: 1800,
tags: ['organizations'],
})
- const cookieStore = cookies()
- const access_token = await getAccessTokenFromRefreshTokenCookie(cookieStore)
- const courses = await getOrgCoursesWithAuthHeader(
+ const session = await getServerSession(nextAuthOptions)
+ const access_token = session?.tokens?.access_token
+
+ const courses = await getOrgCourses(
orgslug,
{ revalidate: 0, tags: ['courses'] },
access_token ? access_token : null
diff --git a/apps/web/app/orgs/[orgslug]/(withmenu)/page.tsx b/apps/web/app/orgs/[orgslug]/(withmenu)/page.tsx
index b8bc5d0a..5718bb98 100644
--- a/apps/web/app/orgs/[orgslug]/(withmenu)/page.tsx
+++ b/apps/web/app/orgs/[orgslug]/(withmenu)/page.tsx
@@ -1,20 +1,20 @@
export const dynamic = 'force-dynamic'
import { Metadata } from 'next'
import { getUriWithOrg } from '@services/config/config'
-import { getOrgCoursesWithAuthHeader } from '@services/courses/courses'
+import { getOrgCourses } 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'
import ContentPlaceHolderIfUserIsNotAdmin from '@components/ContentPlaceHolder'
+import { getOrgCollections } from '@services/courses/collections'
+import { getServerSession } from 'next-auth'
+import { nextAuthOptions } from 'app/auth/options'
type MetadataProps = {
params: { orgslug: string }
@@ -54,10 +54,9 @@ export async function generateMetadata({
const OrgHomePage = async (params: any) => {
const orgslug = params.params.orgslug
- const cookieStore = cookies()
-
- const access_token = await getAccessTokenFromRefreshTokenCookie(cookieStore)
- const courses = await getOrgCoursesWithAuthHeader(
+ const session = await getServerSession(nextAuthOptions)
+ const access_token = session?.tokens?.access_token
+ const courses = await getOrgCourses(
orgslug,
{ revalidate: 0, tags: ['courses'] },
access_token ? access_token : null
@@ -67,7 +66,7 @@ const OrgHomePage = async (params: any) => {
tags: ['organizations'],
})
const org_id = org.id
- const collections = await getOrgCollectionsWithAuthHeader(
+ const collections = await getOrgCollections(
org.id,
access_token ? access_token : null,
{ revalidate: 0, tags: ['courses'] }
diff --git a/apps/web/app/orgs/[orgslug]/dash/ClientAdminLayout.tsx b/apps/web/app/orgs/[orgslug]/dash/ClientAdminLayout.tsx
new file mode 100644
index 00000000..32778e18
--- /dev/null
+++ b/apps/web/app/orgs/[orgslug]/dash/ClientAdminLayout.tsx
@@ -0,0 +1,26 @@
+'use client';
+import LeftMenu from '@components/Dashboard/UI/LeftMenu'
+import AdminAuthorization from '@components/Security/AdminAuthorization'
+import { SessionProvider } from 'next-auth/react'
+import React from 'react'
+
+function ClientAdminLayout({
+ children,
+ params,
+}: {
+ children: React.ReactNode
+ params: any
+}) {
+ return (
+
+
+
+
+
+ )
+}
+
+export default ClientAdminLayout
\ No newline at end of file
diff --git a/apps/web/app/orgs/[orgslug]/dash/courses/client.tsx b/apps/web/app/orgs/[orgslug]/dash/courses/client.tsx
index cce3a585..31ae5ce3 100644
--- a/apps/web/app/orgs/[orgslug]/dash/courses/client.tsx
+++ b/apps/web/app/orgs/[orgslug]/dash/courses/client.tsx
@@ -30,7 +30,6 @@ function CoursesHome(params: CourseProps) {
-
Courses
-
-
-
+
+ {children}
+
>
)
}
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 fa542767..6162f70e 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
@@ -7,7 +7,7 @@ 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 'next-auth/react'
+import { useLHSession } from '@components/Contexts/LHSessionContext'
export type SettingsParams = {
subpage: string
@@ -15,7 +15,7 @@ export type SettingsParams = {
}
function SettingsPage({ params }: { params: SettingsParams }) {
- const session = useSession() as any
+ const session = useLHSession() as any
useEffect(() => {}, [session])
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 1950e259..995c3a68 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
@@ -5,7 +5,7 @@ import Link from 'next/link'
import { getUriWithOrg } from '@services/config/config'
import { ScanEye, SquareUserRound, UserPlus, Users } from 'lucide-react'
import BreadCrumbs from '@components/Dashboard/UI/BreadCrumbs'
-import { useSession } from 'next-auth/react'
+import { useLHSession } from '@components/Contexts/LHSessionContext'
import { useOrg } from '@components/Contexts/OrgContext'
import OrgUsers from '@components/Dashboard/Users/OrgUsers/OrgUsers'
import OrgAccess from '@components/Dashboard/Users/OrgAccess/OrgAccess'
@@ -18,7 +18,7 @@ export type SettingsParams = {
}
function UsersSettingsPage({ params }: { params: SettingsParams }) {
- const session = useSession() as any
+ const session = useLHSession() as any
const org = useOrg() as any
const [H1Label, setH1Label] = React.useState('')
const [H2Label, setH2Label] = React.useState('')
diff --git a/apps/web/app/orgs/[orgslug]/layout.tsx b/apps/web/app/orgs/[orgslug]/layout.tsx
index 219e1707..bdef53c9 100644
--- a/apps/web/app/orgs/[orgslug]/layout.tsx
+++ b/apps/web/app/orgs/[orgslug]/layout.tsx
@@ -1,8 +1,8 @@
'use client'
+import LHSessionProvider from '@components/Contexts/LHSessionContext'
import { OrgProvider } from '@components/Contexts/OrgContext'
import Toast from '@components/StyledElements/Toast/Toast'
import '@styles/globals.css'
-import { SessionProvider } from 'next-auth/react'
export default function RootLayout({
children,
@@ -13,9 +13,9 @@ export default function RootLayout({
}) {
return (
-
- {children}
+
+ {children}
)
diff --git a/apps/web/app/orgs/[orgslug]/login/login.tsx b/apps/web/app/orgs/[orgslug]/login/login.tsx
index 9394005d..2cfebac8 100644
--- a/apps/web/app/orgs/[orgslug]/login/login.tsx
+++ b/apps/web/app/orgs/[orgslug]/login/login.tsx
@@ -10,12 +10,12 @@ 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 { signIn, useSession } from "next-auth/react"
import { getUriWithOrg } from '@services/config/config'
+import { useLHSession } from '@components/Contexts/LHSessionContext'
interface LoginClientProps {
org: any
@@ -42,7 +42,7 @@ const validate = (values: any) => {
const LoginClient = (props: LoginClientProps) => {
const [isSubmitting, setIsSubmitting] = React.useState(false)
const router = useRouter();
- const session = useSession();
+ const session = useLHSession();
const [error, setError] = React.useState('')
const formik = useFormik({
@@ -53,19 +53,21 @@ const LoginClient = (props: LoginClientProps) => {
validate,
onSubmit: async (values) => {
setIsSubmitting(true)
- //let res = await loginAndGetToken(values.email, values.password)
const res = await signIn('credentials', {
redirect: false,
email: values.email,
password: values.password,
+ callbackUrl: '/'
});
if (res && res.error) {
setError("Wrong Email or password");
setIsSubmitting(false);
- }
- else {
- router.push(`/`)
- setIsSubmitting(false)
+ }else {
+ await signIn('credentials', {
+ email: values.email,
+ password: values.password,
+ callbackUrl: '/'
+ });
}
},
})
diff --git a/apps/web/app/orgs/[orgslug]/signup/signup.tsx b/apps/web/app/orgs/[orgslug]/signup/signup.tsx
index 3f222f57..128b46b6 100644
--- a/apps/web/app/orgs/[orgslug]/signup/signup.tsx
+++ b/apps/web/app/orgs/[orgslug]/signup/signup.tsx
@@ -4,7 +4,7 @@ import Image from 'next/image'
import { getOrgLogoMediaDirectory } from '@services/media/media'
import Link from 'next/link'
import { getUriWithOrg } from '@services/config/config'
-import { useSession } from 'next-auth/react'
+import { useLHSession } from '@components/Contexts/LHSessionContext'
import React, { useEffect } from 'react'
import { MailWarning, Shield, Ticket, UserPlus } from 'lucide-react'
import { useOrg } from '@components/Contexts/OrgContext'
@@ -22,7 +22,7 @@ interface SignUpClientProps {
}
function SignUpClient(props: SignUpClientProps) {
- const session = useSession() as any
+ const session = useLHSession() as any
const [joinMethod, setJoinMethod] = React.useState('open')
const [inviteCode, setInviteCode] = React.useState('')
const searchParams = useSearchParams()
@@ -113,7 +113,7 @@ function SignUpClient(props: SignUpClientProps) {
}
const LoggedInJoinScreen = (props: any) => {
- const session = useSession() as any
+ const session = useLHSession() as any
const org = useOrg() as any
const [isLoading, setIsLoading] = React.useState(true)
@@ -144,7 +144,7 @@ const LoggedInJoinScreen = (props: any) => {
}
const NoTokenScreen = (props: any) => {
- const session = useSession() as any
+ const session = useLHSession() as any
const org = useOrg() as any
const router = useRouter()
const [isLoading, setIsLoading] = React.useState(true)
diff --git a/apps/web/components/Contexts/CourseContext.tsx b/apps/web/components/Contexts/CourseContext.tsx
index aed51150..ddcf711c 100644
--- a/apps/web/components/Contexts/CourseContext.tsx
+++ b/apps/web/components/Contexts/CourseContext.tsx
@@ -4,6 +4,7 @@ import { getAPIUrl } from '@services/config/config'
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'
export const CourseContext = createContext(null) as any
export const CourseDispatchContext = createContext(null) as any
@@ -15,9 +16,11 @@ export function CourseProvider({
children: React.ReactNode
courseuuid: string
}) {
+ const session = useLHSession() as any;
+ const access_token = session?.data?.tokens?.access_token;
const { data: courseStructureData } = useSWR(
`${getAPIUrl()}courses/${courseuuid}/meta`,
- swrFetcher
+ (url) => swrFetcher(url, access_token)
)
const [courseStructure, dispatchCourseStructure] = useReducer(courseReducer, {
courseStructure: courseStructureData ? courseStructureData : {},
@@ -33,7 +36,7 @@ export function CourseProvider({
payload: courseStructureData,
})
}
- }, [courseStructureData])
+ }, [courseStructureData,session])
if (!courseStructureData) return
diff --git a/apps/web/components/Contexts/LHSessionContext.tsx b/apps/web/components/Contexts/LHSessionContext.tsx
new file mode 100644
index 00000000..5b2bdcad
--- /dev/null
+++ b/apps/web/components/Contexts/LHSessionContext.tsx
@@ -0,0 +1,33 @@
+'use client'
+import PageLoading from '@components/Objects/Loaders/PageLoading';
+import { useSession } from 'next-auth/react';
+import React, { useContext, createContext, useEffect } from 'react'
+
+export const SessionContext = createContext({}) as any
+
+function LHSessionProvider({ children }: { children: React.ReactNode }) {
+ const session = useSession();
+
+ useEffect(() => {
+ console.log('useLHSession', session);
+ }, [session])
+
+
+ if (session.status == 'loading') {
+ return
+ }
+
+ else {
+ return (
+
+ {children}
+
+ )
+ }
+}
+
+export function useLHSession() {
+ return useContext(SessionContext)
+}
+
+export default LHSessionProvider
\ No newline at end of file
diff --git a/apps/web/components/Contexts/OrgContext.tsx b/apps/web/components/Contexts/OrgContext.tsx
index 1362cb45..28ab6c94 100644
--- a/apps/web/components/Contexts/OrgContext.tsx
+++ b/apps/web/components/Contexts/OrgContext.tsx
@@ -5,6 +5,8 @@ import React, { useContext, useEffect } from 'react'
import useSWR from 'swr'
import { createContext } from 'react'
import { useRouter } from 'next/navigation'
+import { useLHSession } from '@components/Contexts/LHSessionContext'
+import ErrorUI from '@components/StyledElements/Error/Error'
export const OrgContext = createContext({}) as any
@@ -15,7 +17,10 @@ export function OrgProvider({
children: React.ReactNode
orgslug: string
}) {
- const { data: org } = useSWR(`${getAPIUrl()}orgs/slug/${orgslug}`, swrFetcher)
+ const session = useLHSession() as any;
+ const access_token = session?.data?.tokens?.access_token;
+ const { data: org } = useSWR(`${getAPIUrl()}orgs/slug/${orgslug}`, (url) => swrFetcher(url, access_token))
+
const router = useRouter()
// Check if Org is Active
const verifyIfOrgIsActive = () => {
@@ -28,7 +33,12 @@ export function OrgProvider({
verifyIfOrgIsActive()
}, [org])
- return {children}
+ if (org) {
+ return {children}
+ }
+ else {
+ return
+ }
}
export function useOrg() {
diff --git a/apps/web/components/Dashboard/Course/EditCourseAccess/EditCourseAccess.tsx b/apps/web/components/Dashboard/Course/EditCourseAccess/EditCourseAccess.tsx
index 9fa1abc3..1f5eceaf 100644
--- a/apps/web/components/Dashboard/Course/EditCourseAccess/EditCourseAccess.tsx
+++ b/apps/web/components/Dashboard/Course/EditCourseAccess/EditCourseAccess.tsx
@@ -6,6 +6,7 @@ import { getAPIUrl } from '@services/config/config'
import { unLinkResourcesToUserGroup } from '@services/usergroups/usergroups'
import { swrFetcher } from '@services/utils/ts/requests'
import { Globe, SquareUserRound, Users, UsersRound, X } from 'lucide-react'
+import { useLHSession } from '@components/Contexts/LHSessionContext'
import React from 'react'
import toast from 'react-hot-toast'
import useSWR, { mutate } from 'swr'
@@ -17,13 +18,15 @@ 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 dispatchCourse = useCourseDispatch() as any
const courseStructure = course.courseStructure
const { data: usergroups } = useSWR(
courseStructure ? `${getAPIUrl()}usergroups/resource/${courseStructure.course_uuid}` : null,
- swrFetcher
+ (url) => swrFetcher(url, access_token)
)
const [isPublic, setIsPublic] = React.useState(courseStructure.public)
@@ -109,7 +112,7 @@ function EditCourseAccess(props: EditCourseAccessProps) {
status="info"
>
- {!isPublic ? (
) : null}
+ {!isPublic ? (
) : null}
)
diff --git a/apps/web/components/Dashboard/Course/EditCourseGeneral/ThumbnailUpdate.tsx b/apps/web/components/Dashboard/Course/EditCourseGeneral/ThumbnailUpdate.tsx
index 2a3fce58..85c47764 100644
--- a/apps/web/components/Dashboard/Course/EditCourseGeneral/ThumbnailUpdate.tsx
+++ b/apps/web/components/Dashboard/Course/EditCourseGeneral/ThumbnailUpdate.tsx
@@ -4,11 +4,13 @@ import { getAPIUrl } from '@services/config/config'
import { updateCourseThumbnail } from '@services/courses/courses'
import { getCourseThumbnailMediaDirectory } from '@services/media/media'
import { ArrowBigUpDash, UploadCloud } from 'lucide-react'
+import { useLHSession } from '@components/Contexts/LHSessionContext'
import React from 'react'
import { mutate } from 'swr'
function ThumbnailUpdate() {
const course = useCourse() as any
+ const session = useLHSession()
const org = useOrg() as any
const [localThumbnail, setLocalThumbnail] = React.useState(null) as any
const [isLoading, setIsLoading] = React.useState(false) as any
@@ -20,7 +22,8 @@ function ThumbnailUpdate() {
setIsLoading(true)
const res = await updateCourseThumbnail(
course.courseStructure.course_uuid,
- file
+ file,
+ session.data?.tokens?.access_token
)
mutate(`${getAPIUrl()}courses/${course.courseStructure.course_uuid}/meta`)
// wait for 1 second to show loading animation
diff --git a/apps/web/components/Dashboard/Course/EditCourseStructure/Buttons/NewActivityButton.tsx b/apps/web/components/Dashboard/Course/EditCourseStructure/Buttons/NewActivityButton.tsx
index 0926d669..afa30d9a 100644
--- a/apps/web/components/Dashboard/Course/EditCourseStructure/Buttons/NewActivityButton.tsx
+++ b/apps/web/components/Dashboard/Course/EditCourseStructure/Buttons/NewActivityButton.tsx
@@ -10,6 +10,7 @@ import {
import { getOrganizationContextInfoWithoutCredentials } from '@services/organizations/orgs'
import { revalidateTags } from '@services/utils/ts/requests'
import { Layers } from 'lucide-react'
+import { useLHSession } from '@components/Contexts/LHSessionContext'
import { useRouter } from 'next/navigation'
import React, { useEffect } from 'react'
import { mutate } from 'swr'
@@ -23,6 +24,8 @@ function NewActivityButton(props: NewActivityButtonProps) {
const [newActivityModal, setNewActivityModal] = React.useState(false)
const router = useRouter()
const course = useCourse() as any
+ const session = useLHSession() as any;
+ const access_token = session?.data?.tokens?.access_token;
const openNewActivityModal = async (chapterId: any) => {
setNewActivityModal(true)
@@ -38,7 +41,7 @@ function NewActivityButton(props: NewActivityButtonProps) {
props.orgslug,
{ revalidate: 1800 }
)
- await createActivity(activity, props.chapterId, org.org_id)
+ await createActivity(activity, props.chapterId, org.org_id, access_token)
mutate(`${getAPIUrl()}courses/${course.courseStructure.course_uuid}/meta`)
setNewActivityModal(false)
await revalidateTags(['courses'], props.orgslug)
@@ -52,7 +55,7 @@ function NewActivityButton(props: NewActivityButtonProps) {
activity: any,
chapterId: string
) => {
- await createFileActivity(file, type, activity, chapterId)
+ await createFileActivity(file, type, activity, chapterId, access_token)
mutate(`${getAPIUrl()}courses/${course.courseStructure.course_uuid}/meta`)
setNewActivityModal(false)
await revalidateTags(['courses'], props.orgslug)
@@ -68,7 +71,7 @@ function NewActivityButton(props: NewActivityButtonProps) {
await createExternalVideoActivity(
external_video_data,
activity,
- props.chapterId
+ props.chapterId, access_token
)
mutate(`${getAPIUrl()}courses/${course.courseStructure.course_uuid}/meta`)
setNewActivityModal(false)
@@ -76,7 +79,7 @@ function NewActivityButton(props: NewActivityButtonProps) {
router.refresh()
}
- useEffect(() => {}, [course])
+ useEffect(() => { }, [course])
return (
diff --git a/apps/web/components/Dashboard/Course/EditCourseStructure/DraggableElements/ActivityElement.tsx b/apps/web/components/Dashboard/Course/EditCourseStructure/DraggableElements/ActivityElement.tsx
index 4b182c7e..d001fa06 100644
--- a/apps/web/components/Dashboard/Course/EditCourseStructure/DraggableElements/ActivityElement.tsx
+++ b/apps/web/components/Dashboard/Course/EditCourseStructure/DraggableElements/ActivityElement.tsx
@@ -12,6 +12,7 @@ import {
Video,
X,
} from 'lucide-react'
+import { useLHSession } from '@components/Contexts/LHSessionContext'
import Link from 'next/link'
import { useRouter } from 'next/navigation'
import React from 'react'
@@ -32,6 +33,8 @@ interface ModifiedActivityInterface {
function ActivityElement(props: ActivitiyElementProps) {
const router = useRouter()
+ const session = useLHSession() as any;
+ const access_token = session?.data?.tokens?.access_token;
const [modifiedActivity, setModifiedActivity] = React.useState<
ModifiedActivityInterface | undefined
>(undefined)
@@ -41,7 +44,7 @@ function ActivityElement(props: ActivitiyElementProps) {
const activityUUID = props.activity.activity_uuid
async function deleteActivityUI() {
- await deleteActivity(props.activity.activity_uuid)
+ await deleteActivity(props.activity.activity_uuid,access_token)
mutate(`${getAPIUrl()}courses/${props.course_uuid}/meta`)
await revalidateTags(['courses'], props.orgslug)
router.refresh()
@@ -60,7 +63,7 @@ function ActivityElement(props: ActivitiyElementProps) {
content: props.activity.content,
}
- await updateActivity(modifiedActivityCopy, activityUUID)
+ await updateActivity(modifiedActivityCopy, activityUUID,access_token)
mutate(`${getAPIUrl()}courses/${props.course_uuid}/meta`)
await revalidateTags(['courses'], props.orgslug)
router.refresh()
diff --git a/apps/web/components/Dashboard/Course/EditCourseStructure/DraggableElements/ChapterElement.tsx b/apps/web/components/Dashboard/Course/EditCourseStructure/DraggableElements/ChapterElement.tsx
index ac96b86b..092dd5e7 100644
--- a/apps/web/components/Dashboard/Course/EditCourseStructure/DraggableElements/ChapterElement.tsx
+++ b/apps/web/components/Dashboard/Course/EditCourseStructure/DraggableElements/ChapterElement.tsx
@@ -16,6 +16,7 @@ import { revalidateTags } from '@services/utils/ts/requests'
import { useRouter } from 'next/navigation'
import { getAPIUrl } from '@services/config/config'
import { mutate } from 'swr'
+import { useLHSession } from '@components/Contexts/LHSessionContext'
type ChapterElementProps = {
chapter: any
@@ -31,6 +32,8 @@ interface ModifiedChapterInterface {
function ChapterElement(props: ChapterElementProps) {
const activities = props.chapter.activities || []
+ const session = useLHSession() as any;
+ const access_token = session?.data?.tokens?.access_token;
const [modifiedChapter, setModifiedChapter] = React.useState<
ModifiedChapterInterface | undefined
>(undefined)
@@ -41,7 +44,7 @@ function ChapterElement(props: ChapterElementProps) {
const router = useRouter()
const deleteChapterUI = async () => {
- await deleteChapter(props.chapter.id)
+ await deleteChapter(props.chapter.id, access_token)
mutate(`${getAPIUrl()}courses/${props.course_uuid}/meta`)
await revalidateTags(['courses'], props.orgslug)
router.refresh()
@@ -53,7 +56,7 @@ function ChapterElement(props: ChapterElementProps) {
let modifiedChapterCopy = {
name: modifiedChapter.chapterName,
}
- await updateChapter(chapterId, modifiedChapterCopy)
+ await updateChapter(chapterId, modifiedChapterCopy, access_token)
mutate(`${getAPIUrl()}courses/${props.course_uuid}/meta`)
await revalidateTags(['courses'], props.orgslug)
router.refresh()
diff --git a/apps/web/components/Dashboard/Course/EditCourseStructure/EditCourseStructure.tsx b/apps/web/components/Dashboard/Course/EditCourseStructure/EditCourseStructure.tsx
index bb81597b..f9b5b24a 100644
--- a/apps/web/components/Dashboard/Course/EditCourseStructure/EditCourseStructure.tsx
+++ b/apps/web/components/Dashboard/Course/EditCourseStructure/EditCourseStructure.tsx
@@ -15,6 +15,7 @@ import {
import { Hexagon } from 'lucide-react'
import Modal from '@components/StyledElements/Modal/Modal'
import NewChapterModal from '@components/Objects/Modals/Chapters/NewChapter'
+import { useLHSession } from '@components/Contexts/LHSessionContext'
type EditCourseStructureProps = {
orgslug: string
@@ -38,6 +39,8 @@ export type OrderPayload =
const EditCourseStructure = (props: EditCourseStructureProps) => {
const router = useRouter()
+ const session = useLHSession() as any;
+ const access_token = session?.data?.tokens?.access_token;
// Check window availability
const [winReady, setwinReady] = useState(false)
@@ -57,7 +60,7 @@ const EditCourseStructure = (props: EditCourseStructureProps) => {
// Submit new chapter
const submitChapter = async (chapter: any) => {
- await createChapter(chapter)
+ await createChapter(chapter,access_token)
mutate(`${getAPIUrl()}courses/${course.courseStructure.course_uuid}/meta`)
await revalidateTags(['courses'], props.orgslug)
router.refresh()
diff --git a/apps/web/components/Dashboard/UI/LeftMenu.tsx b/apps/web/components/Dashboard/UI/LeftMenu.tsx
index 9986c00c..468e6d41 100644
--- a/apps/web/components/Dashboard/UI/LeftMenu.tsx
+++ b/apps/web/components/Dashboard/UI/LeftMenu.tsx
@@ -1,9 +1,8 @@
'use client'
import { useOrg } from '@components/Contexts/OrgContext'
-import { useSession } from 'next-auth/react'
+import { signOut } from 'next-auth/react'
import ToolTip from '@components/StyledElements/Tooltip/Tooltip'
import LearnHouseDashboardLogo from '@public/dashLogo.png'
-import { logout } from '@services/auth/auth'
import { BookCopy, Home, LogOut, School, Settings, Users } from 'lucide-react'
import Image from 'next/image'
import Link from 'next/link'
@@ -11,10 +10,11 @@ import { useRouter } from 'next/navigation'
import React, { useEffect } from 'react'
import UserAvatar from '../../Objects/UserAvatar'
import AdminAuthorization from '@components/Security/AdminAuthorization'
+import { useLHSession } from '@components/Contexts/LHSessionContext'
function LeftMenu() {
const org = useOrg() as any
- const session = useSession() as any
+ const session = useLHSession() as any
const [loading, setLoading] = React.useState(true)
const route = useRouter()
@@ -26,7 +26,7 @@ function LeftMenu() {
}
async function logOutUI() {
- const res = await logout()
+ const res = await signOut()
if (res) {
route.push('/login')
}
diff --git a/apps/web/components/Dashboard/UI/SaveState.tsx b/apps/web/components/Dashboard/UI/SaveState.tsx
index 5474b44d..a773e74b 100644
--- a/apps/web/components/Dashboard/UI/SaveState.tsx
+++ b/apps/web/components/Dashboard/UI/SaveState.tsx
@@ -11,9 +11,11 @@ import { useRouter } from 'next/navigation'
import React, { useEffect } from 'react'
import { mutate } from 'swr'
import { updateCourse } from '@services/courses/courses'
+import { useLHSession } from '@components/Contexts/LHSessionContext'
function SaveState(props: { orgslug: string }) {
const course = useCourse() as any
+ const session = useLHSession() as any;
const router = useRouter()
const saved = course ? course.isSaved : true
const dispatchCourse = useCourseDispatch() as any
@@ -37,7 +39,8 @@ function SaveState(props: { orgslug: string }) {
mutate(`${getAPIUrl()}courses/${course.courseStructure.course_uuid}/meta`)
await updateCourseOrderStructure(
course.courseStructure.course_uuid,
- course.courseOrder
+ course.courseOrder,
+ session.data?.tokens?.access_token
)
await revalidateTags(['courses'], props.orgslug)
router.refresh()
@@ -49,7 +52,8 @@ function SaveState(props: { orgslug: string }) {
mutate(`${getAPIUrl()}courses/${course.courseStructure.course_uuid}/meta`)
await updateCourse(
course.courseStructure.course_uuid,
- course.courseStructure
+ course.courseStructure,
+ session.data?.tokens?.access_token
)
await revalidateTags(['courses'], props.orgslug)
router.refresh()
diff --git a/apps/web/components/Dashboard/UserAccount/UserEditGeneral/UserEditGeneral.tsx b/apps/web/components/Dashboard/UserAccount/UserEditGeneral/UserEditGeneral.tsx
index 5d23fe8e..aa74203a 100644
--- a/apps/web/components/Dashboard/UserAccount/UserEditGeneral/UserEditGeneral.tsx
+++ b/apps/web/components/Dashboard/UserAccount/UserEditGeneral/UserEditGeneral.tsx
@@ -2,7 +2,7 @@
import { updateProfile } from '@services/settings/profile'
import React, { useEffect } from 'react'
import { Formik, Form, Field } from 'formik'
-import { useSession } from 'next-auth/react'
+import { useLHSession } from '@components/Contexts/LHSessionContext'
import {
ArrowBigUpDash,
Check,
@@ -14,7 +14,7 @@ import UserAvatar from '@components/Objects/UserAvatar'
import { updateUserAvatar } from '@services/users/users'
function UserEditGeneral() {
- const session = useSession() as any
+ const session = useLHSession() as any
const [localAvatar, setLocalAvatar] = React.useState(null) as any
const [isLoading, setIsLoading] = React.useState(false) as any
const [error, setError] = React.useState() as any
diff --git a/apps/web/components/Dashboard/UserAccount/UserEditPassword/UserEditPassword.tsx b/apps/web/components/Dashboard/UserAccount/UserEditPassword/UserEditPassword.tsx
index 257e4c11..e57d0302 100644
--- a/apps/web/components/Dashboard/UserAccount/UserEditPassword/UserEditPassword.tsx
+++ b/apps/web/components/Dashboard/UserAccount/UserEditPassword/UserEditPassword.tsx
@@ -1,10 +1,10 @@
-import { useSession } from 'next-auth/react'
+import { useLHSession } from '@components/Contexts/LHSessionContext'
import { updatePassword } from '@services/settings/password'
import { Formik, Form, Field } from 'formik'
import React, { useEffect } from 'react'
function UserEditPassword() {
- const session = useSession() as any
+ const session = useLHSession() as any
const updatePasswordUI = async (values: any) => {
let user_id = session.data.user.id
diff --git a/apps/web/components/Hooks/useAdminStatus.tsx b/apps/web/components/Hooks/useAdminStatus.tsx
index 5e99a322..4a5ee5b3 100644
--- a/apps/web/components/Hooks/useAdminStatus.tsx
+++ b/apps/web/components/Hooks/useAdminStatus.tsx
@@ -1,43 +1,40 @@
-import { useOrg } from '@components/Contexts/OrgContext'
-import { useSession } from 'next-auth/react'
-import { useEffect } from 'react'
+import { useOrg } from '@components/Contexts/OrgContext';
+import { useLHSession } from '@components/Contexts/LHSessionContext';
+import { useEffect, useState, useMemo } from 'react';
+
+interface Role {
+ org: { id: number };
+ role: { id: number; role_uuid: string };
+}
function useAdminStatus() {
- const session = useSession() as any
- const org = useOrg() as any
- console.log('useAdminStatus', {
- session,
- })
+ const session = useLHSession() as any;
+ const org = useOrg() as any;
+ const [isAdmin, setIsAdmin] = useState
(null);
+ const [loading, setLoading] = useState(true);
- // If session is not loaded, redirect to login
+ const userRoles = useMemo(() => session?.data?.roles || [], [session?.data?.roles]);
useEffect(() => {
- if (session.status == 'loading') {
- return
- }
-
- }
- , [session])
-
- const isUserAdmin = () => {
- if (session.status == 'authenticated') {
- const isAdmin = session?.data?.roles.some((role: any) => {
+ if (session.status === 'authenticated' && org?.id) {
+ const isAdminVar = userRoles.some((role: Role) => {
return (
role.org.id === org.id &&
(role.role.id === 1 ||
role.role.id === 2 ||
role.role.role_uuid === 'role_global_admin' ||
role.role.role_uuid === 'role_global_maintainer')
- )
- })
- return isAdmin
+ );
+ });
+ setIsAdmin(isAdminVar);
+ setLoading(false); // Set loading to false once the status is determined
+ } else {
+ setIsAdmin(false);
+ setLoading(false); // Set loading to false if not authenticated or org not found
}
- return false
- }
-
- // Return the user admin status
- return isUserAdmin()
+ }, [session.status, userRoles, org.id]);
+ return { isAdmin, loading };
}
-export default useAdminStatus
\ No newline at end of file
+export default useAdminStatus;
diff --git a/apps/web/components/Objects/Activities/AI/AIActivityAsk.tsx b/apps/web/components/Objects/Activities/AI/AIActivityAsk.tsx
index bd0c2d12..057cb986 100644
--- a/apps/web/components/Objects/Activities/AI/AIActivityAsk.tsx
+++ b/apps/web/components/Objects/Activities/AI/AIActivityAsk.tsx
@@ -1,4 +1,4 @@
-import { useSession } from 'next-auth/react'
+import { useLHSession } from '@components/Contexts/LHSessionContext'
import {
sendActivityAIChatMessage,
startActivityAIChatSession,
@@ -74,7 +74,7 @@ type ActivityChatMessageBoxProps = {
}
function ActivityChatMessageBox(props: ActivityChatMessageBoxProps) {
- const session = useSession() as any
+ const session = useLHSession() as any
const aiChatBotState = useAIChatBot() as AIChatBotStateTypes
const dispatchAIChatBot = useAIChatBotDispatch() as any
@@ -328,7 +328,7 @@ type AIMessageProps = {
}
function AIMessage(props: AIMessageProps) {
- const session = useSession() as any
+ const session = useLHSession() as any
const words = props.message.message.split(' ')
@@ -378,7 +378,7 @@ const AIMessagePlaceHolder = (props: {
activity_uuid: string
sendMessage: any
}) => {
- const session = useSession() as any
+ const session = useLHSession() as any
const [feedbackModal, setFeedbackModal] = React.useState(false)
const aiChatBotState = useAIChatBot() as AIChatBotStateTypes
diff --git a/apps/web/components/Objects/CourseUpdates/CourseUpdates.tsx b/apps/web/components/Objects/CourseUpdates/CourseUpdates.tsx
index 2b173eff..33e96b5b 100644
--- a/apps/web/components/Objects/CourseUpdates/CourseUpdates.tsx
+++ b/apps/web/components/Objects/CourseUpdates/CourseUpdates.tsx
@@ -20,12 +20,15 @@ import toast from 'react-hot-toast'
import ConfirmationModal from '@components/StyledElements/ConfirmationModal/ConfirmationModal'
import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';
+import { useLHSession } from '@components/Contexts/LHSessionContext'
dayjs.extend(relativeTime);
function CourseUpdates() {
const course = useCourse() as any;
- const { data: updates } = useSWR(`${getAPIUrl()}courses/${course?.courseStructure.course_uuid}/updates`, swrFetcher)
+ const session = useLHSession() as any;
+ const access_token = session?.data?.tokens?.access_token;
+ const { data: updates } = useSWR(`${getAPIUrl()}courses/${course?.courseStructure.course_uuid}/updates`, (url) => swrFetcher(url, access_token))
const [isModelOpen, setIsModelOpen] = React.useState(false)
function handleModelOpen() {
@@ -71,7 +74,7 @@ function CourseUpdates() {
const UpdatesSection = () => {
const [selectedView, setSelectedView] = React.useState('list')
- const isAdmin = useAdminStatus() as boolean;
+ const adminStatus = useAdminStatus() ;
return (
@@ -80,7 +83,7 @@ const UpdatesSection = () => {
Updates
- {isAdmin &&
setSelectedView('new')}
className='py-2 px-4 space-x-2 items-center flex cursor-pointer text-xs font-medium hover:bg-gray-200 bg-gray-100 outline outline-1 outline-neutral-200/40'>
@@ -98,6 +101,7 @@ const UpdatesSection = () => {
const NewUpdateForm = ({ setSelectedView }: any) => {
const org = useOrg() as any;
const course = useCourse() as any;
+ const session = useLHSession() as any;
const validate = (values: any) => {
const errors: any = {}
@@ -124,7 +128,7 @@ const NewUpdateForm = ({ setSelectedView }: any) => {
course_uuid: course.courseStructure.course_uuid,
org_id: org.id
}
- const res = await createCourseUpdate(body)
+ const res = await createCourseUpdate(body, session.data?.tokens?.access_token)
if (res.status === 200) {
toast.success('Update added successfully')
setSelectedView('list')
@@ -192,23 +196,25 @@ const NewUpdateForm = ({ setSelectedView }: any) => {
const UpdatesListView = () => {
const course = useCourse() as any;
- const isAdmin = useAdminStatus() as boolean;
- const { data: updates } = useSWR(`${getAPIUrl()}courses/${course?.courseStructure.course_uuid}/updates`, swrFetcher)
+ const adminStatus = useAdminStatus() ;
+ const session = useLHSession() as any;
+ const access_token = session?.data?.tokens?.access_token;
+ const { data: updates } = useSWR(`${getAPIUrl()}courses/${course?.courseStructure?.course_uuid}/updates`, (url) => swrFetcher(url, access_token))
return (
- {updates && updates.map((update: any) => (
+ {updates && !adminStatus.loading && updates.map((update: any) => (
{update.title}
-
- {dayjs(update.creation_date).fromNow()}
+
+ {dayjs(update.creation_date).fromNow()}
- {isAdmin &&
}
+ {adminStatus.isAdmin && !adminStatus.loading &&
}
{update.content}
))}
@@ -223,11 +229,12 @@ const UpdatesListView = () => {
}
const DeleteUpdateButton = ({ update }: any) => {
+ const session = useLHSession() as any;
const course = useCourse() as any;
const org = useOrg() as any;
const handleDelete = async () => {
- const res = await deleteCourseUpdate(course.courseStructure.course_uuid, update.courseupdate_uuid)
+ const res = await deleteCourseUpdate(course.courseStructure.course_uuid, update.courseupdate_uuid, session.data?.tokens?.access_token)
if (res.status === 200) {
toast.success('Update deleted successfully')
mutate(`${getAPIUrl()}courses/${course?.courseStructure.course_uuid}/updates`)
diff --git a/apps/web/components/Objects/Editor/ActiveAvatars.tsx b/apps/web/components/Objects/Editor/ActiveAvatars.tsx
index 18e6739f..ddab6d8a 100644
--- a/apps/web/components/Objects/Editor/ActiveAvatars.tsx
+++ b/apps/web/components/Objects/Editor/ActiveAvatars.tsx
@@ -1,6 +1,6 @@
import React, { useEffect, useState } from 'react'
import UserAvatar from '../UserAvatar'
-import { useSession } from 'next-auth/react'
+import { useLHSession } from '@components/Contexts/LHSessionContext'
import { getUserAvatarMediaDirectory } from '@services/media/media';
import { getCollaborationServerUrl } from '@services/config/config';
import { useOrg } from '@components/Contexts/OrgContext';
@@ -11,7 +11,7 @@ type ActiveAvatarsProps = {
}
function ActiveAvatars(props: ActiveAvatarsProps) {
- const session = useSession() as any;
+ const session = useLHSession() as any;
const org = useOrg() as any;
const [activeUsers, setActiveUsers] = useState({} as any);
diff --git a/apps/web/components/Objects/Editor/Editor.tsx b/apps/web/components/Objects/Editor/Editor.tsx
index 681e0f7a..1a31c0e4 100644
--- a/apps/web/components/Objects/Editor/Editor.tsx
+++ b/apps/web/components/Objects/Editor/Editor.tsx
@@ -41,7 +41,7 @@ import html from 'highlight.js/lib/languages/xml'
import python from 'highlight.js/lib/languages/python'
import java from 'highlight.js/lib/languages/java'
import { CourseProvider } from '@components/Contexts/CourseContext'
-import { useSession } from 'next-auth/react'
+import { useLHSession } from '@components/Contexts/LHSessionContext'
import AIEditorToolkit from './AI/AIEditorToolkit'
import useGetAIFeatures from '@components/AI/Hooks/useGetAIFeatures'
import UserAvatar from '../UserAvatar'
@@ -65,7 +65,7 @@ interface Editor {
}
function Editor(props: Editor) {
- const session = useSession() as any
+ const session = useLHSession() as any
const dispatchAIEditor = useAIEditorDispatch() as any
const aiEditorState = useAIEditor() as AIEditorStateTypes
const is_ai_feature_enabled = useGetAIFeatures({ feature: 'editor' })
diff --git a/apps/web/components/Objects/Editor/EditorWrapper.tsx b/apps/web/components/Objects/Editor/EditorWrapper.tsx
index fbeafc52..2e3a8f59 100644
--- a/apps/web/components/Objects/Editor/EditorWrapper.tsx
+++ b/apps/web/components/Objects/Editor/EditorWrapper.tsx
@@ -5,7 +5,7 @@ import { updateActivity } from '@services/courses/activities'
import { toast } from 'react-hot-toast'
import Toast from '@components/StyledElements/Toast/Toast'
import { OrgProvider } from '@components/Contexts/OrgContext'
-import { useSession } from 'next-auth/react'
+import { useLHSession } from '@components/Contexts/LHSessionContext'
// Collaboration
import { HocuspocusProvider } from '@hocuspocus/provider'
@@ -24,7 +24,7 @@ interface EditorWrapperProps {
}
function EditorWrapper(props: EditorWrapperProps): JSX.Element {
- const session = useSession() as any
+ const session = useLHSession() as any
// Define provider in the state
const [provider, setProvider] = React.useState
(null);
const [thisPageColor, setThisPageColor] = useState(randomColor({ luminosity: 'light' }) as string)
diff --git a/apps/web/components/Objects/Menu/Menu.tsx b/apps/web/components/Objects/Menu/Menu.tsx
index 212d2b6c..8bf3df13 100644
--- a/apps/web/components/Objects/Menu/Menu.tsx
+++ b/apps/web/components/Objects/Menu/Menu.tsx
@@ -7,15 +7,15 @@ import MenuLinks from './MenuLinks'
import { getOrgLogoMediaDirectory } from '@services/media/media'
import useSWR from 'swr'
import { swrFetcher } from '@services/utils/ts/requests'
+import { useLHSession } from '@components/Contexts/LHSessionContext'
+import { useOrg } from '@components/Contexts/OrgContext'
export const Menu = (props: any) => {
const orgslug = props.orgslug
+ const session = useLHSession() as any;
+ const access_token = session?.data?.tokens?.access_token;
const [feedbackModal, setFeedbackModal] = React.useState(false)
- const {
- data: org,
- error: error,
- isLoading,
- } = useSWR(`${getAPIUrl()}orgs/slug/${orgslug}`, swrFetcher)
+ const org = useOrg() as any;
function closeFeedbackModal() {
setFeedbackModal(false)
diff --git a/apps/web/components/Objects/Modals/Course/Create/CreateCourse.tsx b/apps/web/components/Objects/Modals/Course/Create/CreateCourse.tsx
index 13fd3ce5..2c68a242 100644
--- a/apps/web/components/Objects/Modals/Course/Create/CreateCourse.tsx
+++ b/apps/web/components/Objects/Modals/Course/Create/CreateCourse.tsx
@@ -15,9 +15,11 @@ import React, { useState } from 'react'
import { BarLoader } from 'react-spinners'
import { revalidateTags } from '@services/utils/ts/requests'
import { useRouter } from 'next/navigation'
+import { useLHSession } from '@components/Contexts/LHSessionContext'
function CreateCourseModal({ closeModal, orgslug }: any) {
const [isSubmitting, setIsSubmitting] = useState(false)
+ const session = useLHSession()
const [name, setName] = React.useState('')
const [description, setDescription] = React.useState('')
const [learnings, setLearnings] = React.useState('')
@@ -71,7 +73,8 @@ function CreateCourseModal({ closeModal, orgslug }: any) {
let status = await createNewCourse(
orgId,
{ name, description, tags, visibility },
- thumbnail
+ thumbnail,
+ session.data?.tokens?.access_token
)
await revalidateTags(['courses'], orgslug)
setIsSubmitting(false)
@@ -80,9 +83,6 @@ function CreateCourseModal({ closeModal, orgslug }: any) {
closeModal()
router.refresh()
await revalidateTags(['courses'], orgslug)
-
- // refresh page (FIX for Next.js BUG)
- // window.location.reload();
} else {
alert('Error creating course, please see console logs')
}
diff --git a/apps/web/components/Objects/Modals/Dash/OrgAccess/OrgInviteCodeGenerate.tsx b/apps/web/components/Objects/Modals/Dash/OrgAccess/OrgInviteCodeGenerate.tsx
index bd63fd8d..5197de72 100644
--- a/apps/web/components/Objects/Modals/Dash/OrgAccess/OrgInviteCodeGenerate.tsx
+++ b/apps/web/components/Objects/Modals/Dash/OrgAccess/OrgInviteCodeGenerate.tsx
@@ -3,6 +3,7 @@ import { getAPIUrl } from '@services/config/config'
import { createInviteCode, createInviteCodeWithUserGroup } from '@services/organizations/invites'
import { swrFetcher } from '@services/utils/ts/requests'
import { Shield, Ticket } from 'lucide-react'
+import { useLHSession } from '@components/Contexts/LHSessionContext'
import React, { useEffect } from 'react'
import toast from 'react-hot-toast'
import useSWR, { mutate } from 'swr'
@@ -13,6 +14,7 @@ type OrgInviteCodeGenerateProps = {
function OrgInviteCodeGenerate(props: OrgInviteCodeGenerateProps) {
const org = useOrg() as any
+ const session = useLHSession()
const [usergroup_id, setUsergroup_id] = React.useState(0);
const { data: usergroups } = useSWR(
org ? `${getAPIUrl()}usergroups/org/${org.id}` : null,
@@ -20,7 +22,7 @@ function OrgInviteCodeGenerate(props: OrgInviteCodeGenerateProps) {
)
async function createInviteWithUserGroup() {
- let res = await createInviteCodeWithUserGroup(org.id, usergroup_id)
+ let res = await createInviteCodeWithUserGroup(org.id, usergroup_id, session.data?.tokens?.access_token)
if (res.status == 200) {
mutate(`${getAPIUrl()}orgs/${org.id}/invites`)
props.setInvitesModal(false)
@@ -30,7 +32,7 @@ function OrgInviteCodeGenerate(props: OrgInviteCodeGenerateProps) {
}
async function createInvite() {
- let res = await createInviteCode(org.id)
+ let res = await createInviteCode(org.id, session.data?.tokens?.access_token)
if (res.status == 200) {
mutate(`${getAPIUrl()}orgs/${org.id}/invites`)
props.setInvitesModal(false)
diff --git a/apps/web/components/Objects/Thumbnails/CollectionThumbnail.tsx b/apps/web/components/Objects/Thumbnails/CollectionThumbnail.tsx
index 034a87a5..73ff2554 100644
--- a/apps/web/components/Objects/Thumbnails/CollectionThumbnail.tsx
+++ b/apps/web/components/Objects/Thumbnails/CollectionThumbnail.tsx
@@ -7,6 +7,7 @@ import { deleteCollection } from '@services/courses/collections'
import { getCourseThumbnailMediaDirectory } from '@services/media/media'
import { revalidateTags } from '@services/utils/ts/requests'
import { X } from 'lucide-react'
+import { useLHSession } from '@components/Contexts/LHSessionContext'
import Link from 'next/link'
import { useRouter } from 'next/navigation'
import React from 'react'
@@ -74,9 +75,10 @@ function CollectionThumbnail(props: PropsType) {
const CollectionAdminEditsArea = (props: any) => {
const router = useRouter()
+ const session = useLHSession() ;
const deleteCollectionUI = async (collectionId: number) => {
- await deleteCollection(collectionId)
+ await deleteCollection(collectionId, session.data?.tokens?.access_token)
await revalidateTags(['collections'], props.orgslug)
// reload the page
router.refresh()
diff --git a/apps/web/components/Objects/Thumbnails/CourseThumbnail.tsx b/apps/web/components/Objects/Thumbnails/CourseThumbnail.tsx
index 4899e131..c9373eb5 100644
--- a/apps/web/components/Objects/Thumbnails/CourseThumbnail.tsx
+++ b/apps/web/components/Objects/Thumbnails/CourseThumbnail.tsx
@@ -7,6 +7,7 @@ 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 { useLHSession } from '@components/Contexts/LHSessionContext'
import Link from 'next/link'
import { useRouter } from 'next/navigation'
import React, { useEffect } from 'react'
@@ -24,15 +25,16 @@ function removeCoursePrefix(course_uuid: string) {
function CourseThumbnail(props: PropsType) {
const router = useRouter()
const org = useOrg() as any
+ const session = useLHSession();
async function deleteCourses(course_uuid: any) {
- await deleteCourseFromBackend(course_uuid)
+ await deleteCourseFromBackend(course_uuid, session.data?.tokens?.access_token)
await revalidateTags(['courses'], props.orgslug)
router.refresh()
}
- useEffect(() => {}, [org])
+ useEffect(() => { }, [org])
return (
@@ -92,8 +94,8 @@ const AdminEditsArea = (props: {
href={getUriWithOrg(
props.orgSlug,
'/dash/courses/course/' +
- removeCoursePrefix(props.courseId) +
- '/general'
+ removeCoursePrefix(props.courseId) +
+ '/general'
)}
>
(undefined)
@@ -33,7 +35,7 @@ function Activity(props: any) {
>(undefined)
async function removeActivity() {
- await deleteActivity(props.activity.id)
+ await deleteActivity(props.activity.id, session.data?.tokens?.access_token)
mutate(`${getAPIUrl()}chapters/meta/course_${props.courseid}`)
await revalidateTags(['courses'], props.orgslug)
router.refresh()
@@ -52,7 +54,7 @@ function Activity(props: any) {
content: props.activity.content,
}
- await updateActivity(modifiedActivityCopy, activityId)
+ await updateActivity(modifiedActivityCopy, activityId, session.data?.tokens?.access_token)
await mutate(`${getAPIUrl()}chapters/meta/course_${props.courseid}`)
await revalidateTags(['courses'], props.orgslug)
router.refresh()
diff --git a/apps/web/components/Pages/CourseEdit/Draggables/Chapter.tsx b/apps/web/components/Pages/CourseEdit/Draggables/Chapter.tsx
index f0fe7bf5..121eb838 100644
--- a/apps/web/components/Pages/CourseEdit/Draggables/Chapter.tsx
+++ b/apps/web/components/Pages/CourseEdit/Draggables/Chapter.tsx
@@ -9,6 +9,7 @@ import { updateChapter } from '@services/courses/chapters'
import { mutate } from 'swr'
import { getAPIUrl } from '@services/config/config'
import { revalidateTags } from '@services/utils/ts/requests'
+import { useLHSession } from '@components/Contexts/LHSessionContext'
interface ModifiedChapterInterface {
chapterId: string
@@ -17,6 +18,7 @@ interface ModifiedChapterInterface {
function Chapter(props: any) {
const router = useRouter()
+ const session = useLHSession() as any;
const [modifiedChapter, setModifiedChapter] = React.useState<
ModifiedChapterInterface | undefined
>(undefined)
@@ -30,7 +32,7 @@ function Chapter(props: any) {
let modifiedChapterCopy = {
name: modifiedChapter.chapterName,
}
- await updateChapter(chapterId, modifiedChapterCopy)
+ await updateChapter(chapterId, modifiedChapterCopy, session.data?.tokens?.access_token)
await mutate(`${getAPIUrl()}chapters/course/${props.course_uuid}/meta`)
await revalidateTags(['courses'], props.orgslug)
router.refresh()
diff --git a/apps/web/components/Pages/Trail/TrailCourseElement.tsx b/apps/web/components/Pages/Trail/TrailCourseElement.tsx
index 4303e458..dfbcd456 100644
--- a/apps/web/components/Pages/Trail/TrailCourseElement.tsx
+++ b/apps/web/components/Pages/Trail/TrailCourseElement.tsx
@@ -4,6 +4,7 @@ import { getAPIUrl, getUriWithOrg } from '@services/config/config'
import { removeCourse } from '@services/courses/activity'
import { getCourseThumbnailMediaDirectory } from '@services/media/media'
import { revalidateTags } from '@services/utils/ts/requests'
+import { useLHSession } from '@components/Contexts/LHSessionContext'
import Link from 'next/link'
import { useRouter } from 'next/navigation'
import { useEffect } from 'react'
@@ -17,6 +18,8 @@ interface TrailCourseElementProps {
function TrailCourseElement(props: TrailCourseElementProps) {
const org = useOrg() as any
+ const session = useLHSession() as any;
+ const access_token = session?.data?.tokens?.access_token;
const courseid = props.course.course_uuid.replace('course_', '')
const course = props.course
const router = useRouter()
@@ -29,7 +32,7 @@ function TrailCourseElement(props: TrailCourseElementProps) {
async function quitCourse(course_uuid: string) {
// Close activity
- let activity = await removeCourse(course_uuid, props.orgslug)
+ let activity = await removeCourse(course_uuid, props.orgslug,access_token)
// Mutate course
await revalidateTags(['courses'], props.orgslug)
router.refresh()
diff --git a/apps/web/components/Security/AdminAuthorization.tsx b/apps/web/components/Security/AdminAuthorization.tsx
index 1f00c31a..05a7737e 100644
--- a/apps/web/components/Security/AdminAuthorization.tsx
+++ b/apps/web/components/Security/AdminAuthorization.tsx
@@ -1,15 +1,14 @@
-'use client'
-import { useOrg } from '@components/Contexts/OrgContext'
-import { useSession } from 'next-auth/react'
-import useAdminStatus from '@components/Hooks/useAdminStatus'
-import { usePathname, useRouter } from 'next/navigation'
-import React from 'react'
+'use client';
+import React, { useEffect, useState, useCallback, useMemo } from 'react';
+import { useOrg } from '@components/Contexts/OrgContext';
+import { useLHSession } from '@components/Contexts/LHSessionContext';
+import useAdminStatus from '@components/Hooks/useAdminStatus';
+import { usePathname, useRouter } from 'next/navigation';
type AuthorizationProps = {
- children: React.ReactNode
- // Authorize components rendering or page rendering
- authorizationMode: 'component' | 'page'
-}
+ children: React.ReactNode;
+ authorizationMode: 'component' | 'page';
+};
const ADMIN_PATHS = [
'/dash/org/*',
@@ -19,106 +18,71 @@ const ADMIN_PATHS = [
'/dash/courses/*',
'/dash/courses',
'/dash/org/settings/general',
-]
+];
-function AdminAuthorization(props: AuthorizationProps) {
- const session = useSession() as any
- const org = useOrg() as any
- const pathname = usePathname()
- const router = useRouter()
+const AdminAuthorization: React.FC
= ({ children, authorizationMode }) => {
+ const session = useLHSession() as any;
+ const pathname = usePathname();
+ const router = useRouter();
+ const { isAdmin, loading } = useAdminStatus() as any
+ const [isAuthorized, setIsAuthorized] = useState(false);
- // States
- const [isLoading, setIsLoading] = React.useState(true)
- const [isAuthorized, setIsAuthorized] = React.useState(false)
+ const isUserAuthenticated = useMemo(() => session.status === 'authenticated', [session.status]);
- // Verify if the user is authenticated
- const isUserAuthenticated = () => {
- if (session.status === 'authenticated') {
- return true
- } else {
- return false
+ const checkPathname = useCallback((pattern: string, pathname: string) => {
+ const regexPattern = new RegExp(`^${pattern.replace(/\//g, '\\/').replace(/\*/g, '.*')}$`);
+ return regexPattern.test(pathname);
+ }, []);
+
+ const isAdminPath = useMemo(() => ADMIN_PATHS.some(path => checkPathname(path, pathname)), [pathname, checkPathname]);
+
+ const authorizeUser = useCallback(() => {
+ if (loading) {
+ return; // Wait until the admin status is determined
}
- }
- // Verify if the user is an Admin (1), Maintainer (2) or Member (3) of the organization
- const isUserAdmin = useAdminStatus()
+ if (!isUserAuthenticated) {
+ router.push('/login');
+ return;
+ }
- function checkPathname(pattern: string, pathname: string) {
- // Escape special characters in the pattern and replace '*' with a regex pattern
- const regexPattern = new RegExp(
- `^${pattern.replace(/\//g, '\\/').replace(/\*/g, '.*')}$`
- )
-
- // Test if the pathname matches the regex pattern
- const isMatch = regexPattern.test(pathname)
-
- return isMatch
- }
-
- const Authorize = () => {
- if (props.authorizationMode === 'page') {
- // Check if user is in an admin path
- if (ADMIN_PATHS.some((path) => checkPathname(path, pathname))) {
- if (isUserAuthenticated()) {
- // Check if the user is an Admin
- if (isUserAdmin) {
- setIsAuthorized(true)
- } else {
- setIsAuthorized(false)
- router.push('/dash')
- }
+ if (authorizationMode === 'page') {
+ if (isAdminPath) {
+ if (isAdmin) {
+ setIsAuthorized(true);
} else {
- router.push('/login')
+ setIsAuthorized(false);
+ router.push('/dash');
}
} else {
- if (isUserAuthenticated()) {
- setIsAuthorized(true)
- } else {
- setIsAuthorized(false)
- router.push('/login')
- }
+ setIsAuthorized(true);
}
+ } else if (authorizationMode === 'component') {
+ setIsAuthorized(isAdmin);
}
+ }, [loading, isUserAuthenticated, isAdmin, isAdminPath, authorizationMode, router]);
- if (props.authorizationMode === 'component') {
- // Component mode
- if (isUserAuthenticated() && isUserAdmin) {
- setIsAuthorized(true)
- } else {
- setIsAuthorized(false)
- }
- }
+ useEffect(() => {
+ authorizeUser();
+ }, [authorizeUser]);
+
+ if (loading) {
+ return (
+
+
Loading...
+
+ );
}
- React.useEffect(() => {
- if (session.status == 'loading') {
- return
- }
+ if (authorizationMode === 'page' && !isAuthorized) {
+ return (
+
+
You are not authorized to access this page
+
+ );
+ }
- Authorize()
- setIsLoading(false)
- }, [session, org, pathname])
+ return <>{isAuthorized && children}>;
+};
- return (
- <>
- {props.authorizationMode === 'component' &&
- isAuthorized === true &&
- props.children}
- {props.authorizationMode === 'page' &&
- isAuthorized === true &&
- !isLoading &&
- props.children}
- {props.authorizationMode === 'page' &&
- isAuthorized === false &&
- !isLoading && (
-
-
- You are not authorized to access this page
-
-
- )}
- >
- )
-}
-
-export default AdminAuthorization
+export default AdminAuthorization;
diff --git a/apps/web/components/Security/AuthenticatedClientElement.tsx b/apps/web/components/Security/AuthenticatedClientElement.tsx
index 66ce5660..ec65e5b3 100644
--- a/apps/web/components/Security/AuthenticatedClientElement.tsx
+++ b/apps/web/components/Security/AuthenticatedClientElement.tsx
@@ -1,6 +1,6 @@
'use client'
import React from 'react'
-import { useSession } from 'next-auth/react'
+import { useLHSession } from '@components/Contexts/LHSessionContext'
import { useOrg } from '@components/Contexts/OrgContext'
interface AuthenticatedClientElementProps {
@@ -20,7 +20,7 @@ export const AuthenticatedClientElement = (
props: AuthenticatedClientElementProps
) => {
const [isAllowed, setIsAllowed] = React.useState(false)
- const session = useSession() as any
+ const session = useLHSession() as any
const org = useOrg() as any
function isUserAllowed(
@@ -49,13 +49,13 @@ export const AuthenticatedClientElement = (
}
function check() {
- if (session.status == 'authenticated') {
+ if (session.status == 'unauthenticated') {
setIsAllowed(false)
return
} else {
if (props.checkMethod === 'authentication') {
setIsAllowed(session.status == 'authenticated')
- } else if (props.checkMethod === 'roles' && session.status == 'authenticated') {
+ } else if (props.checkMethod === 'roles' ) {
return setIsAllowed(
isUserAllowed(
session?.data?.roles,
@@ -74,7 +74,7 @@ export const AuthenticatedClientElement = (
}
check()
- }, [session, org])
+ }, [session.data, org])
return <>{isAllowed && props.children}>
}
diff --git a/apps/web/components/Security/HeaderProfileBox.tsx b/apps/web/components/Security/HeaderProfileBox.tsx
index 3c932bd1..f6427c0f 100644
--- a/apps/web/components/Security/HeaderProfileBox.tsx
+++ b/apps/web/components/Security/HeaderProfileBox.tsx
@@ -5,10 +5,10 @@ import Link from 'next/link'
import { Settings } from 'lucide-react'
import UserAvatar from '@components/Objects/UserAvatar'
import useAdminStatus from '@components/Hooks/useAdminStatus'
-import { useSession } from 'next-auth/react'
+import { useLHSession } from '@components/Contexts/LHSessionContext'
export const HeaderProfileBox = () => {
- const session = useSession() as any
+ const session = useLHSession() as any
const isUserAdmin = useAdminStatus() as any
useEffect(() => {
diff --git a/apps/web/pnpm-lock.yaml b/apps/web/pnpm-lock.yaml
index 62f82e90..8fa72ec5 100644
--- a/apps/web/pnpm-lock.yaml
+++ b/apps/web/pnpm-lock.yaml
@@ -1549,6 +1549,7 @@ packages:
"@typescript-eslint/visitor-keys": 6.21.0
debug: 4.3.4
eslint: 8.57.0
+ optionalDependencies:
typescript: 5.4.4
transitivePeerDependencies:
- supports-color
@@ -1570,6 +1571,7 @@ packages:
minimatch: 9.0.3
semver: 7.6.0
ts-api-utils: 1.3.0(typescript@5.4.4)
+ optionalDependencies:
typescript: 5.4.4
transitivePeerDependencies:
- supports-color
@@ -1713,8 +1715,8 @@ packages:
dependencies:
possible-typed-array-names: 1.0.0
- avvvatars-react@0.4.2(csstype@3.1.3)(react-dom@18.2.0)(react@18.2.0):
- dependencies:
+ ? avvvatars-react@0.4.2(csstype@3.1.3)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
+ : dependencies:
goober: 2.1.14(csstype@3.1.3)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
@@ -2070,11 +2072,12 @@ packages:
"@typescript-eslint/parser": 6.21.0(eslint@8.57.0)(typescript@5.4.4)
eslint: 8.57.0
eslint-import-resolver-node: 0.3.9
- eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0)
- eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
+ eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.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-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.4))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
eslint-plugin-jsx-a11y: 6.8.0(eslint@8.57.0)
eslint-plugin-react: 7.34.1(eslint@8.57.0)
eslint-plugin-react-hooks: 4.6.0(eslint@8.57.0)
+ optionalDependencies:
typescript: 5.4.4
transitivePeerDependencies:
- eslint-import-resolver-webpack
@@ -2093,8 +2096,8 @@ packages:
debug: 4.3.4
enhanced-resolve: 5.16.0
eslint: 8.57.0
- eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
- eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
+ eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.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@6.21.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@6.21.0(eslint@8.57.0)(typescript@5.4.4))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
fast-glob: 3.3.2
get-tsconfig: 4.7.3
is-core-module: 2.13.1
@@ -2109,9 +2112,11 @@ packages:
: dependencies:
"@typescript-eslint/parser": 6.21.0(eslint@8.57.0)(typescript@5.4.4)
debug: 3.2.7
+ optionalDependencies:
+ "@typescript-eslint/parser": 6.21.0(eslint@8.57.0)(typescript@5.4.4)
eslint: 8.57.0
eslint-import-resolver-node: 0.3.9
- eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0)
+ eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.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)
transitivePeerDependencies:
- supports-color
@@ -2126,7 +2131,7 @@ packages:
doctrine: 2.1.0
eslint: 8.57.0
eslint-import-resolver-node: 0.3.9
- eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
+ eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.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@6.21.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)
hasown: 2.0.2
is-core-module: 2.13.1
is-glob: 4.0.3
@@ -2136,6 +2141,8 @@ packages:
object.values: 1.2.0
semver: 6.3.1
tsconfig-paths: 3.15.0
+ optionalDependencies:
+ "@typescript-eslint/parser": 6.21.0(eslint@8.57.0)(typescript@5.4.4)
transitivePeerDependencies:
- eslint-import-resolver-typescript
- eslint-import-resolver-webpack
@@ -2324,10 +2331,8 @@ packages:
fraction.js@4.3.7: {}
- framer-motion@10.18.0(react-dom@18.2.0)(react@18.2.0):
+ framer-motion@10.18.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
- react: 18.2.0
- react-dom: 18.2.0(react@18.2.0)
tslib: 2.6.2
optionalDependencies:
"@emotion/is-prop-valid": 0.8.8
@@ -2985,8 +2990,9 @@ packages:
postcss-load-config@4.0.2(postcss@8.4.38):
dependencies:
lilconfig: 3.1.1
- postcss: 8.4.38
yaml: 2.4.1
+ optionalDependencies:
+ postcss: 8.4.38
postcss-nested@6.0.1(postcss@8.4.38):
dependencies:
@@ -3146,12 +3152,12 @@ packages:
randomcolor@0.6.2: {}
- re-resizable@6.9.11(react-dom@18.2.0)(react@18.2.0):
+ re-resizable@6.9.11(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
- react-beautiful-dnd@13.1.1(react-dom@18.2.0)(react@18.2.0):
+ react-beautiful-dnd@13.1.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
"@babel/runtime": 7.24.4
css-box-model: 1.2.1
@@ -3159,7 +3165,7 @@ packages:
raf-schd: 4.0.3
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
- react-redux: 7.2.9(react-dom@18.2.0)(react@18.2.0)
+ react-redux: 7.2.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
redux: 4.2.1
use-memo-one: 1.1.3(react@18.2.0)
transitivePeerDependencies:
@@ -3178,8 +3184,8 @@ packages:
react-fast-compare@2.0.4: {}
- react-hot-toast@2.4.1(csstype@3.1.3)(react-dom@18.2.0)(react@18.2.0):
- dependencies:
+ ? react-hot-toast@2.4.1(csstype@3.1.3)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
+ : dependencies:
goober: 2.1.14(csstype@3.1.3)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
@@ -3196,7 +3202,7 @@ packages:
prop-types: 15.8.1
react: 18.2.0
- react-redux@7.2.9(react-dom@18.2.0)(react@18.2.0):
+ react-redux@7.2.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
"@babel/runtime": 7.24.4
"@types/react-redux": 7.1.33
@@ -3204,8 +3210,9 @@ packages:
loose-envify: 1.4.0
prop-types: 15.8.1
react: 18.2.0
- react-dom: 18.2.0(react@18.2.0)
react-is: 17.0.2
+ optionalDependencies:
+ react-dom: 18.2.0(react@18.2.0)
react-remove-scroll-bar@2.3.6(@types/react@18.2.74)(react@18.2.0):
dependencies:
@@ -3213,6 +3220,8 @@ packages:
react: 18.2.0
react-style-singleton: 2.2.1(@types/react@18.2.74)(react@18.2.0)
tslib: 2.6.2
+ optionalDependencies:
+ "@types/react": 18.2.74
react-remove-scroll@2.5.5(@types/react@18.2.74)(react@18.2.0):
dependencies:
@@ -3223,8 +3232,10 @@ packages:
tslib: 2.6.2
use-callback-ref: 1.3.2(@types/react@18.2.74)(react@18.2.0)
use-sidecar: 1.1.2(@types/react@18.2.74)(react@18.2.0)
+ optionalDependencies:
+ "@types/react": 18.2.74
- react-spinners@0.13.8(react-dom@18.2.0)(react@18.2.0):
+ react-spinners@0.13.8(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
@@ -3236,6 +3247,8 @@ packages:
invariant: 2.2.4
react: 18.2.0
tslib: 2.6.2
+ optionalDependencies:
+ "@types/react": 18.2.74
react-youtube@10.1.0(react@18.2.0):
dependencies:
@@ -3485,7 +3498,7 @@ packages:
strip-json-comments@3.1.1: {}
- styled-components@6.1.8(react-dom@18.2.0)(react@18.2.0):
+ styled-components@6.1.8(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
"@emotion/is-prop-valid": 1.2.1
"@emotion/unitless": 0.8.0
@@ -3672,6 +3685,8 @@ packages:
"@types/react": 18.2.74
react: 18.2.0
tslib: 2.6.2
+ optionalDependencies:
+ "@types/react": 18.2.74
use-memo-one@1.1.3(react@18.2.0):
dependencies:
@@ -3683,6 +3698,8 @@ packages:
detect-node-es: 1.1.0
react: 18.2.0
tslib: 2.6.2
+ optionalDependencies:
+ "@types/react": 18.2.74
use-sync-external-store@1.2.0(react@18.2.0):
dependencies:
diff --git a/apps/web/services/courses/activities.ts b/apps/web/services/courses/activities.ts
index 1c8748a9..1fa050f0 100644
--- a/apps/web/services/courses/activities.ts
+++ b/apps/web/services/courses/activities.ts
@@ -1,18 +1,22 @@
import { getAPIUrl } from '@services/config/config'
import {
- RequestBody,
- RequestBodyForm,
+ RequestBodyFormWithAuthHeader,
RequestBodyWithAuthHeader,
} from '@services/utils/ts/requests'
-export async function createActivity(data: any, chapter_id: any, org_id: any) {
+export async function createActivity(
+ data: any,
+ chapter_id: any,
+ org_id: any,
+ access_token: string
+) {
data.content = {}
// remove chapter_id from data
delete data.chapterId
const result = await fetch(
`${getAPIUrl()}activities/?coursechapter_id=${chapter_id}&org_id=${org_id}`,
- RequestBody('POST', data, null)
+ RequestBodyWithAuthHeader('POST', data, null, access_token)
)
const res = await result.json()
return res
@@ -22,7 +26,8 @@ export async function createFileActivity(
file: File,
type: string,
data: any,
- chapter_id: any
+ chapter_id: any,
+ access_token: string
) {
// Send file thumbnail as form data
const formData = new FormData()
@@ -44,7 +49,7 @@ export async function createFileActivity(
const result: any = await fetch(
endpoint,
- RequestBodyForm('POST', formData, null)
+ RequestBodyFormWithAuthHeader('POST', formData, null, access_token)
)
const res = await result.json()
return res
@@ -53,7 +58,8 @@ export async function createFileActivity(
export async function createExternalVideoActivity(
data: any,
activity: any,
- chapter_id: any
+ chapter_id: any,
+ access_token: string
) {
// add coursechapter_id to data
data.chapter_id = chapter_id
@@ -61,25 +67,29 @@ export async function createExternalVideoActivity(
const result = await fetch(
`${getAPIUrl()}activities/external_video`,
- RequestBody('POST', data, null)
+ RequestBodyWithAuthHeader('POST', data, null, access_token)
)
const res = await result.json()
return res
}
-export async function getActivity(activity_id: any, next: any) {
+export async function getActivity(
+ activity_id: any,
+ next: any,
+ access_token: string
+) {
const result = await fetch(
`${getAPIUrl()}activities/${activity_id}`,
- RequestBody('GET', null, next)
+ RequestBodyWithAuthHeader('GET', null, next, access_token)
)
const res = await result.json()
return res
}
-export async function deleteActivity(activity_id: any) {
+export async function deleteActivity(activity_id: any, access_token: string) {
const result = await fetch(
`${getAPIUrl()}activities/${activity_id}`,
- RequestBody('DELETE', null, null)
+ RequestBodyWithAuthHeader('DELETE', null, null, access_token)
)
const res = await result.json()
return res
@@ -98,10 +108,14 @@ export async function getActivityWithAuthHeader(
return res
}
-export async function updateActivity(data: any, activity_uuid: string) {
+export async function updateActivity(
+ data: any,
+ activity_uuid: string,
+ access_token: string
+) {
const result = await fetch(
`${getAPIUrl()}activities/${activity_uuid}`,
- RequestBody('PUT', data, null)
+ RequestBodyWithAuthHeader('PUT', data, null, access_token)
)
const res = await result.json()
return res
diff --git a/apps/web/services/courses/activity.ts b/apps/web/services/courses/activity.ts
index 8b0e7838..b571741d 100644
--- a/apps/web/services/courses/activity.ts
+++ b/apps/web/services/courses/activity.ts
@@ -1,4 +1,4 @@
-import { RequestBody, errorHandling } from '@services/utils/ts/requests'
+import { RequestBody, RequestBodyWithAuthHeader, errorHandling } from '@services/utils/ts/requests'
import { getAPIUrl } from '@services/config/config'
/*
@@ -6,19 +6,19 @@ import { getAPIUrl } from '@services/config/config'
GET requests are called from the frontend using SWR (https://swr.vercel.app/)
*/
-export async function startCourse(course_uuid: string, org_slug: string) {
+export async function startCourse(course_uuid: string, org_slug: string,access_token:any) {
const result: any = await fetch(
`${getAPIUrl()}trail/add_course/${course_uuid}`,
- RequestBody('POST', null, null)
+ RequestBodyWithAuthHeader('POST', null, null,access_token)
)
const res = await errorHandling(result)
return res
}
-export async function removeCourse(course_uuid: string, org_slug: string) {
+export async function removeCourse(course_uuid: string, org_slug: string,access_token:any) {
const result: any = await fetch(
`${getAPIUrl()}trail/remove_course/${course_uuid}`,
- RequestBody('DELETE', null, null)
+ RequestBodyWithAuthHeader('DELETE', null, null,access_token)
)
const res = await errorHandling(result)
return res
@@ -27,11 +27,11 @@ export async function removeCourse(course_uuid: string, org_slug: string) {
export async function markActivityAsComplete(
org_slug: string,
course_uuid: string,
- activity_uuid: string
+ activity_uuid: string,access_token:any
) {
const result: any = await fetch(
`${getAPIUrl()}trail/add_activity/${activity_uuid}`,
- RequestBody('POST', null, null)
+ RequestBodyWithAuthHeader('POST', null, null,access_token)
)
const res = await errorHandling(result)
return res
diff --git a/apps/web/services/courses/chapters.ts b/apps/web/services/courses/chapters.ts
index 58ed5d1f..f04c5b37 100644
--- a/apps/web/services/courses/chapters.ts
+++ b/apps/web/services/courses/chapters.ts
@@ -1,6 +1,9 @@
import { OrderPayload } from '@components/Dashboard/Course/EditCourseStructure/EditCourseStructure'
import { getAPIUrl } from '@services/config/config'
-import { RequestBody, errorHandling } from '@services/utils/ts/requests'
+import {
+ RequestBodyWithAuthHeader,
+ errorHandling,
+} from '@services/utils/ts/requests'
/*
This file includes only POST, PUT, DELETE requests
@@ -8,28 +11,40 @@ import { RequestBody, errorHandling } from '@services/utils/ts/requests'
*/
//TODO : depreciate this function
-export async function getCourseChaptersMetadata(course_uuid: any, next: any) {
+export async function getCourseChaptersMetadata(
+ course_uuid: any,
+ next: any,
+ access_token: any
+) {
const result = await fetch(
`${getAPIUrl()}chapters/meta/course_${course_uuid}`,
- RequestBody('GET', null, next)
+ RequestBodyWithAuthHeader('GET', null, next, access_token)
)
const res = await errorHandling(result)
return res
}
-export async function updateChaptersMetadata(course_uuid: any, data: any) {
+export async function updateChaptersMetadata(
+ course_uuid: any,
+ data: any,
+ access_token: any
+) {
const result: any = await fetch(
`${getAPIUrl()}chapters/course/course_${course_uuid}/order`,
- RequestBody('PUT', data, null)
+ RequestBodyWithAuthHeader('PUT', data, null, access_token)
)
const res = await errorHandling(result)
return res
}
-export async function updateChapter(coursechapter_id: any, data: any) {
+export async function updateChapter(
+ coursechapter_id: any,
+ data: any,
+ access_token: any
+) {
const result: any = await fetch(
`${getAPIUrl()}chapters/${coursechapter_id}`,
- RequestBody('PUT', data, null)
+ RequestBodyWithAuthHeader('PUT', data, null, access_token)
)
const res = await errorHandling(result)
return res
@@ -37,30 +52,31 @@ export async function updateChapter(coursechapter_id: any, data: any) {
export async function updateCourseOrderStructure(
course_uuid: any,
- data: OrderPayload
+ data: OrderPayload,
+ access_token: any
) {
const result: any = await fetch(
`${getAPIUrl()}chapters/course/${course_uuid}/order`,
- RequestBody('PUT', data, null)
+ RequestBodyWithAuthHeader('PUT', data, null, access_token)
)
const res = await errorHandling(result)
return res
}
-export async function createChapter(data: any) {
+export async function createChapter(data: any, access_token: any) {
const result: any = await fetch(
`${getAPIUrl()}chapters/`,
- RequestBody('POST', data, null)
+ RequestBodyWithAuthHeader('POST', data, null, access_token)
)
const res = await errorHandling(result)
return res
}
-export async function deleteChapter(coursechapter_id: any) {
+export async function deleteChapter(coursechapter_id: any, access_token: any) {
const result: any = await fetch(
`${getAPIUrl()}chapters/${coursechapter_id}`,
- RequestBody('DELETE', null, null)
+ RequestBodyWithAuthHeader('DELETE', null, null, access_token)
)
const res = await errorHandling(result)
return res
diff --git a/apps/web/services/courses/collections.ts b/apps/web/services/courses/collections.ts
index 84575309..5439f61a 100644
--- a/apps/web/services/courses/collections.ts
+++ b/apps/web/services/courses/collections.ts
@@ -1,6 +1,5 @@
import { getAPIUrl } from '../config/config'
import {
- RequestBody,
RequestBodyWithAuthHeader,
errorHandling,
} from '@services/utils/ts/requests'
@@ -10,36 +9,30 @@ import {
GET requests are called from the frontend using SWR (https://swr.vercel.app/)
*/
-export async function deleteCollection(collection_uuid: any) {
+export async function deleteCollection(
+ collection_uuid: any,
+ access_token: any
+) {
const result: any = await fetch(
`${getAPIUrl()}collections/${collection_uuid}`,
- RequestBody('DELETE', null, null)
+ RequestBodyWithAuthHeader('DELETE', null, null, access_token)
)
const res = await errorHandling(result)
return res
}
// Create a new collection
-export async function createCollection(collection: any) {
+export async function createCollection(collection: any, access_token: any) {
+ console.log(collection)
const result: any = await fetch(
`${getAPIUrl()}collections/`,
- RequestBody('POST', collection, null)
+ RequestBodyWithAuthHeader('POST', collection, null, access_token)
)
const res = await errorHandling(result)
return res
}
-// Get a colletion by id
-export async function getCollectionById(collection_uuid: any) {
- const result: any = await fetch(
- `${getAPIUrl()}collections/${collection_uuid}`,
- { next: { revalidate: 10 } }
- )
- const res = await errorHandling(result)
- return res
-}
-
-export async function getCollectionByIdWithAuthHeader(
+export async function getCollectionById(
collection_uuid: any,
access_token: string,
next: any
@@ -52,17 +45,7 @@ export async function getCollectionByIdWithAuthHeader(
return res
}
-// Get collections
-// TODO : add per org filter
-export async function getOrgCollections() {
- const result: any = await fetch(`${getAPIUrl()}collections/page/1/limit/10`, {
- next: { revalidate: 10 },
- })
- const res = await errorHandling(result)
- return res
-}
-
-export async function getOrgCollectionsWithAuthHeader(
+export async function getOrgCollections(
org_id: string,
access_token: string,
next: any
diff --git a/apps/web/services/courses/courses.ts b/apps/web/services/courses/courses.ts
index 3e32968a..40dbeaf8 100644
--- a/apps/web/services/courses/courses.ts
+++ b/apps/web/services/courses/courses.ts
@@ -2,6 +2,7 @@ import { getAPIUrl } from '@services/config/config'
import {
RequestBody,
RequestBodyForm,
+ RequestBodyFormWithAuthHeader,
RequestBodyWithAuthHeader,
errorHandling,
getResponseMetadata,
@@ -12,19 +13,10 @@ import {
GET requests are called from the frontend using SWR (https://swr.vercel.app/)
*/
-export async function getOrgCourses(org_id: number, next: any) {
- const result: any = await fetch(
- `${getAPIUrl()}courses/org_slug/${org_id}/page/1/limit/10`,
- RequestBody('GET', null, next)
- )
- const res = await errorHandling(result)
- return res
-}
-
-export async function getOrgCoursesWithAuthHeader(
+export async function getOrgCourses(
org_id: number,
next: any,
- access_token: string
+ access_token: any
) {
const result: any = await fetch(
`${getAPIUrl()}courses/org_slug/${org_id}/page/1/limit/10`,
@@ -34,7 +26,7 @@ export async function getOrgCoursesWithAuthHeader(
return res
}
-export async function getCourseMetadataWithAuthHeader(
+export async function getCourseMetadata(
course_uuid: any,
next: any,
access_token: string
@@ -47,30 +39,30 @@ export async function getCourseMetadataWithAuthHeader(
return res
}
-export async function updateCourse(course_uuid: any, data: any) {
+export async function updateCourse(course_uuid: any, data: any, access_token:any) {
const result: any = await fetch(
`${getAPIUrl()}courses/${course_uuid}`,
- RequestBody('PUT', data, null)
+ RequestBodyWithAuthHeader('PUT', data, null,access_token)
)
const res = await errorHandling(result)
return res
}
-export async function getCourse(course_uuid: string, next: any) {
+export async function getCourse(course_uuid: string, next: any, access_token:any) {
const result: any = await fetch(
`${getAPIUrl()}courses/${course_uuid}`,
- RequestBody('GET', null, next)
+ RequestBodyWithAuthHeader('GET', null, next,access_token)
)
const res = await errorHandling(result)
return res
}
-export async function updateCourseThumbnail(course_uuid: any, thumbnail: any) {
+export async function updateCourseThumbnail(course_uuid: any, thumbnail: any, access_token:any) {
const formData = new FormData()
formData.append('thumbnail', thumbnail)
const result: any = await fetch(
`${getAPIUrl()}courses/${course_uuid}/thumbnail`,
- RequestBodyForm('PUT', formData, null)
+ RequestBodyFormWithAuthHeader('PUT', formData, null,access_token)
)
const res = await getResponseMetadata(result)
return res
@@ -79,7 +71,8 @@ export async function updateCourseThumbnail(course_uuid: any, thumbnail: any) {
export async function createNewCourse(
org_id: string,
course_body: any,
- thumbnail: any
+ thumbnail: any,
+ access_token: any
) {
// Send file thumbnail as form data
const formData = new FormData()
@@ -96,16 +89,16 @@ export async function createNewCourse(
const result = await fetch(
`${getAPIUrl()}courses/?org_id=${org_id}`,
- RequestBodyForm('POST', formData, null)
+ RequestBodyFormWithAuthHeader('POST', formData, null, access_token)
)
const res = await errorHandling(result)
return res
}
-export async function deleteCourseFromBackend(course_uuid: any) {
+export async function deleteCourseFromBackend(course_uuid: any, access_token:any) {
const result: any = await fetch(
`${getAPIUrl()}courses/${course_uuid}`,
- RequestBody('DELETE', null, null)
+ RequestBodyWithAuthHeader('DELETE', null, null,access_token)
)
const res = await errorHandling(result)
return res
diff --git a/apps/web/services/courses/updates.ts b/apps/web/services/courses/updates.ts
index 8b515106..061d6a33 100644
--- a/apps/web/services/courses/updates.ts
+++ b/apps/web/services/courses/updates.ts
@@ -1,10 +1,14 @@
import { getAPIUrl } from '@services/config/config'
-import { RequestBody, getResponseMetadata } from '@services/utils/ts/requests'
+import {
+ RequestBody,
+ RequestBodyWithAuthHeader,
+ getResponseMetadata,
+} from '@services/utils/ts/requests'
-export async function createCourseUpdate(body: any) {
+export async function createCourseUpdate(body: any, access_token: string) {
const result: any = await fetch(
`${getAPIUrl()}courses/${body.course_uuid}/updates`,
- RequestBody('POST', body, null)
+ RequestBodyWithAuthHeader('POST', body, null, access_token)
)
const res = await getResponseMetadata(result)
return res
@@ -12,11 +16,12 @@ export async function createCourseUpdate(body: any) {
export async function deleteCourseUpdate(
course_uuid: string,
- update_uuid: number
+ update_uuid: number,
+ access_token: string
) {
const result: any = await fetch(
`${getAPIUrl()}courses/${course_uuid}/update/${update_uuid}`,
- RequestBody('DELETE', null, null)
+ RequestBodyWithAuthHeader('DELETE', null, null, access_token)
)
const res = await getResponseMetadata(result)
return res
diff --git a/apps/web/services/utils/ts/requests.ts b/apps/web/services/utils/ts/requests.ts
index 2947964a..1ac8fd8b 100644
--- a/apps/web/services/utils/ts/requests.ts
+++ b/apps/web/services/utils/ts/requests.ts
@@ -32,7 +32,7 @@ export const RequestBodyWithAuthHeader = (
headers: HeadersConfig,
redirect: 'follow',
credentials: 'include',
- body: data,
+ body: (method === 'POST' || method === 'PUT') ? JSON.stringify(data) : null,
// Next.js
next: next,
}
@@ -41,6 +41,27 @@ export const RequestBodyWithAuthHeader = (
export const RequestBodyForm = (method: string, data: any, next: any) => {
let HeadersConfig = new Headers({})
+ let options: any = {
+ method: method,
+ headers: HeadersConfig,
+ redirect: 'follow',
+ credentials: 'include',
+ body: (method === 'POST' || method === 'PUT') ? JSON.stringify(data) : null,
+ // Next.js
+ next: next,
+ }
+ return options
+}
+
+export const RequestBodyFormWithAuthHeader = (
+ method: string,
+ data: any,
+ next: any,
+ access_token: string
+) => {
+ let HeadersConfig = new Headers({
+ Authorization: `Bearer ${access_token}`,
+ })
let options: any = {
method: method,
headers: HeadersConfig,
@@ -53,9 +74,13 @@ export const RequestBodyForm = (method: string, data: any, next: any) => {
return options
}
-export const swrFetcher = async (url: string) => {
+export const swrFetcher = async (url: string, token?: string) => {
// Create the request options
- let HeadersConfig = new Headers({ 'Content-Type': 'application/json' })
+ let HeadersConfig = new Headers(
+ token
+ ? { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` }
+ : { 'Content-Type': 'application/json' }
+ )
let options: any = {
method: 'GET',
headers: HeadersConfig,
diff --git a/apps/web/types/next-auth.d.ts b/apps/web/types/next-auth.d.ts
new file mode 100644
index 00000000..5287cbc2
--- /dev/null
+++ b/apps/web/types/next-auth.d.ts
@@ -0,0 +1,15 @@
+import type { NextAuthOptions } from 'next-auth/index';
+
+// next-auth.d.ts
+declare module 'next-auth' {
+ interface Session {
+ user: any | undefined
+ roles?: string[] | undefined
+ tokens?:
+ | {
+ access_token?: string | undefined
+ refresh_token?: string | undefined
+ }
+ | undefined
+ }
+}
diff --git a/package.json b/package.json
index e80202c6..7174e3cc 100644
--- a/package.json
+++ b/package.json
@@ -12,5 +12,5 @@
"prettier": "^3.2.5",
"turbo": "^1.13.2"
},
- "packageManager": "pnpm@8.6.10"
+ "packageManager": "pnpm@9.0.6"
}