mirror of
https://github.com/rzmk/learnhouse.git
synced 2025-12-19 04:19:25 +00:00
Merge pull request #459 from learnhouse/feat/next-15
Next.js 15 Upgrade
This commit is contained in:
commit
dbfd05edde
110 changed files with 3580 additions and 3586 deletions
|
|
@ -113,13 +113,13 @@ function ForgotPasswordClient() {
|
|||
</p>
|
||||
|
||||
{error && (
|
||||
<div className="flex justify-center bg-red-200 rounded-md text-red-950 space-x-2 items-center p-4 transition-all shadow-sm">
|
||||
<div className="flex justify-center bg-red-200 rounded-md text-red-950 space-x-2 items-center p-4 transition-all shadow-xs">
|
||||
<AlertTriangle size={18} />
|
||||
<div className="font-bold text-sm">{error}</div>
|
||||
</div>
|
||||
)}
|
||||
{message && (
|
||||
<div className="flex justify-center bg-green-200 rounded-md text-green-950 space-x-2 items-center p-4 transition-all shadow-sm">
|
||||
<div className="flex justify-center bg-green-200 rounded-md text-green-950 space-x-2 items-center p-4 transition-all shadow-xs">
|
||||
<Info size={18} />
|
||||
<div className="font-bold text-sm">{message}</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ const LoginClient = (props: LoginClientProps) => {
|
|||
<div className="left-login-part bg-white flex flex-row">
|
||||
<div className="login-form m-auto w-72">
|
||||
{error && (
|
||||
<div className="flex justify-center bg-red-200 rounded-md text-red-950 space-x-2 items-center p-4 transition-all shadow-sm">
|
||||
<div className="flex justify-center bg-red-200 rounded-md text-red-950 space-x-2 items-center p-4 transition-all shadow-xs">
|
||||
<AlertTriangle size={18} />
|
||||
<div className="font-bold text-sm">{error}</div>
|
||||
</div>
|
||||
|
|
@ -188,11 +188,11 @@ const LoginClient = (props: LoginClientProps) => {
|
|||
<div className='flex h-0.5 rounded-2xl bg-slate-100 mt-5 mx-10'></div>
|
||||
<div className='flex justify-center py-5 mx-auto'>OR </div>
|
||||
<div className='flex flex-col space-y-4'>
|
||||
<Link href={{ pathname: getUriWithoutOrg('/signup'), query: props.org.slug ? { orgslug: props.org.slug } : null }} className="flex justify-center items-center py-3 text-md w-full bg-gray-800 text-gray-300 space-x-3 font-semibold text-center p-2 rounded-md shadow hover:cursor-pointer">
|
||||
<Link href={{ pathname: getUriWithoutOrg('/signup'), query: props.org.slug ? { orgslug: props.org.slug } : null }} className="flex justify-center items-center py-3 text-md w-full bg-gray-800 text-gray-300 space-x-3 font-semibold text-center p-2 rounded-md shadow-sm hover:cursor-pointer">
|
||||
<UserRoundPlus size={17} />
|
||||
<span>Sign up</span>
|
||||
</Link>
|
||||
<button onClick={() => signIn('google', { callbackUrl: '/redirect_from_auth' })} className="flex justify-center py-3 text-md w-full bg-white text-slate-600 space-x-3 font-semibold text-center p-2 rounded-md shadow hover:cursor-pointer">
|
||||
<button onClick={() => signIn('google', { callbackUrl: '/redirect_from_auth' })} className="flex justify-center py-3 text-md w-full bg-white text-slate-600 space-x-3 font-semibold text-center p-2 rounded-md shadow-sm hover:cursor-pointer">
|
||||
<img src="https://fonts.gstatic.com/s/i/productlogos/googleg/v6/24px.svg" alt="" />
|
||||
<span>Sign in with Google</span>
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -3,12 +3,12 @@ import LoginClient from './login'
|
|||
import { Metadata } from 'next'
|
||||
|
||||
type MetadataProps = {
|
||||
params: { orgslug: string }
|
||||
searchParams: { [key: string]: string | string[] | undefined }
|
||||
params: Promise<{ orgslug: string }>
|
||||
searchParams: Promise<{ [key: string]: string | string[] | undefined }>
|
||||
}
|
||||
|
||||
export async function generateMetadata(params: MetadataProps): Promise<Metadata> {
|
||||
const orgslug = params.searchParams.orgslug
|
||||
const orgslug = (await params.searchParams).orgslug
|
||||
|
||||
//const orgslug = params.orgslug
|
||||
// Get Org context information
|
||||
|
|
@ -23,7 +23,7 @@ export async function generateMetadata(params: MetadataProps): Promise<Metadata>
|
|||
}
|
||||
|
||||
const Login = async (params: MetadataProps) => {
|
||||
const orgslug = params.searchParams.orgslug
|
||||
const orgslug = (await params.searchParams).orgslug
|
||||
const org = await getOrganizationContextInfo(orgslug, {
|
||||
revalidate: 0,
|
||||
tags: ['organizations'],
|
||||
|
|
|
|||
|
|
@ -133,14 +133,14 @@ function ResetPasswordClient() {
|
|||
</p>
|
||||
|
||||
{error && (
|
||||
<div className="flex justify-center bg-red-200 rounded-md text-red-950 space-x-2 items-center p-4 transition-all shadow-sm">
|
||||
<div className="flex justify-center bg-red-200 rounded-md text-red-950 space-x-2 items-center p-4 transition-all shadow-xs">
|
||||
<AlertTriangle size={18} />
|
||||
<div className="font-bold text-sm">{error}</div>
|
||||
</div>
|
||||
)}
|
||||
{message && (
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex justify-center bg-green-200 rounded-md text-green-950 space-x-2 items-center p-4 transition-all shadow-sm">
|
||||
<div className="flex justify-center bg-green-200 rounded-md text-green-950 space-x-2 items-center p-4 transition-all shadow-xs">
|
||||
<Info size={18} />
|
||||
<div className="font-bold text-sm">{message}</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -98,13 +98,13 @@ function InviteOnlySignUpComponent(props: InviteOnlySignUpProps) {
|
|||
return (
|
||||
<div className="login-form m-auto w-72">
|
||||
{error && (
|
||||
<div className="flex justify-center bg-red-200 rounded-md text-red-950 space-x-2 items-center p-4 transition-all shadow-sm">
|
||||
<div className="flex justify-center bg-red-200 rounded-md text-red-950 space-x-2 items-center p-4 transition-all shadow-xs">
|
||||
<AlertTriangle size={18} />
|
||||
<div className="font-bold text-sm">{error}</div>
|
||||
</div>
|
||||
)}
|
||||
{message && (
|
||||
<div className="flex flex-col space-y-4 justify-center bg-green-200 rounded-md text-green-950 space-x-2 items-center p-4 transition-all shadow-sm">
|
||||
<div className="flex flex-col space-y-4 justify-center bg-green-200 rounded-md text-green-950 space-x-2 items-center p-4 transition-all shadow-xs">
|
||||
<div className="flex space-x-2">
|
||||
<Check size={18} />
|
||||
<div className="font-bold text-sm">{message}</div>
|
||||
|
|
@ -185,7 +185,7 @@ function InviteOnlySignUpComponent(props: InviteOnlySignUpProps) {
|
|||
</FormLayout>
|
||||
<div>
|
||||
<div className='flex h-0.5 rounded-2xl bg-slate-100 mt-5 mb-5 mx-10'></div>
|
||||
<button onClick={() => signIn('google')} className="flex justify-center py-3 text-md w-full bg-white text-slate-600 space-x-3 font-semibold text-center p-2 rounded-md shadow hover:cursor-pointer">
|
||||
<button onClick={() => signIn('google')} className="flex justify-center py-3 text-md w-full bg-white text-slate-600 space-x-3 font-semibold text-center p-2 rounded-md shadow-sm hover:cursor-pointer">
|
||||
<img src="https://fonts.gstatic.com/s/i/productlogos/googleg/v6/24px.svg" alt="" />
|
||||
<span>Sign in with Google</span>
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -94,13 +94,13 @@ function OpenSignUpComponent() {
|
|||
return (
|
||||
<div className="login-form m-auto w-72">
|
||||
{error && (
|
||||
<div className="flex justify-center bg-red-200 rounded-md text-red-950 space-x-2 items-center p-4 transition-all shadow-sm">
|
||||
<div className="flex justify-center bg-red-200 rounded-md text-red-950 space-x-2 items-center p-4 transition-all shadow-xs">
|
||||
<AlertTriangle size={18} />
|
||||
<div className="font-bold text-sm">{error}</div>
|
||||
</div>
|
||||
)}
|
||||
{message && (
|
||||
<div className="flex flex-col space-y-4 justify-center bg-green-200 rounded-md text-green-950 space-x-2 items-center p-4 transition-all shadow-sm">
|
||||
<div className="flex flex-col space-y-4 justify-center bg-green-200 rounded-md text-green-950 space-x-2 items-center p-4 transition-all shadow-xs">
|
||||
<div className="flex space-x-2">
|
||||
<Check size={18} />
|
||||
<div className="font-bold text-sm">{message}</div>
|
||||
|
|
@ -179,7 +179,7 @@ function OpenSignUpComponent() {
|
|||
</FormLayout>
|
||||
<div>
|
||||
<div className='flex h-0.5 rounded-2xl bg-slate-100 mt-5 mb-5 mx-10'></div>
|
||||
<button onClick={() => signIn('google')} className="flex justify-center py-3 text-md w-full bg-white text-slate-600 space-x-3 font-semibold text-center p-2 rounded-md shadow hover:cursor-pointer">
|
||||
<button onClick={() => signIn('google')} className="flex justify-center py-3 text-md w-full bg-white text-slate-600 space-x-3 font-semibold text-center p-2 rounded-md shadow-sm hover:cursor-pointer">
|
||||
<img src="https://fonts.gstatic.com/s/i/productlogos/googleg/v6/24px.svg" alt="" />
|
||||
<span>Sign in with Google</span>
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -5,14 +5,14 @@ import { Suspense } from 'react'
|
|||
import PageLoading from '@components/Objects/Loaders/PageLoading'
|
||||
|
||||
type MetadataProps = {
|
||||
params: { orgslug: string; courseid: string }
|
||||
searchParams: { [key: string]: string | string[] | undefined }
|
||||
params: Promise<{ orgslug: string; courseid: string }>
|
||||
searchParams: Promise<{ [key: string]: string | string[] | undefined }>
|
||||
}
|
||||
|
||||
export async function generateMetadata(
|
||||
params
|
||||
: MetadataProps): Promise<Metadata> {
|
||||
const orgslug = params.searchParams.orgslug
|
||||
const orgslug = (await params.searchParams).orgslug
|
||||
// Get Org context information
|
||||
const org = await getOrganizationContextInfo(orgslug, {
|
||||
revalidate: 0,
|
||||
|
|
@ -25,7 +25,7 @@ export async function generateMetadata(
|
|||
}
|
||||
|
||||
const SignUp = async (params: any) => {
|
||||
const orgslug = params.searchParams.orgslug
|
||||
const orgslug = (await params.searchParams).orgslug
|
||||
const org = await getOrganizationContextInfo(orgslug, {
|
||||
revalidate: 0,
|
||||
tags: ['organizations'],
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
import { default as React } from 'react'
|
||||
import dynamic from 'next/dynamic'
|
||||
import { getCourseMetadata } from '@services/courses/courses'
|
||||
|
|
@ -8,17 +9,16 @@ 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 })
|
||||
import EditorWrapper from '@components/Objects/Editor/EditorWrapper'
|
||||
|
||||
|
||||
type MetadataProps = {
|
||||
params: { orgslug: string; courseid: string; activityid: string }
|
||||
searchParams: { [key: string]: string | string[] | undefined }
|
||||
params: Promise<{ orgslug: string; courseid: string; activityid: string }>
|
||||
searchParams: Promise<{ [key: string]: string | string[] | undefined }>
|
||||
}
|
||||
|
||||
export async function generateMetadata({
|
||||
params,
|
||||
}: MetadataProps): Promise<Metadata> {
|
||||
export async function generateMetadata(props: MetadataProps): Promise<Metadata> {
|
||||
const params = await props.params;
|
||||
const session = await getServerSession(nextAuthOptions)
|
||||
const access_token = session?.tokens?.access_token
|
||||
// Get Org context information
|
||||
|
|
@ -37,8 +37,8 @@ export async function generateMetadata({
|
|||
const EditActivity = async (params: any) => {
|
||||
const session = await getServerSession(nextAuthOptions)
|
||||
const access_token = session?.tokens?.access_token
|
||||
const activityuuid = params.params.activityuuid
|
||||
const courseid = params.params.courseid
|
||||
const activityuuid = (await params.params).activityuuid
|
||||
const courseid = (await params.params).courseid
|
||||
const courseInfo = await getCourseMetadata(
|
||||
courseid,
|
||||
{ revalidate: 0, tags: ['courses'] },
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ export default function RootLayout({
|
|||
animate="enter" // Animated state to variants.enter
|
||||
exit="exit" // Exit state (used later) to variants.exit
|
||||
transition={{ type: 'linear' }} // Set the transition to linear
|
||||
className=""
|
||||
>
|
||||
{children}
|
||||
</motion.main>
|
||||
|
|
|
|||
|
|
@ -9,13 +9,12 @@ import { getServerSession } from 'next-auth'
|
|||
import Link from 'next/link'
|
||||
|
||||
type MetadataProps = {
|
||||
params: { orgslug: string; courseid: string; collectionid: string }
|
||||
searchParams: { [key: string]: string | string[] | undefined }
|
||||
params: Promise<{ orgslug: string; courseid: string; collectionid: string }>
|
||||
searchParams: Promise<{ [key: string]: string | string[] | undefined }>
|
||||
}
|
||||
|
||||
export async function generateMetadata({
|
||||
params,
|
||||
}: MetadataProps): Promise<Metadata> {
|
||||
export async function generateMetadata(props: MetadataProps): Promise<Metadata> {
|
||||
const params = await props.params;
|
||||
const session = await getServerSession(nextAuthOptions)
|
||||
const access_token = session?.tokens?.access_token
|
||||
|
||||
|
|
@ -55,13 +54,13 @@ export async function generateMetadata({
|
|||
const CollectionPage = async (params: any) => {
|
||||
const session = await getServerSession(nextAuthOptions)
|
||||
const access_token = session?.tokens?.access_token
|
||||
const org = await getOrganizationContextInfo(params.params.orgslug, {
|
||||
const org = await getOrganizationContextInfo((await params.params).orgslug, {
|
||||
revalidate: 1800,
|
||||
tags: ['organizations'],
|
||||
})
|
||||
const orgslug = params.params.orgslug
|
||||
const orgslug = (await params.params).orgslug
|
||||
const col = await getCollectionById(
|
||||
params.params.collectionid,
|
||||
(await params.params).collectionid,
|
||||
access_token ? access_token : null,
|
||||
{ revalidate: 0, tags: ['collections'] }
|
||||
)
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ function NewCollection(params: any) {
|
|||
placeholder="Enter collection name"
|
||||
value={name}
|
||||
onChange={handleNameChange}
|
||||
className="mt-1 block w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition"
|
||||
className="mt-1 block w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-hidden focus:ring-2 focus:ring-blue-500 focus:border-transparent transition"
|
||||
maxLength={100}
|
||||
/>
|
||||
</label>
|
||||
|
|
@ -116,7 +116,7 @@ function NewCollection(params: any) {
|
|||
<span className="text-sm font-medium text-gray-700">Visibility</span>
|
||||
<select
|
||||
onChange={handleVisibilityChange}
|
||||
className="mt-1 block w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition"
|
||||
className="mt-1 block w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-hidden focus:ring-2 focus:ring-blue-500 focus:border-transparent transition"
|
||||
defaultValue={isPublic}
|
||||
>
|
||||
<option value="true">Public Collection - Visible to everyone</option>
|
||||
|
|
@ -131,7 +131,7 @@ function NewCollection(params: any) {
|
|||
value={description}
|
||||
onChange={handleDescriptionChange}
|
||||
rows={4}
|
||||
className="mt-1 block w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition"
|
||||
className="mt-1 block w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-hidden focus:ring-2 focus:ring-blue-500 focus:border-transparent transition"
|
||||
maxLength={500}
|
||||
/>
|
||||
</label>
|
||||
|
|
@ -168,7 +168,7 @@ function NewCollection(params: any) {
|
|||
}}
|
||||
className="h-4 w-4 text-blue-500 rounded border-gray-300 focus:ring-blue-500"
|
||||
/>
|
||||
<div className="relative w-24 h-16 rounded-md overflow-hidden bg-gray-100 flex-shrink-0">
|
||||
<div className="relative w-24 h-16 rounded-md overflow-hidden bg-gray-100 shrink-0">
|
||||
{course.thumbnail_image ? (
|
||||
<img
|
||||
src={getCourseThumbnailMediaDirectory(org.org_uuid, course.course_uuid, course.thumbnail_image)}
|
||||
|
|
@ -204,14 +204,14 @@ function NewCollection(params: any) {
|
|||
<button
|
||||
type="button"
|
||||
onClick={() => router.back()}
|
||||
className="px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition"
|
||||
className="px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 focus:outline-hidden focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isSubmitting}
|
||||
className="px-6 py-2 text-sm font-medium text-white bg-blue-600 rounded-lg shadow-sm hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition disabled:opacity-50 disabled:cursor-not-allowed flex items-center space-x-2"
|
||||
className="px-6 py-2 text-sm font-medium text-white bg-blue-600 rounded-lg shadow-xs hover:bg-blue-700 focus:outline-hidden focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition disabled:opacity-50 disabled:cursor-not-allowed flex items-center space-x-2"
|
||||
>
|
||||
{isSubmitting && <Loader2 className="w-4 h-4 animate-spin" />}
|
||||
<span>{isSubmitting ? 'Creating...' : 'Create Collection'}</span>
|
||||
|
|
|
|||
|
|
@ -14,13 +14,12 @@ import { getOrgThumbnailMediaDirectory } from '@services/media/media'
|
|||
import ContentPlaceHolderIfUserIsNotAdmin from '@components/Objects/ContentPlaceHolder'
|
||||
|
||||
type MetadataProps = {
|
||||
params: { orgslug: string; courseid: string }
|
||||
searchParams: { [key: string]: string | string[] | undefined }
|
||||
params: Promise<{ orgslug: string; courseid: string }>
|
||||
searchParams: Promise<{ [key: string]: string | string[] | undefined }>
|
||||
}
|
||||
|
||||
export async function generateMetadata({
|
||||
params,
|
||||
}: MetadataProps): Promise<Metadata> {
|
||||
export async function generateMetadata(props: MetadataProps): Promise<Metadata> {
|
||||
const params = await props.params;
|
||||
// Get Org context information
|
||||
const org = await getOrganizationContextInfo(params.orgslug, {
|
||||
revalidate: 0,
|
||||
|
|
@ -60,7 +59,7 @@ export async function generateMetadata({
|
|||
const CollectionsPage = async (params: any) => {
|
||||
const session = await getServerSession(nextAuthOptions)
|
||||
const access_token = session?.tokens?.access_token
|
||||
const orgslug = params.params.orgslug
|
||||
const orgslug = (await params.params).orgslug
|
||||
const org = await getOrganizationContextInfo(orgslug, {
|
||||
revalidate: 1800,
|
||||
tags: ['organizations'],
|
||||
|
|
|
|||
|
|
@ -171,7 +171,7 @@ function ActivityClient(props: ActivityClientProps) {
|
|||
</div>
|
||||
</div>
|
||||
{activity && activity.published == false && (
|
||||
<div className="p-7 drop-shadow-sm rounded-lg bg-gray-800">
|
||||
<div className="p-7 drop-shadow-xs rounded-lg bg-gray-800">
|
||||
<div className="text-white">
|
||||
<h1 className="font-bold text-2xl">
|
||||
This activity is not published yet
|
||||
|
|
@ -185,7 +185,7 @@ function ActivityClient(props: ActivityClientProps) {
|
|||
{activity.content.paid_access == false ? (
|
||||
<PaidCourseActivityDisclaimer course={course} />
|
||||
) : (
|
||||
<div className={`p-7 drop-shadow-sm rounded-lg ${bgColor}`}>
|
||||
<div className={`p-7 drop-shadow-xs rounded-lg ${bgColor}`}>
|
||||
{/* Activity Types */}
|
||||
<div>
|
||||
{activity.activity_type == 'TYPE_DYNAMIC' && (
|
||||
|
|
@ -461,7 +461,7 @@ function ActivityChapterDropdown(props: {
|
|||
<div className="relative" ref={dropdownRef}>
|
||||
<button
|
||||
onClick={toggleDropdown}
|
||||
className="flex items-center justify-center bg-white nice-shadow p-2.5 rounded-full"
|
||||
className="flex items-center justify-center bg-white nice-shadow p-2.5 rounded-full cursor-pointer"
|
||||
aria-label="View all activities"
|
||||
title="View all activities"
|
||||
>
|
||||
|
|
@ -469,12 +469,12 @@ function ActivityChapterDropdown(props: {
|
|||
</button>
|
||||
|
||||
{isOpen && (
|
||||
<div className={`absolute z-50 mt-2 ${isMobile ? 'left-0 w-[90vw] sm:w-80' : 'left-0 w-80'} max-h-[70vh] overflow-y-auto bg-white rounded-lg shadow-xl border border-gray-200 py-2 animate-in fade-in duration-200`}>
|
||||
<div className={`absolute z-50 mt-2 ${isMobile ? 'left-0 w-[90vw] sm:w-80' : 'left-0 w-80'} max-h-[70vh] cursor-pointer overflow-y-auto bg-white rounded-lg shadow-xl border border-gray-200 py-2 animate-in fade-in duration-200`}>
|
||||
<div className="px-4 py-2 border-b border-gray-100 flex justify-between items-center">
|
||||
<h3 className="font-bold text-gray-800">Course Content</h3>
|
||||
<button
|
||||
onClick={() => setIsOpen(false)}
|
||||
className="text-gray-500 hover:text-gray-700 p-1 rounded-full hover:bg-gray-100"
|
||||
className="text-gray-500 hover:text-gray-700 p-1 rounded-full hover:bg-gray-100 cursor-pointer"
|
||||
>
|
||||
<X size={18} />
|
||||
</button>
|
||||
|
|
@ -519,7 +519,7 @@ function ActivityChapterDropdown(props: {
|
|||
)?.steps?.find(
|
||||
(step: any) => (step.activity_id === activity.id || step.activity_id === activity.activity_uuid) && step.complete === true
|
||||
) && (
|
||||
<span className="ml-2 text-gray-400 flex-shrink-0">
|
||||
<span className="ml-2 text-gray-400 shrink-0">
|
||||
<Check size={14} />
|
||||
</span>
|
||||
)}
|
||||
|
|
@ -630,7 +630,7 @@ function ActivityNavigation(props: {
|
|||
<>
|
||||
<button
|
||||
onClick={() => navigateToActivity(prevActivity)}
|
||||
className={`flex items-center space-x-1.5 p-2 rounded-md transition-all duration-200 ${
|
||||
className={`flex items-center space-x-1.5 p-2 rounded-md transition-all duration-200 cursor-pointer ${
|
||||
prevActivity
|
||||
? 'text-gray-700'
|
||||
: 'opacity-50 text-gray-400 cursor-not-allowed'
|
||||
|
|
@ -638,7 +638,7 @@ function ActivityNavigation(props: {
|
|||
disabled={!prevActivity}
|
||||
title={prevActivity ? `Previous: ${prevActivity.name}` : 'No previous activity'}
|
||||
>
|
||||
<ChevronLeft size={20} className="text-gray-800 flex-shrink-0" />
|
||||
<ChevronLeft size={20} className="text-gray-800 shrink-0" />
|
||||
<div className="flex flex-col items-start">
|
||||
<span className="text-xs text-gray-500">Previous</span>
|
||||
<span className="text-sm capitalize font-semibold text-left">
|
||||
|
|
@ -649,7 +649,7 @@ function ActivityNavigation(props: {
|
|||
|
||||
<button
|
||||
onClick={() => navigateToActivity(nextActivity)}
|
||||
className={`flex items-center space-x-1.5 p-2 rounded-md transition-all duration-200 ${
|
||||
className={`flex items-center space-x-1.5 p-2 rounded-md transition-all duration-200 cursor-pointer ${
|
||||
nextActivity
|
||||
? 'text-gray-700'
|
||||
: 'opacity-50 text-gray-400 cursor-not-allowed'
|
||||
|
|
@ -663,7 +663,7 @@ function ActivityNavigation(props: {
|
|||
{nextActivity ? nextActivity.name : 'No next activity'}
|
||||
</span>
|
||||
</div>
|
||||
<ChevronRight size={20} className="text-gray-800 flex-shrink-0" />
|
||||
<ChevronRight size={20} className="text-gray-800 shrink-0" />
|
||||
</button>
|
||||
</>
|
||||
) : (
|
||||
|
|
@ -672,7 +672,7 @@ function ActivityNavigation(props: {
|
|||
<div className="justify-self-start">
|
||||
<button
|
||||
onClick={() => navigateToActivity(prevActivity)}
|
||||
className={`flex items-center space-x-1.5 px-3.5 py-2 rounded-md transition-all duration-200 ${
|
||||
className={`flex items-center space-x-1.5 px-3.5 py-2 rounded-md transition-all duration-200 cursor-pointer ${
|
||||
prevActivity
|
||||
? 'bg-white nice-shadow text-gray-700'
|
||||
: 'bg-gray-100 text-gray-400 cursor-not-allowed'
|
||||
|
|
@ -680,7 +680,7 @@ function ActivityNavigation(props: {
|
|||
disabled={!prevActivity}
|
||||
title={prevActivity ? `Previous: ${prevActivity.name}` : 'No previous activity'}
|
||||
>
|
||||
<ChevronLeft size={16} className="flex-shrink-0" />
|
||||
<ChevronLeft size={16} className="shrink-0" />
|
||||
<div className="flex flex-col items-start">
|
||||
<span className="text-xs text-gray-500">Previous</span>
|
||||
<span className="text-sm capitalize font-semibold text-left">
|
||||
|
|
@ -697,7 +697,7 @@ function ActivityNavigation(props: {
|
|||
<div className="justify-self-end">
|
||||
<button
|
||||
onClick={() => navigateToActivity(nextActivity)}
|
||||
className={`flex items-center space-x-1.5 px-3.5 py-2 rounded-md transition-all duration-200 ${
|
||||
className={`flex items-center space-x-1.5 px-3.5 py-2 rounded-md transition-all duration-200 cursor-pointer ${
|
||||
nextActivity
|
||||
? 'bg-white nice-shadow text-gray-700'
|
||||
: 'bg-gray-100 text-gray-400 cursor-not-allowed'
|
||||
|
|
@ -711,7 +711,7 @@ function ActivityNavigation(props: {
|
|||
{nextActivity ? nextActivity.name : 'No next activity'}
|
||||
</span>
|
||||
</div>
|
||||
<ChevronRight size={16} className="flex-shrink-0" />
|
||||
<ChevronRight size={16} className="shrink-0" />
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
|
|
@ -730,7 +730,7 @@ function ActivityNavigation(props: {
|
|||
{!isBottomNavVisible && (
|
||||
<div className="fixed bottom-8 left-1/2 transform -translate-x-1/2 z-50 w-[85%] sm:w-auto sm:min-w-[350px] max-w-lg transition-all duration-300 ease-in-out">
|
||||
<div
|
||||
className="bg-white/90 backdrop-blur-xl rounded-full py-1.5 px-2.5 shadow-sm animate-in fade-in slide-in-from-bottom duration-300"
|
||||
className="bg-white/90 backdrop-blur-xl rounded-full py-1.5 px-2.5 shadow-xs animate-in fade-in slide-in-from-bottom duration-300"
|
||||
>
|
||||
<NavigationButtons isFloating={true} />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -7,13 +7,12 @@ import { getServerSession } from 'next-auth'
|
|||
import { nextAuthOptions } from 'app/auth/options'
|
||||
|
||||
type MetadataProps = {
|
||||
params: { orgslug: string; courseuuid: string; activityid: string }
|
||||
searchParams: { [key: string]: string | string[] | undefined }
|
||||
params: Promise<{ orgslug: string; courseuuid: string; activityid: string }>
|
||||
searchParams: Promise<{ [key: string]: string | string[] | undefined }>
|
||||
}
|
||||
|
||||
export async function generateMetadata({
|
||||
params,
|
||||
}: MetadataProps): Promise<Metadata> {
|
||||
export async function generateMetadata(props: MetadataProps): Promise<Metadata> {
|
||||
const params = await props.params;
|
||||
const session = await getServerSession(nextAuthOptions)
|
||||
const access_token = session?.tokens?.access_token
|
||||
|
||||
|
|
@ -60,9 +59,9 @@ export async function generateMetadata({
|
|||
const ActivityPage = async (params: any) => {
|
||||
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 activityid = (await params.params).activityid
|
||||
const courseuuid = (await params.params).courseuuid
|
||||
const orgslug = (await params.params).orgslug
|
||||
|
||||
const course_meta = await getCourseMetadata(
|
||||
courseuuid,
|
||||
|
|
|
|||
|
|
@ -166,7 +166,7 @@ const CourseClient = (props: any) => {
|
|||
<div key={chapter} className="">
|
||||
<div className="flex text-lg py-4 px-4 outline outline-1 outline-neutral-200/40 font-bold bg-neutral-50 text-neutral-600 items-center">
|
||||
<h3 className="grow mr-3 break-words">{chapter.name}</h3>
|
||||
<p className="text-sm font-normal text-neutral-400 px-3 py-[2px] outline-1 outline outline-neutral-200 rounded-full whitespace-nowrap flex-shrink-0">
|
||||
<p className="text-sm font-normal text-neutral-400 px-3 py-[2px] outline-1 outline outline-neutral-200 rounded-full whitespace-nowrap shrink-0">
|
||||
{chapter.activities.length} Activities
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -8,13 +8,12 @@ import { nextAuthOptions } from 'app/auth/options'
|
|||
import { getServerSession } from 'next-auth'
|
||||
|
||||
type MetadataProps = {
|
||||
params: { orgslug: string; courseuuid: string }
|
||||
searchParams: { [key: string]: string | string[] | undefined }
|
||||
params: Promise<{ orgslug: string; courseuuid: string }>
|
||||
searchParams: Promise<{ [key: string]: string | string[] | undefined }>
|
||||
}
|
||||
|
||||
export async function generateMetadata({
|
||||
params,
|
||||
}: MetadataProps): Promise<Metadata> {
|
||||
export async function generateMetadata(props: MetadataProps): Promise<Metadata> {
|
||||
const params = await props.params;
|
||||
const session = await getServerSession(nextAuthOptions)
|
||||
const access_token = session?.tokens?.access_token
|
||||
|
||||
|
|
@ -67,8 +66,8 @@ export async function generateMetadata({
|
|||
}
|
||||
|
||||
const CoursePage = async (params: any) => {
|
||||
const courseuuid = params.params.courseuuid
|
||||
const orgslug = params.params.orgslug
|
||||
const courseuuid = (await params.params).courseuuid
|
||||
const orgslug = (await params.params).orgslug
|
||||
const session = await getServerSession(nextAuthOptions)
|
||||
const access_token = session?.tokens?.access_token
|
||||
const course_meta = await getCourseMetadata(
|
||||
|
|
|
|||
|
|
@ -8,13 +8,12 @@ import { getOrgCourses } from '@services/courses/courses'
|
|||
import { getOrgThumbnailMediaDirectory } from '@services/media/media'
|
||||
|
||||
type MetadataProps = {
|
||||
params: { orgslug: string }
|
||||
searchParams: { [key: string]: string | string[] | undefined }
|
||||
params: Promise<{ orgslug: string }>
|
||||
searchParams: Promise<{ [key: string]: string | string[] | undefined }>
|
||||
}
|
||||
|
||||
export async function generateMetadata({
|
||||
params,
|
||||
}: MetadataProps): Promise<Metadata> {
|
||||
export async function generateMetadata(props: MetadataProps): Promise<Metadata> {
|
||||
const params = await props.params;
|
||||
// Get Org context information
|
||||
const org = await getOrganizationContextInfo(params.orgslug, {
|
||||
revalidate: 0,
|
||||
|
|
@ -53,7 +52,7 @@ export async function generateMetadata({
|
|||
}
|
||||
|
||||
const CoursesPage = async (params: any) => {
|
||||
const orgslug = params.params.orgslug
|
||||
const orgslug = (await params.params).orgslug
|
||||
const org = await getOrganizationContextInfo(orgslug, {
|
||||
revalidate: 1800,
|
||||
tags: ['organizations'],
|
||||
|
|
|
|||
|
|
@ -1,16 +1,22 @@
|
|||
'use client'
|
||||
'use client';
|
||||
import { use } from "react";
|
||||
import '@styles/globals.css'
|
||||
import { SessionProvider } from 'next-auth/react'
|
||||
import Watermark from '@components/Objects/Watermark'
|
||||
import { OrgMenu } from '@components/Objects/Menus/OrgMenu'
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
params,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
params: any
|
||||
}) {
|
||||
export default function RootLayout(
|
||||
props: {
|
||||
children: React.ReactNode
|
||||
params: Promise<any>
|
||||
}
|
||||
) {
|
||||
const params = use(props.params);
|
||||
|
||||
const {
|
||||
children
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<>
|
||||
<SessionProvider>
|
||||
|
|
|
|||
|
|
@ -20,13 +20,12 @@ import LandingClassic from '@components/Landings/LandingClassic'
|
|||
import LandingCustom from '@components/Landings/LandingCustom'
|
||||
|
||||
type MetadataProps = {
|
||||
params: { orgslug: string }
|
||||
searchParams: { [key: string]: string | string[] | undefined }
|
||||
params: Promise<{ orgslug: string }>
|
||||
searchParams: Promise<{ [key: string]: string | string[] | undefined }>
|
||||
}
|
||||
|
||||
export async function generateMetadata({
|
||||
params,
|
||||
}: MetadataProps): Promise<Metadata> {
|
||||
export async function generateMetadata(props: MetadataProps): Promise<Metadata> {
|
||||
const params = await props.params;
|
||||
// Get Org context information
|
||||
const org = await getOrganizationContextInfo(params.orgslug, {
|
||||
revalidate: 0,
|
||||
|
|
@ -64,7 +63,7 @@ export async function generateMetadata({
|
|||
}
|
||||
|
||||
const OrgHomePage = async (params: any) => {
|
||||
const orgslug = params.params.orgslug
|
||||
const orgslug = (await params.params).orgslug
|
||||
const session = await getServerSession(nextAuthOptions)
|
||||
const access_token = session?.tokens?.access_token
|
||||
const courses = await getOrgCourses(
|
||||
|
|
|
|||
|
|
@ -6,13 +6,12 @@ import { getServerSession } from 'next-auth'
|
|||
import { nextAuthOptions } from 'app/auth/options'
|
||||
|
||||
type MetadataProps = {
|
||||
params: { orgslug: string }
|
||||
searchParams: { [key: string]: string | string[] | undefined }
|
||||
params: Promise<{ orgslug: string }>
|
||||
searchParams: Promise<{ [key: string]: string | string[] | undefined }>
|
||||
}
|
||||
|
||||
export async function generateMetadata({
|
||||
params,
|
||||
}: MetadataProps): Promise<Metadata> {
|
||||
export async function generateMetadata(props: MetadataProps): Promise<Metadata> {
|
||||
const params = await props.params;
|
||||
const session = await getServerSession(nextAuthOptions)
|
||||
const access_token = session?.tokens?.access_token
|
||||
// Get Org context information
|
||||
|
|
@ -28,7 +27,7 @@ export async function generateMetadata({
|
|||
}
|
||||
|
||||
const TrailPage = async (params: any) => {
|
||||
let orgslug = params.params.orgslug
|
||||
let orgslug = (await params.params).orgslug
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -209,12 +209,12 @@ function UpdateTaskRef() {
|
|||
|
||||
|
||||
return (
|
||||
<div className="w-auto bg-gray-50 rounded-xl outline outline-1 outline-gray-200 h-[200px] shadow">
|
||||
<div className="w-auto bg-gray-50 rounded-xl outline outline-1 outline-gray-200 h-[200px] shadow-sm">
|
||||
<div className="flex flex-col justify-center items-center h-full">
|
||||
<div className="flex flex-col justify-center items-center">
|
||||
<div className="flex flex-col justify-center items-center">
|
||||
{error && (
|
||||
<div className="flex justify-center bg-red-200 rounded-md text-red-950 space-x-2 items-center p-2 transition-all shadow-sm">
|
||||
<div className="flex justify-center bg-red-200 rounded-md text-red-950 space-x-2 items-center p-2 transition-all shadow-xs">
|
||||
<div className="text-sm font-semibold">{error}</div>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -224,8 +224,8 @@ export default function TaskFileObject({ view, user_id, assignmentTaskUUID }: Ta
|
|||
<Link
|
||||
href={getTaskFileSubmissionDir(org?.org_uuid, assignment.course_object.course_uuid, assignment.activity_object.activity_uuid, assignment.assignment_object.assignment_uuid, assignmentTaskUUID, userSubmissions.fileUUID)}
|
||||
target='_blank'
|
||||
className='flex flex-col rounded-lg bg-white text-gray-500 shadow-sm hover:shadow-md transition-shadow border border-gray-100 px-4 sm:px-5 py-4 space-y-1 items-center relative w-full sm:w-auto mx-auto'>
|
||||
<div className='absolute top-0 right-0 transform translate-x-1/2 -translate-y-1/2 bg-emerald-500 rounded-full p-1.5 text-white flex justify-center items-center shadow-sm'>
|
||||
className='flex flex-col rounded-lg bg-white text-gray-500 shadow-xs hover:shadow-md transition-shadow border border-gray-100 px-4 sm:px-5 py-4 space-y-1 items-center relative w-full sm:w-auto mx-auto'>
|
||||
<div className='absolute top-0 right-0 transform translate-x-1/2 -translate-y-1/2 bg-emerald-500 rounded-full p-1.5 text-white flex justify-center items-center shadow-xs'>
|
||||
<Cloud size={14} />
|
||||
</div>
|
||||
|
||||
|
|
@ -241,19 +241,19 @@ export default function TaskFileObject({ view, user_id, assignmentTaskUUID }: Ta
|
|||
)}
|
||||
{view === 'student' && (
|
||||
<>
|
||||
<div className="w-full bg-white rounded-lg border border-gray-100 min-h-[200px] shadow-sm px-4 sm:px-6 py-5 sm:py-6">
|
||||
<div className="w-full bg-white rounded-lg border border-gray-100 min-h-[200px] shadow-xs px-4 sm:px-6 py-5 sm:py-6">
|
||||
<div className="flex flex-col justify-center items-center h-full w-full">
|
||||
<div className="flex flex-col justify-center items-center w-full max-w-full">
|
||||
<div className="flex flex-col justify-center items-center w-full">
|
||||
{error && (
|
||||
<div className="flex justify-center bg-red-50 border border-red-100 rounded-md text-red-600 space-x-2 items-center p-3 transition-all shadow-sm w-full sm:w-auto mb-4">
|
||||
<div className="flex justify-center bg-red-50 border border-red-100 rounded-md text-red-600 space-x-2 items-center p-3 transition-all shadow-xs w-full sm:w-auto mb-4">
|
||||
<div className="text-xs sm:text-sm font-medium">{error}</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{localUploadFile && !isLoading && (
|
||||
<div className='flex flex-col rounded-lg bg-white text-gray-500 shadow-sm border border-gray-100 px-4 sm:px-5 py-4 space-y-1 items-center relative w-full sm:w-auto mt-3'>
|
||||
<div className='absolute top-0 right-0 transform translate-x-1/2 -translate-y-1/2 bg-emerald-500 rounded-full p-1.5 text-white flex justify-center items-center shadow-sm'>
|
||||
<div className='flex flex-col rounded-lg bg-white text-gray-500 shadow-xs border border-gray-100 px-4 sm:px-5 py-4 space-y-1 items-center relative w-full sm:w-auto mt-3'>
|
||||
<div className='absolute top-0 right-0 transform translate-x-1/2 -translate-y-1/2 bg-emerald-500 rounded-full p-1.5 text-white flex justify-center items-center shadow-xs'>
|
||||
<Cloud size={14} />
|
||||
</div>
|
||||
|
||||
|
|
@ -268,8 +268,8 @@ export default function TaskFileObject({ view, user_id, assignmentTaskUUID }: Ta
|
|||
</div>
|
||||
)}
|
||||
{userSubmissions.fileUUID && !isLoading && !localUploadFile && (
|
||||
<div className='flex flex-col rounded-lg bg-white text-gray-500 shadow-sm border border-gray-100 px-4 sm:px-5 py-4 space-y-1 items-center relative w-full sm:w-auto mt-3'>
|
||||
<div className='absolute top-0 right-0 transform translate-x-1/2 -translate-y-1/2 bg-emerald-500 rounded-full p-1.5 text-white flex justify-center items-center shadow-sm'>
|
||||
<div className='flex flex-col rounded-lg bg-white text-gray-500 shadow-xs border border-gray-100 px-4 sm:px-5 py-4 space-y-1 items-center relative w-full sm:w-auto mt-3'>
|
||||
<div className='absolute top-0 right-0 transform translate-x-1/2 -translate-y-1/2 bg-emerald-500 rounded-full p-1.5 text-white flex justify-center items-center shadow-xs'>
|
||||
<Cloud size={14} />
|
||||
</div>
|
||||
|
||||
|
|
@ -287,7 +287,7 @@ export default function TaskFileObject({ view, user_id, assignmentTaskUUID }: Ta
|
|||
</div>
|
||||
{!access_token ? (
|
||||
<div className="flex justify-center items-center w-full mt-5">
|
||||
<div className="flex justify-center bg-amber-50 border border-amber-100 rounded-md text-amber-600 space-x-2 items-center p-3 transition-all shadow-sm w-full sm:w-auto">
|
||||
<div className="flex justify-center bg-amber-50 border border-amber-100 rounded-md text-amber-600 space-x-2 items-center p-3 transition-all shadow-xs w-full sm:w-auto">
|
||||
<Info size={15} className="text-amber-500" />
|
||||
<div className="text-xs sm:text-sm font-medium">Please sign in to upload files</div>
|
||||
</div>
|
||||
|
|
@ -314,7 +314,7 @@ export default function TaskFileObject({ view, user_id, assignmentTaskUUID }: Ta
|
|||
onChange={handleFileChange}
|
||||
/>
|
||||
<button
|
||||
className="font-medium antialiased items-center text-white text-xs sm:text-sm rounded-md px-4 sm:px-5 py-2.5 flex bg-emerald-500 hover:bg-emerald-600 transition-colors shadow-sm"
|
||||
className="font-medium antialiased items-center text-white text-xs sm:text-sm rounded-md px-4 sm:px-5 py-2.5 flex bg-emerald-500 hover:bg-emerald-600 transition-colors shadow-xs"
|
||||
onClick={() => document.getElementById("fileInput_" + assignmentTaskUUID)?.click()}
|
||||
>
|
||||
<UploadCloud size={15} className="mr-2" />
|
||||
|
|
|
|||
|
|
@ -346,7 +346,7 @@ function TaskQuizObject({ view, assignmentTaskUUID, user_id }: TaskQuizObjectPro
|
|||
<div className="flex" key={oIndex}>
|
||||
<div
|
||||
onClick={() => view === 'student' && chooseOption(qIndex, oIndex)}
|
||||
className={"answer outline outline-3 outline-white pr-2 shadow w-full flex items-center space-x-2 h-[30px] hover:bg-opacity-100 hover:shadow-md rounded-lg bg-white text-sm duration-150 cursor-pointer ease-linear nice-shadow " + (view == 'student' ? 'active:scale-110' : '')}
|
||||
className={"answer outline outline-3 outline-white pr-2 shadow-sm w-full flex items-center space-x-2 h-[30px] hover:bg-opacity-100 hover:shadow-md rounded-lg bg-white text-sm duration-150 cursor-pointer ease-linear nice-shadow " + (view == 'student' ? 'active:scale-110' : '')}
|
||||
>
|
||||
<div className="font-bold text-base flex items-center h-full w-[40px] rounded-l-md text-slate-800 bg-slate-100/80">
|
||||
<p className="mx-auto font-bold text-sm">{String.fromCharCode(65 + oIndex)}</p>
|
||||
|
|
@ -459,7 +459,7 @@ function TaskQuizObject({ view, assignmentTaskUUID, user_id }: TaskQuizObjectPro
|
|||
{view === 'teacher' && oIndex === question.options.length - 1 && questions[qIndex].options.length <= 4 && (
|
||||
<div className="flex justify-center mx-auto px-2">
|
||||
<div
|
||||
className="outline text-xs outline-3 outline-white px-2 shadow w-full flex items-center h-[30px] hover:bg-opacity-100 hover:shadow-md rounded-lg bg-white duration-150 cursor-pointer ease-linear nice-shadow"
|
||||
className="outline text-xs outline-3 outline-white px-2 shadow-sm w-full flex items-center h-[30px] hover:bg-opacity-100 hover:shadow-md rounded-lg bg-white duration-150 cursor-pointer ease-linear nice-shadow"
|
||||
onClick={() => addOption(qIndex)}
|
||||
>
|
||||
<Plus size={14} className="inline-block" />
|
||||
|
|
@ -476,7 +476,7 @@ function TaskQuizObject({ view, assignmentTaskUUID, user_id }: TaskQuizObjectPro
|
|||
{view === 'teacher' && questions.length <= 5 && (
|
||||
<div className="flex justify-center mx-auto px-2">
|
||||
<div
|
||||
className="flex w-full my-2 py-2 px-4 bg-white text-slate text-xs rounded-md nice-shadow hover:shadow-sm cursor-pointer space-x-3 items-center transition duration-150 ease-linear"
|
||||
className="flex w-full my-2 py-2 px-4 bg-white text-slate text-xs rounded-md nice-shadow hover:shadow-xs cursor-pointer space-x-3 items-center transition duration-150 ease-linear"
|
||||
onClick={addQuestion}
|
||||
>
|
||||
<PlusCircle size={14} className="inline-block" />
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ function AssignmentTaskEditor({ page }: any) {
|
|||
<div>
|
||||
<div
|
||||
onClick={() => deleteTaskUI()}
|
||||
className='flex px-2 py-1.5 cursor-pointer rounded-md space-x-2 items-center bg-gradient-to-bl text-red-800 bg-rose-100 border border-rose-600/10 shadow-rose-900/10 shadow-lg'>
|
||||
className='flex px-2 py-1.5 cursor-pointer rounded-md space-x-2 items-center bg-linear-to-bl text-red-800 bg-rose-100 border border-rose-600/10 shadow-rose-900/10 shadow-lg'>
|
||||
<Trash size={18} />
|
||||
<p className='text-xs font-semibold'>Delete Task</p>
|
||||
</div>
|
||||
|
|
@ -91,7 +91,7 @@ function AssignmentTaskEditor({ page }: any) {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='ml-10 mr-10 mt-10 mx-auto bg-white rounded-xl shadow-sm px-6 py-5 nice-shadow'>
|
||||
<div className='ml-10 mr-10 mt-10 mx-auto bg-white rounded-xl shadow-xs px-6 py-5 nice-shadow'>
|
||||
{selectedSubPage === 'general' && <AssignmentTaskGeneralEdit />}
|
||||
{selectedSubPage === 'content' && <AssignmentTaskContentEdit />}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ function PublishingState() {
|
|||
<Link
|
||||
target='_blank'
|
||||
href={`/course/${assignment?.course_object?.course_uuid.replace('course_', '')}/activity/${assignment?.activity_object?.activity_uuid.replace('activity_', '')}`}
|
||||
className='flex px-3 py-2 cursor-pointer rounded-md space-x-2 items-center bg-gradient-to-bl text-cyan-800 font-medium from-sky-400/50 to-cyan-200/80 border border-cyan-600/10 shadow-cyan-900/10 shadow-lg'>
|
||||
className='flex px-3 py-2 cursor-pointer rounded-md space-x-2 items-center bg-linear-to-bl text-cyan-800 font-medium from-sky-400/50 to-cyan-200/80 border border-cyan-600/10 shadow-cyan-900/10 shadow-lg'>
|
||||
<Eye size={18} />
|
||||
<p className=' text-sm font-bold'>Preview</p>
|
||||
</Link>
|
||||
|
|
@ -151,7 +151,7 @@ function PublishingState() {
|
|||
content="Make your Assignment unavailable for students" >
|
||||
<div
|
||||
onClick={() => updateAssignmentPublishState(assignment?.assignment_object?.assignment_uuid)}
|
||||
className='flex px-3 py-2 cursor-pointer rounded-md space-x-2 items-center bg-gradient-to-bl text-gray-800 font-medium from-gray-400/50 to-gray-200/80 border border-gray-600/10 shadow-gray-900/10 shadow-lg'>
|
||||
className='flex px-3 py-2 cursor-pointer rounded-md space-x-2 items-center bg-linear-to-bl text-gray-800 font-medium from-gray-400/50 to-gray-200/80 border border-gray-600/10 shadow-gray-900/10 shadow-lg'>
|
||||
<BookX size={18} />
|
||||
<p className='text-sm font-bold'>Unpublish</p>
|
||||
</div>
|
||||
|
|
@ -164,7 +164,7 @@ function PublishingState() {
|
|||
content="Make your Assignment public and available for students" >
|
||||
<div
|
||||
onClick={() => updateAssignmentPublishState(assignment?.assignment_object?.assignment_uuid)}
|
||||
className='flex px-3 py-2 cursor-pointer rounded-md space-x-2 items-center bg-gradient-to-bl text-green-800 font-medium from-green-400/50 to-lime-200/80 border border-green-600/10 shadow-green-900/10 shadow-lg'>
|
||||
className='flex px-3 py-2 cursor-pointer rounded-md space-x-2 items-center bg-linear-to-bl text-green-800 font-medium from-green-400/50 to-lime-200/80 border border-green-600/10 shadow-green-900/10 shadow-lg'>
|
||||
<BookOpen size={18} />
|
||||
<p className=' text-sm font-bold'>Publish</p>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ function AssignmentEditorSubPage({ assignmentuuid }: { assignmentuuid: string })
|
|||
</div>
|
||||
<AssignmentTasks assignment_uuid={'assignment_' + assignmentuuid} />
|
||||
</div>
|
||||
<div className='flex flex-grow bg-[#fefcfe] nice-shadow h-full w-full'>
|
||||
<div className='flex grow bg-[#fefcfe] nice-shadow h-full w-full'>
|
||||
<AssignmentProvider assignment_uuid={'assignment_' + assignmentuuid}>
|
||||
<AssignmentTaskEditor page='general' />
|
||||
</AssignmentProvider>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
'use client'
|
||||
import { getUriWithOrg } from '@services/config/config'
|
||||
import React from 'react'
|
||||
import React, { use } from 'react';
|
||||
import { CourseProvider } from '../../../../../../../../components/Contexts/CourseContext'
|
||||
import Link from 'next/link'
|
||||
import { CourseOverviewTop } from '@components/Dashboard/Misc/CourseOverviewTop'
|
||||
|
|
@ -16,14 +16,15 @@ export type CourseOverviewParams = {
|
|||
subpage: string
|
||||
}
|
||||
|
||||
function CourseOverviewPage({ params }: { params: CourseOverviewParams }) {
|
||||
function CourseOverviewPage(props: { params: Promise<CourseOverviewParams> }) {
|
||||
const params = use(props.params);
|
||||
function getEntireCourseUUID(courseuuid: string) {
|
||||
// add course_ to uuid
|
||||
return `course_${courseuuid}`
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="h-screen w-full bg-[#f8f8f8] grid grid-rows-[auto,1fr]">
|
||||
<div className="h-screen w-full bg-[#f8f8f8] grid grid-rows-[auto_1fr]">
|
||||
<CourseProvider courseuuid={getEntireCourseUUID(params.courseuuid)}>
|
||||
<div className="pl-10 pr-10 text-sm tracking-tight bg-[#fcfbfc] z-10 shadow-[0px_4px_16px_rgba(0,0,0,0.06)]">
|
||||
<CourseOverviewTop params={params} />
|
||||
|
|
|
|||
|
|
@ -7,13 +7,12 @@ import { getServerSession } from 'next-auth'
|
|||
import { getOrgCourses } from '@services/courses/courses'
|
||||
|
||||
type MetadataProps = {
|
||||
params: { orgslug: string }
|
||||
searchParams: { [key: string]: string | string[] | undefined }
|
||||
params: Promise<{ orgslug: string }>
|
||||
searchParams: Promise<{ [key: string]: string | string[] | undefined }>
|
||||
}
|
||||
|
||||
export async function generateMetadata({
|
||||
params,
|
||||
}: MetadataProps): Promise<Metadata> {
|
||||
export async function generateMetadata(props: MetadataProps): Promise<Metadata> {
|
||||
const params = await props.params;
|
||||
// Get Org context information
|
||||
const org = await getOrganizationContextInfo(params.orgslug, {
|
||||
revalidate: 1800,
|
||||
|
|
@ -44,7 +43,7 @@ export async function generateMetadata({
|
|||
}
|
||||
|
||||
async function CoursesPage(params: any) {
|
||||
const orgslug = params.params.orgslug
|
||||
const orgslug = (await params.params).orgslug
|
||||
const org = await getOrganizationContextInfo(orgslug, {
|
||||
revalidate: 1800,
|
||||
tags: ['organizations'],
|
||||
|
|
|
|||
|
|
@ -6,13 +6,18 @@ export const metadata: Metadata = {
|
|||
title: 'LearnHouse Dashboard',
|
||||
}
|
||||
|
||||
function DashboardLayout({
|
||||
children,
|
||||
params,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
params: any
|
||||
}) {
|
||||
async function DashboardLayout(
|
||||
props: {
|
||||
children: React.ReactNode
|
||||
params: Promise<any>
|
||||
}
|
||||
) {
|
||||
const params = await props.params;
|
||||
|
||||
const {
|
||||
children
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<>
|
||||
<ClientAdminLayout
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import BreadCrumbs from '@components/Dashboard/Misc/BreadCrumbs'
|
|||
import { getUriWithOrg } from '@services/config/config'
|
||||
import { ImageIcon, Info, LockIcon, SearchIcon, TextIcon, LucideIcon, Share2Icon, LayoutDashboardIcon } from 'lucide-react'
|
||||
import Link from 'next/link'
|
||||
import React, { useEffect } from 'react'
|
||||
import React, { useEffect, use } from 'react';
|
||||
import { motion } from 'framer-motion'
|
||||
import OrgEditGeneral from '@components/Dashboard/Pages/Org/OrgEditGeneral/OrgEditGeneral'
|
||||
import OrgEditImages from '@components/Dashboard/Pages/Org/OrgEditImages/OrgEditImages'
|
||||
|
|
@ -49,7 +49,8 @@ function TabLink({ tab, isActive, orgslug }: {
|
|||
)
|
||||
}
|
||||
|
||||
function OrgPage({ params }: { params: OrgParams }) {
|
||||
function OrgPage(props: { params: Promise<OrgParams> }) {
|
||||
const params = use(props.params);
|
||||
const [H1Label, setH1Label] = React.useState('')
|
||||
const [H2Label, setH2Label] = React.useState('')
|
||||
|
||||
|
|
|
|||
|
|
@ -17,55 +17,55 @@ function DashboardHome() {
|
|||
/>
|
||||
</div>
|
||||
<AdminAuthorization authorizationMode="component">
|
||||
<div className="flex flex-col sm:flex-row space-y-4 sm:space-y-0 sm:space-x-4 lg:space-x-10">
|
||||
<div className="flex flex-col sm:flex-row gap-4 lg:gap-10">
|
||||
{/* Card components */}
|
||||
<DashboardCard
|
||||
href="/dash/courses"
|
||||
icon={<BookCopy className="mx-auto text-gray-500" size={50} />}
|
||||
icon={<BookCopy className="mx-auto text-gray-500/100" size={50} />}
|
||||
title="Courses"
|
||||
description="Create and manage courses, chapters and activities"
|
||||
/>
|
||||
<DashboardCard
|
||||
href="/dash/org/settings/general"
|
||||
icon={<School className="mx-auto text-gray-500" size={50} />}
|
||||
icon={<School className="mx-auto text-gray-500/100" size={50} />}
|
||||
title="Organization"
|
||||
description="Configure your Organization general settings"
|
||||
/>
|
||||
<DashboardCard
|
||||
href="/dash/users/settings/users"
|
||||
icon={<Users className="mx-auto text-gray-500" size={50} />}
|
||||
icon={<Users className="mx-auto text-gray-500/100" size={50} />}
|
||||
title="Users"
|
||||
description="Manage your Organization's users, roles"
|
||||
/>
|
||||
</div>
|
||||
</AdminAuthorization>
|
||||
<div className="flex flex-col space-y-6 sm:space-y-10 mt-6 sm:mt-10">
|
||||
<div className="flex flex-col gap-6 sm:gap-10 mt-6 sm:mt-10">
|
||||
<AdminAuthorization authorizationMode="component">
|
||||
<div className="h-1 w-[100px] bg-neutral-200 rounded-full mx-auto"></div>
|
||||
<div className="h-1 w-[100px] bg-neutral-200/100 rounded-full mx-auto"></div>
|
||||
<div className="flex justify-center items-center">
|
||||
<Link
|
||||
href={'https://university.learnhouse.io/'}
|
||||
target='_blank'
|
||||
className="flex mt-4 sm:mt-[40px] bg-black space-x-2 items-center py-3 px-7 rounded-lg shadow-lg hover:scale-105 transition-all ease-linear cursor-pointer"
|
||||
className="flex mt-4 sm:mt-[40px] bg-black gap-2 items-center py-3 px-7 rounded-lg shadow-lg hover:scale-105 transition-all ease-linear cursor-pointer"
|
||||
>
|
||||
<University className="text-gray-100" size={20} />
|
||||
<div className="text-sm font-bold text-gray-100">
|
||||
<University className="text-gray-100/100" size={20} />
|
||||
<div className="text-sm font-bold text-gray-100/100">
|
||||
LearnHouse University
|
||||
</div>
|
||||
</Link>
|
||||
</div>
|
||||
<div className="mx-auto mt-4 sm:mt-[40px] w-28 h-1 bg-neutral-200 rounded-full"></div>
|
||||
<div className="mx-auto mt-4 sm:mt-[40px] w-28 h-1 bg-neutral-200/100 rounded-full"></div>
|
||||
</AdminAuthorization>
|
||||
|
||||
<Link
|
||||
href={'/dash/user-account/settings/general'}
|
||||
className="flex bg-white shadow-lg p-4 items-center rounded-lg mx-auto hover:scale-105 transition-all ease-linear cursor-pointer max-w-md"
|
||||
>
|
||||
<div className="flex flex-col sm:flex-row mx-auto space-y-2 sm:space-y-0 sm:space-x-3 items-center text-center sm:text-left">
|
||||
<Settings className="text-gray-500" size={20} />
|
||||
<div className="flex flex-col sm:flex-row mx-auto gap-2 sm:gap-3 items-center text-center sm:text-left">
|
||||
<Settings className="text-gray-500/100" size={20} />
|
||||
<div>
|
||||
<div className="font-bold text-gray-500">Account Settings</div>
|
||||
<p className="text-sm text-gray-400">
|
||||
<div className="font-bold text-gray-500/100">Account Settings</div>
|
||||
<p className="text-sm text-gray-400/100">
|
||||
Configure your personal settings, passwords, email
|
||||
</p>
|
||||
</div>
|
||||
|
|
@ -83,10 +83,10 @@ function DashboardCard({ href, icon, title, description }: { href: string, icon:
|
|||
href={href}
|
||||
className="flex bg-white shadow-lg p-6 w-full sm:w-[250px] rounded-lg items-center mx-auto hover:scale-105 transition-all ease-linear cursor-pointer"
|
||||
>
|
||||
<div className="flex flex-col mx-auto space-y-2">
|
||||
<div className="flex flex-col mx-auto gap-2">
|
||||
{icon}
|
||||
<div className="text-center font-bold text-gray-500">{title}</div>
|
||||
<p className="text-center text-sm text-gray-400">{description}</p>
|
||||
<div className="text-center font-bold text-gray-500/100">{title}</div>
|
||||
<p className="text-center text-sm text-gray-400/100">{description}</p>
|
||||
</div>
|
||||
</Link>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
'use client'
|
||||
import React from 'react'
|
||||
import React, { use } from 'react';
|
||||
import { motion } from 'framer-motion'
|
||||
import BreadCrumbs from '@components/Dashboard/Misc/BreadCrumbs'
|
||||
import Link from 'next/link'
|
||||
|
|
@ -17,7 +17,8 @@ export type PaymentsParams = {
|
|||
orgslug: string
|
||||
}
|
||||
|
||||
function PaymentsPage({ params }: { params: PaymentsParams }) {
|
||||
function PaymentsPage(props: { params: Promise<PaymentsParams> }) {
|
||||
const params = use(props.params);
|
||||
const session = useLHSession() as any
|
||||
const org = useOrg() as any
|
||||
const subpage = params.subpage || 'customers'
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
'use client'
|
||||
import React, { useEffect } from 'react'
|
||||
import React, { useEffect, use } from 'react';
|
||||
import { motion } from 'framer-motion'
|
||||
import UserEditGeneral from '@components/Dashboard/Pages/UserAccount/UserEditGeneral/UserEditGeneral'
|
||||
import UserEditPassword from '@components/Dashboard/Pages/UserAccount/UserEditPassword/UserEditPassword'
|
||||
|
|
@ -14,7 +14,8 @@ export type SettingsParams = {
|
|||
orgslug: string
|
||||
}
|
||||
|
||||
function SettingsPage({ params }: { params: SettingsParams }) {
|
||||
function SettingsPage(props: { params: Promise<SettingsParams> }) {
|
||||
const params = use(props.params);
|
||||
const session = useLHSession() as any
|
||||
|
||||
useEffect(() => {}, [session])
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
'use client'
|
||||
import React, { useEffect } from 'react'
|
||||
import React, { useEffect, use } from 'react';
|
||||
import { motion } from 'framer-motion'
|
||||
import Link from 'next/link'
|
||||
import { useMediaQuery } from 'usehooks-ts'
|
||||
|
|
@ -18,7 +18,8 @@ export type SettingsParams = {
|
|||
orgslug: string
|
||||
}
|
||||
|
||||
function UsersSettingsPage({ params }: { params: SettingsParams }) {
|
||||
function UsersSettingsPage(props: { params: Promise<SettingsParams> }) {
|
||||
const params = use(props.params);
|
||||
const session = useLHSession() as any
|
||||
const org = useOrg() as any
|
||||
const [H1Label, setH1Label] = React.useState('')
|
||||
|
|
@ -63,7 +64,7 @@ function UsersSettingsPage({ params }: { params: SettingsParams }) {
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="h-screen w-full bg-[#f8f8f8] grid grid-rows-[auto,1fr]">
|
||||
<div className="h-screen w-full bg-[#f8f8f8] grid grid-rows-[auto_1fr]">
|
||||
<div className="pl-10 pr-10 tracking-tight bg-[#fcfbfc] z-10 shadow-[0px_4px_16px_rgba(0,0,0,0.06)]">
|
||||
<BreadCrumbs type="orgusers"></BreadCrumbs>
|
||||
<div className="my-2 py-3">
|
||||
|
|
|
|||
|
|
@ -1,17 +1,23 @@
|
|||
'use client'
|
||||
'use client';
|
||||
import { use } from "react";
|
||||
import { OrgProvider } from '@components/Contexts/OrgContext'
|
||||
import NextTopLoader from 'nextjs-toploader';
|
||||
import Toast from '@components/Objects/StyledElements/Toast/Toast'
|
||||
import '@styles/globals.css'
|
||||
import Onboarding from '@components/Objects/Onboarding/Onboarding';
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
params,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
params: any
|
||||
}) {
|
||||
export default function RootLayout(
|
||||
props: {
|
||||
children: React.ReactNode
|
||||
params: Promise<any>
|
||||
}
|
||||
) {
|
||||
const params = use(props.params);
|
||||
|
||||
const {
|
||||
children
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<OrgProvider orgslug={params.orgslug}>
|
||||
|
|
|
|||
|
|
@ -16,5 +16,6 @@
|
|||
"ui": "@/components/ui",
|
||||
"lib": "@/lib",
|
||||
"hooks": "@/hooks"
|
||||
}
|
||||
},
|
||||
"iconLibrary": "lucide"
|
||||
}
|
||||
|
|
@ -50,7 +50,7 @@ function EditCourseAccess(props: EditCourseAccessProps) {
|
|||
{courseStructure && (
|
||||
<div>
|
||||
<div className="h-6"></div>
|
||||
<div className="mx-4 sm:mx-10 bg-white rounded-xl shadow-sm px-4 py-4">
|
||||
<div className="mx-4 sm:mx-10 bg-white rounded-xl shadow-xs px-4 py-4">
|
||||
<div className="flex flex-col bg-gray-50 -space-y-1 px-3 sm:px-5 py-3 rounded-md mb-3">
|
||||
<h1 className="font-bold text-lg sm:text-xl text-gray-800">Access to the course</h1>
|
||||
<h2 className="text-gray-500 text-xs sm:text-sm">
|
||||
|
|
|
|||
|
|
@ -145,11 +145,11 @@ function EditCourseGeneral(props: EditCourseStructureProps) {
|
|||
return (
|
||||
<div>
|
||||
<div className="h-6"></div>
|
||||
<div className="ml-10 mr-10 mx-auto bg-white rounded-xl shadow-sm px-6 py-5">
|
||||
<div className="ml-10 mr-10 mx-auto bg-white rounded-xl shadow-xs px-6 py-5">
|
||||
{courseStructure && (
|
||||
<div className="editcourse-form">
|
||||
{error && (
|
||||
<div className="flex justify-center bg-red-200 rounded-md text-red-950 space-x-2 items-center p-4 transition-all shadow-sm">
|
||||
<div className="flex justify-center bg-red-200 rounded-md text-red-950 space-x-2 items-center p-4 transition-all shadow-xs">
|
||||
<AlertTriangle size={18} />
|
||||
<div className="font-bold text-sm">{error}</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -249,7 +249,7 @@ const LearningItemsList = ({ value, onChange, error }: LearningItemsListProps) =
|
|||
setShowEmojiPicker(showEmojiPicker === item.id ? null : item.id);
|
||||
setShowLinkInput(null);
|
||||
}}
|
||||
className="text-lg flex-shrink-0"
|
||||
className="text-lg shrink-0"
|
||||
>
|
||||
<span>{item.emoji}</span>
|
||||
</button>
|
||||
|
|
@ -261,7 +261,7 @@ const LearningItemsList = ({ value, onChange, error }: LearningItemsListProps) =
|
|||
onFocus={() => handleInputFocus(item.id)}
|
||||
onBlur={handleInputBlur}
|
||||
placeholder="Enter learning item..."
|
||||
className="flex-grow border-0 bg-transparent focus-visible:ring-0 px-0 h-8 text-sm learning-item-input"
|
||||
className="grow border-0 bg-transparent focus-visible:ring-0 px-0 h-8 text-sm learning-item-input"
|
||||
/>
|
||||
|
||||
{item.link && (
|
||||
|
|
@ -318,7 +318,7 @@ const LearningItemsList = ({ value, onChange, error }: LearningItemsListProps) =
|
|||
)}
|
||||
|
||||
{showLinkInput === item.id && (
|
||||
<div ref={linkInputRef} className="mt-1 p-2 bg-white border border-gray-200 rounded-lg shadow-sm">
|
||||
<div ref={linkInputRef} className="mt-1 p-2 bg-white border border-gray-200 rounded-lg shadow-xs">
|
||||
<Input
|
||||
ref={setLinkInputRef(item.id)}
|
||||
value={items.find(i => i.id === item.id)?.link || ''}
|
||||
|
|
|
|||
|
|
@ -52,19 +52,19 @@ function ThumbnailUpdate() {
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="w-auto bg-gray-50 rounded-xl outline outline-1 outline-gray-200 h-[200px] shadow">
|
||||
<div className="w-auto bg-gray-50 rounded-xl outline outline-1 outline-gray-200 h-[200px] shadow-sm">
|
||||
<div className="flex flex-col justify-center items-center h-full">
|
||||
<div className="flex flex-col justify-center items-center">
|
||||
<div className="flex flex-col justify-center items-center">
|
||||
{error && (
|
||||
<div className="flex justify-center bg-red-200 rounded-md text-red-950 space-x-2 items-center p-2 transition-all shadow-sm">
|
||||
<div className="flex justify-center bg-red-200 rounded-md text-red-950 space-x-2 items-center p-2 transition-all shadow-xs">
|
||||
<div className="text-sm font-semibold">{error}</div>
|
||||
</div>
|
||||
)}
|
||||
{localThumbnail ? (
|
||||
<img
|
||||
src={URL.createObjectURL(localThumbnail)}
|
||||
className={`${isLoading ? 'animate-pulse' : ''} shadow w-[200px] h-[100px] rounded-md`}
|
||||
className={`${isLoading ? 'animate-pulse' : ''} shadow-sm w-[200px] h-[100px] rounded-md`}
|
||||
/>
|
||||
) : (
|
||||
<img
|
||||
|
|
@ -73,7 +73,7 @@ function ThumbnailUpdate() {
|
|||
course.courseStructure.course_uuid,
|
||||
course.courseStructure.thumbnail_image
|
||||
) : '/empty_thumbnail.png'}`}
|
||||
className="shadow w-[200px] h-[100px] rounded-md bg-gray-200"
|
||||
className="shadow-sm w-[200px] h-[100px] rounded-md bg-gray-200"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ const UnsplashImagePicker: React.FC<UnsplashImagePickerProps> = ({ onSelect, onC
|
|||
value={query}
|
||||
onChange={handleSearch}
|
||||
placeholder="Search for images..."
|
||||
className="w-full p-2 pl-10 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
className="w-full p-2 pl-10 border rounded-lg focus:outline-hidden focus:ring-2 focus:ring-blue-500"
|
||||
/>
|
||||
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400" size={20} />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -117,10 +117,10 @@ function NewActivityButton(props: NewActivityButtonProps) {
|
|||
onClick={() => {
|
||||
openNewActivityModal(props.chapterId)
|
||||
}}
|
||||
className="flex w-44 h-10 space-x-2 items-center py-2 my-3 rounded-xl justify-center text-white bg-black hover:cursor-pointer"
|
||||
className="flex w-44 h-10 items-center justify-center py-2 my-3 rounded-xl text-white bg-black hover:cursor-pointer"
|
||||
>
|
||||
<Layers className="" size={17} />
|
||||
<div className="text-sm mx-auto my-auto items-center font-bold">
|
||||
<Layers size={17} />
|
||||
<div className="text-sm font-bold ml-2">
|
||||
Add Activity
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import { useLHSession } from '@components/Contexts/LHSessionContext'
|
|||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { Draggable } from 'react-beautiful-dnd'
|
||||
import { Draggable } from '@hello-pangea/dnd'
|
||||
import { mutate } from 'swr'
|
||||
import { deleteAssignmentUsingActivityUUID, getAssignmentFromActivityUUID } from '@services/courses/assignments'
|
||||
import { useOrg } from '@components/Contexts/OrgContext'
|
||||
|
|
@ -114,7 +114,7 @@ function ActivityElement(props: ActivitiyElementProps) {
|
|||
>
|
||||
{(provided, snapshot) => (
|
||||
<div
|
||||
className="flex flex-col sm:flex-row py-2 px-3 my-2 w-full rounded-md bg-gray-50 text-gray-500 hover:bg-gray-100 hover:scale-102 space-y-2 sm:space-y-0 sm:space-x-2 items-center ring-1 ring-inset ring-gray-400/10 nice-shadow"
|
||||
className="flex flex-col sm:flex-row py-2 px-3 my-2 w-full rounded-md bg-gray-50 text-gray-500 hover:bg-gray-100 hover:scale-102 space-y-2 sm:space-y-0 sm:space-x-2 items-center shadow-md border-1 border-gray-200 nice-shadow transition-all duration-200"
|
||||
key={props.activity.id}
|
||||
{...provided.draggableProps}
|
||||
{...provided.dragHandleProps}
|
||||
|
|
@ -129,7 +129,7 @@ function ActivityElement(props: ActivitiyElementProps) {
|
|||
<div className="chapter-modification-zone text-[7px] text-gray-600 shadow-inner bg-gray-200/60 py-1 px-4 rounded-lg space-x-3">
|
||||
<input
|
||||
type="text"
|
||||
className="bg-transparent outline-none text-xs text-gray-500"
|
||||
className="bg-transparent outline-hidden text-xs text-gray-500"
|
||||
placeholder="Activity name"
|
||||
value={
|
||||
modifiedActivity
|
||||
|
|
@ -166,8 +166,8 @@ function ActivityElement(props: ActivitiyElementProps) {
|
|||
<button
|
||||
className={`p-1 px-2 sm:px-3 border shadow-md rounded-md font-bold text-xs flex items-center space-x-1 transition-colors duration-200 ${
|
||||
!props.activity.published
|
||||
? 'bg-gradient-to-bl text-green-800 from-green-400/50 to-lime-200/80 border-green-600/10 hover:from-green-500/50 hover:to-lime-300/80'
|
||||
: 'bg-gradient-to-bl text-gray-800 from-gray-400/50 to-gray-200/80 border-gray-600/10 hover:from-gray-500/50 hover:to-gray-300/80'
|
||||
? 'bg-linear-to-bl text-green-800 from-green-400/50 to-lime-200/80 border-green-600/10 hover:from-green-500/50 hover:to-lime-300/80'
|
||||
: 'bg-linear-to-bl text-gray-800 from-gray-400/50 to-gray-200/80 border-gray-600/10 hover:from-gray-500/50 hover:to-gray-300/80'
|
||||
}`}
|
||||
onClick={() => changePublicStatus()}
|
||||
>
|
||||
|
|
@ -192,7 +192,7 @@ function ActivityElement(props: ActivitiyElementProps) {
|
|||
)}`
|
||||
}
|
||||
prefetch
|
||||
className="p-1 px-2 sm:px-3 bg-gradient-to-bl text-cyan-800 from-sky-400/50 to-cyan-200/80 border border-cyan-600/10 shadow-md rounded-md font-bold text-xs flex items-center space-x-1 transition-colors duration-200 hover:from-sky-500/50 hover:to-cyan-300/80"
|
||||
className="p-1 px-2 sm:px-3 bg-linear-to-bl text-cyan-800 from-sky-400/50 to-cyan-200/80 border border-cyan-600/10 shadow-md rounded-md font-bold text-xs flex items-center space-x-1 transition-colors duration-200 hover:from-sky-500/50 hover:to-cyan-300/80"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Eye strokeWidth={2} size={14} className="text-sky-600" />
|
||||
|
|
@ -244,7 +244,7 @@ const ActivityTypeIndicator = ({activityType, isMobile} : { activityType: keyof
|
|||
const {displayName, Icon} = ACTIVITIES[activityType]
|
||||
|
||||
return (
|
||||
<div className={`px-3 text-gray-300 space-x-1 w-28 flex ${isMobile ? 'flex-col' : ''}`}>
|
||||
<div className={`text-gray-300 space-x-1 w-28 flex ${isMobile ? 'flex-col' : ''}`}>
|
||||
<div className="flex space-x-2 items-center">
|
||||
<Icon className="size-4" />{' '}
|
||||
<div className="text-xs bg-gray-200 text-gray-400 font-bold px-2 py-1 rounded-full mx-auto justify-center align-middle">
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import {
|
|||
Trash2,
|
||||
} from 'lucide-react'
|
||||
import React from 'react'
|
||||
import { Draggable, Droppable } from 'react-beautiful-dnd'
|
||||
import { Draggable, Droppable } from '@hello-pangea/dnd'
|
||||
import ActivityElement from './ActivityElement'
|
||||
import NewActivityButton from '../Buttons/NewActivityButton'
|
||||
import { deleteChapter, updateChapter } from '@services/courses/chapters'
|
||||
|
|
@ -92,7 +92,7 @@ function ChapterElement(props: ChapterElementProps) {
|
|||
<div className="chapter-modification-zone bg-neutral-100 py-1 px-2 sm:px-4 rounded-lg flex items-center space-x-2">
|
||||
<input
|
||||
type="text"
|
||||
className="bg-transparent outline-none text-sm text-neutral-700 w-full max-w-[150px] sm:max-w-none"
|
||||
className="bg-transparent outline-hidden text-sm text-neutral-700 w-full max-w-[150px] sm:max-w-none"
|
||||
placeholder="Chapter name"
|
||||
value={
|
||||
modifiedChapter
|
||||
|
|
@ -133,7 +133,7 @@ function ChapterElement(props: ChapterElementProps) {
|
|||
dialogTitle={'Delete ' + props.chapter.name + ' ?'}
|
||||
dialogTrigger={
|
||||
<button
|
||||
className="hover:cursor-pointer p-1 px-2 sm:px-3 bg-red-600 rounded-md shadow flex items-center text-rose-100 text-sm"
|
||||
className="hover:cursor-pointer p-1 px-2 sm:px-3 bg-red-600 rounded-md shadow-sm flex items-center text-rose-100 text-sm"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Trash2 size={15} className="text-rose-200" />
|
||||
|
|
@ -151,7 +151,7 @@ function ChapterElement(props: ChapterElementProps) {
|
|||
>
|
||||
{(provided) => (
|
||||
<div {...provided.droppableProps} ref={provided.innerRef}>
|
||||
<div className="flex flex-col">
|
||||
<div className="flex flex-col min-h-[60px]">
|
||||
{activities.map((activity: any, index: any) => {
|
||||
return (
|
||||
<div key={activity.activity_uuid} className="flex items-center ">
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
import { getAPIUrl } from '@services/config/config'
|
||||
import { revalidateTags } from '@services/utils/ts/requests'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { DragDropContext, Droppable } from 'react-beautiful-dnd'
|
||||
import { DragDropContext, Droppable } from '@hello-pangea/dnd'
|
||||
import { mutate } from 'swr'
|
||||
import ChapterElement from './DraggableElements/ChapterElement'
|
||||
import PageLoading from '@components/Objects/Loaders/PageLoading'
|
||||
|
|
@ -164,7 +164,7 @@ const EditCourseStructure = (props: EditCourseStructureProps) => {
|
|||
dialogTitle="Create chapter"
|
||||
dialogDescription="Add a new chapter to the course"
|
||||
dialogTrigger={
|
||||
<div className="w-44 my-16 py-5 max-w-screen-2xl mx-auto bg-cyan-800 text-white rounded-xl shadow-sm px-6 items-center flex flex-row h-10">
|
||||
<div className="w-44 my-16 py-5 max-w-(--breakpoint-2xl) mx-auto bg-cyan-800 text-white rounded-xl shadow-xs px-6 items-center flex flex-row h-10">
|
||||
<div className="mx-auto flex space-x-2 items-center hover:cursor-pointer">
|
||||
<Hexagon
|
||||
strokeWidth={3}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from
|
|||
import { Button } from "@components/ui/button"
|
||||
import { Label } from "@components/ui/label"
|
||||
import { SiLoom, SiYoutube } from '@icons-pack/react-simple-icons'
|
||||
import { DragDropContext, Droppable, Draggable, DropResult } from 'react-beautiful-dnd'
|
||||
import { DragDropContext, Droppable, Draggable, DropResult } from '@hello-pangea/dnd'
|
||||
|
||||
const SUPPORTED_FILES = constructAcceptValue(['png', 'jpg'])
|
||||
|
||||
|
|
@ -367,21 +367,21 @@ export default function OrgEditImages() {
|
|||
<TabsList className="grid w-full grid-cols-3 p-1 bg-gray-100 rounded-lg">
|
||||
<TabsTrigger
|
||||
value="logo"
|
||||
className="data-[state=active]:bg-white data-[state=active]:shadow-sm transition-all flex items-center space-x-2"
|
||||
className="data-[state=active]:bg-white data-[state=active]:shadow-xs transition-all flex items-center space-x-2"
|
||||
>
|
||||
<StarIcon size={16} />
|
||||
<span>Logo</span>
|
||||
</TabsTrigger>
|
||||
<TabsTrigger
|
||||
value="thumbnail"
|
||||
className="data-[state=active]:bg-white data-[state=active]:shadow-sm transition-all flex items-center space-x-2"
|
||||
className="data-[state=active]:bg-white data-[state=active]:shadow-xs transition-all flex items-center space-x-2"
|
||||
>
|
||||
<ImageIcon size={16} />
|
||||
<span>Thumbnail</span>
|
||||
</TabsTrigger>
|
||||
<TabsTrigger
|
||||
value="previews"
|
||||
className="data-[state=active]:bg-white data-[state=active]:shadow-sm transition-all flex items-center space-x-2"
|
||||
className="data-[state=active]:bg-white data-[state=active]:shadow-xs transition-all flex items-center space-x-2"
|
||||
>
|
||||
<Images size={16} />
|
||||
<span>Previews</span>
|
||||
|
|
@ -390,7 +390,7 @@ export default function OrgEditImages() {
|
|||
|
||||
<TabsContent value="logo" className="mt-2">
|
||||
<div className="flex flex-col space-y-5 w-full">
|
||||
<div className="w-full bg-gradient-to-b from-gray-50 to-white rounded-xl transition-all duration-300 py-8">
|
||||
<div className="w-full bg-linear-to-b from-gray-50 to-white rounded-xl transition-all duration-300 py-8">
|
||||
<div className="flex flex-col justify-center items-center space-y-8">
|
||||
<div className="relative group">
|
||||
<div
|
||||
|
|
@ -416,9 +416,9 @@ export default function OrgEditImages() {
|
|||
disabled={isLogoUploading}
|
||||
className={cn(
|
||||
"font-medium text-sm px-6 py-2.5 rounded-full",
|
||||
"bg-gradient-to-r from-blue-500 to-blue-600 text-white",
|
||||
"bg-linear-to-r from-blue-500 to-blue-600 text-white",
|
||||
"hover:from-blue-600 hover:to-blue-700",
|
||||
"shadow-sm hover:shadow transition-all duration-300",
|
||||
"shadow-xs hover:shadow-sm transition-all duration-300",
|
||||
"flex items-center space-x-2",
|
||||
isLogoUploading && "opacity-75 cursor-not-allowed"
|
||||
)}
|
||||
|
|
@ -443,7 +443,7 @@ export default function OrgEditImages() {
|
|||
|
||||
<TabsContent value="thumbnail" className="mt-2">
|
||||
<div className="flex flex-col space-y-5 w-full">
|
||||
<div className="w-full bg-gradient-to-b from-gray-50 to-white rounded-xl transition-all duration-300 py-8">
|
||||
<div className="w-full bg-linear-to-b from-gray-50 to-white rounded-xl transition-all duration-300 py-8">
|
||||
<div className="flex flex-col justify-center items-center space-y-8">
|
||||
<div className="relative group">
|
||||
<div
|
||||
|
|
@ -469,9 +469,9 @@ export default function OrgEditImages() {
|
|||
disabled={isThumbnailUploading}
|
||||
className={cn(
|
||||
"font-medium text-sm px-6 py-2.5 rounded-full",
|
||||
"bg-gradient-to-r from-purple-500 to-purple-600 text-white",
|
||||
"bg-linear-to-r from-purple-500 to-purple-600 text-white",
|
||||
"hover:from-purple-600 hover:to-purple-700",
|
||||
"shadow-sm hover:shadow transition-all duration-300",
|
||||
"shadow-xs hover:shadow-sm transition-all duration-300",
|
||||
"flex items-center space-x-2",
|
||||
isThumbnailUploading && "opacity-75 cursor-not-allowed"
|
||||
)}
|
||||
|
|
@ -496,7 +496,7 @@ export default function OrgEditImages() {
|
|||
|
||||
<TabsContent value="previews" className="mt-4">
|
||||
<div className="flex flex-col space-y-5 w-full">
|
||||
<div className="w-full bg-gradient-to-b from-gray-50 to-white rounded-xl transition-all duration-300 py-6">
|
||||
<div className="w-full bg-linear-to-b from-gray-50 to-white rounded-xl transition-all duration-300 py-6">
|
||||
<div className="flex flex-col justify-center items-center space-y-6">
|
||||
<DragDropContext onDragEnd={handleDragEnd}>
|
||||
<Droppable droppableId="previews" direction="horizontal">
|
||||
|
|
@ -520,7 +520,7 @@ export default function OrgEditImages() {
|
|||
ref={provided.innerRef}
|
||||
{...provided.draggableProps}
|
||||
className={cn(
|
||||
"relative group flex-shrink-0",
|
||||
"relative group shrink-0",
|
||||
"w-48",
|
||||
snapshot.isDragging ? "scale-105 z-50" : "hover:scale-102",
|
||||
)}
|
||||
|
|
@ -529,7 +529,7 @@ export default function OrgEditImages() {
|
|||
onClick={() => removePreview(preview.id)}
|
||||
className={cn(
|
||||
"absolute -top-2 -right-2 bg-red-500 hover:bg-red-600 text-white rounded-full p-1.5",
|
||||
"opacity-0 group-hover:opacity-100 z-10 shadow-sm",
|
||||
"opacity-0 group-hover:opacity-100 z-10 shadow-xs",
|
||||
"transition-opacity duration-200"
|
||||
)}
|
||||
>
|
||||
|
|
@ -539,7 +539,7 @@ export default function OrgEditImages() {
|
|||
{...provided.dragHandleProps}
|
||||
className={cn(
|
||||
"absolute -top-2 -left-2 bg-gray-600 hover:bg-gray-700 text-white rounded-full p-1.5",
|
||||
"opacity-0 group-hover:opacity-100 cursor-grab active:cursor-grabbing z-10 shadow-sm",
|
||||
"opacity-0 group-hover:opacity-100 cursor-grab active:cursor-grabbing z-10 shadow-xs",
|
||||
"transition-opacity duration-200"
|
||||
)}
|
||||
>
|
||||
|
|
@ -551,7 +551,7 @@ export default function OrgEditImages() {
|
|||
`w-full ${PREVIEW_HEIGHT} bg-contain bg-no-repeat bg-center rounded-xl bg-white`,
|
||||
"border border-gray-200 hover:border-gray-300",
|
||||
"transition-colors duration-200",
|
||||
snapshot.isDragging ? "shadow-lg" : "shadow-sm hover:shadow-md"
|
||||
snapshot.isDragging ? "shadow-lg" : "shadow-xs hover:shadow-md"
|
||||
)}
|
||||
style={{
|
||||
backgroundImage: `url(${getOrgPreviewMediaDirectory(org?.org_uuid, preview.id)})`,
|
||||
|
|
@ -561,7 +561,7 @@ export default function OrgEditImages() {
|
|||
<div className={cn(
|
||||
`w-full ${PREVIEW_HEIGHT} relative rounded-xl overflow-hidden`,
|
||||
"border border-gray-200 hover:border-gray-300 transition-colors duration-200",
|
||||
snapshot.isDragging ? "shadow-lg" : "shadow-sm hover:shadow-md"
|
||||
snapshot.isDragging ? "shadow-lg" : "shadow-xs hover:shadow-md"
|
||||
)}>
|
||||
<div
|
||||
className="absolute inset-0 bg-cover bg-center"
|
||||
|
|
@ -583,7 +583,7 @@ export default function OrgEditImages() {
|
|||
{provided.placeholder}
|
||||
{previews.length < 4 && (
|
||||
<div className={cn(
|
||||
"flex-shrink-0 w-48",
|
||||
"shrink-0 w-48",
|
||||
previews.length === 0 && "m-0"
|
||||
)}>
|
||||
<Dialog open={videoDialogOpen} onOpenChange={(open) => {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
import React from 'react'
|
||||
import { LandingObject, LandingSection, LandingHeroSection, LandingTextAndImageSection, LandingLogos, LandingPeople, LandingBackground, LandingButton, LandingHeading, LandingImage, LandingFeaturedCourses } from './landing_types'
|
||||
import { Plus, Eye, ArrowUpDown, Trash2, GripVertical, LayoutTemplate, ImageIcon, Users, Award, ArrowRight, Edit, Link, Upload, Save, BookOpen, TextIcon } from 'lucide-react'
|
||||
import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd'
|
||||
import { DragDropContext, Droppable, Draggable } from '@hello-pangea/dnd'
|
||||
import { Input } from "@components/ui/input"
|
||||
import { Textarea } from "@components/ui/textarea"
|
||||
import { Label } from "@components/ui/label"
|
||||
|
|
@ -288,7 +288,7 @@ const OrgEditLanding = () => {
|
|||
onChange={() => setIsLandingEnabled(!isLandingEnabled)}
|
||||
className="sr-only peer"
|
||||
/>
|
||||
<div className="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-600"></div>
|
||||
<div className="w-11 h-6 bg-gray-200 peer-focus:outline-hidden peer-focus:ring-4 peer-focus:ring-blue-300 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-600"></div>
|
||||
</label>
|
||||
<Button
|
||||
variant="default"
|
||||
|
|
@ -328,10 +328,10 @@ const OrgEditLanding = () => {
|
|||
ref={provided.innerRef}
|
||||
{...provided.draggableProps}
|
||||
onClick={() => setSelectedSection(index)}
|
||||
className={`p-4 bg-white/80 backdrop-blur-sm rounded-lg cursor-pointer border ${
|
||||
className={`p-4 bg-white/80 backdrop-blur-xs rounded-lg cursor-pointer border ${
|
||||
selectedSection === index
|
||||
? 'border-blue-500 bg-blue-50 ring-2 ring-blue-500/20 shadow-sm'
|
||||
: 'border-gray-200 hover:border-gray-300 hover:bg-gray-50/50 hover:shadow-sm'
|
||||
? 'border-blue-500 bg-blue-50 ring-2 ring-blue-500/20 shadow-xs'
|
||||
: 'border-gray-200 hover:border-gray-300 hover:bg-gray-50/50 hover:shadow-xs'
|
||||
} ${snapshot.isDragging ? 'shadow-lg ring-2 ring-blue-500/20 rotate-2' : ''}`}
|
||||
>
|
||||
<div className="flex items-center justify-between group">
|
||||
|
|
@ -888,7 +888,7 @@ const HeroSectionEditor: React.FC<{
|
|||
<TabsContent value="buttons" className="space-y-4 mt-4">
|
||||
<div className="space-y-3">
|
||||
{section.buttons.map((button, index) => (
|
||||
<div key={index} className="grid grid-cols-[1fr,1fr,auto] gap-2 p-4 border rounded-lg">
|
||||
<div key={index} className="grid grid-cols-[1fr_1fr_auto] gap-2 p-4 border rounded-lg">
|
||||
<div className="space-y-2">
|
||||
<Label>Button Text & Colors</Label>
|
||||
<Input
|
||||
|
|
@ -1297,7 +1297,7 @@ const LogosSectionEditor: React.FC<{
|
|||
</div>
|
||||
|
||||
{section.logos.map((logo, index) => (
|
||||
<div key={index} className="grid grid-cols-[1fr,1fr,auto] gap-2">
|
||||
<div key={index} className="grid grid-cols-[1fr_1fr_auto] gap-2">
|
||||
<div className="space-y-2">
|
||||
<Input
|
||||
value={logo.url}
|
||||
|
|
@ -1400,7 +1400,7 @@ const PeopleSectionEditor: React.FC<{
|
|||
<Label>People</Label>
|
||||
<div className="space-y-4 mt-2">
|
||||
{section.people.map((person, index) => (
|
||||
<div key={index} className="grid grid-cols-[1fr,1fr,1fr,auto] gap-4 p-4 border rounded-lg">
|
||||
<div key={index} className="grid grid-cols-[1fr_1fr_1fr_auto] gap-4 p-4 border rounded-lg">
|
||||
<div className="space-y-2">
|
||||
<Label>Name</Label>
|
||||
<Input
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ const PaymentsConfigurationPage: React.FC = () => {
|
|||
|
||||
<div className="flex flex-col rounded-lg light-shadow">
|
||||
{stripeConfig ? (
|
||||
<div className="flex items-center justify-between bg-gradient-to-r from-indigo-500 to-purple-600 p-6 rounded-lg shadow-md">
|
||||
<div className="flex items-center justify-between bg-linear-to-r from-indigo-500 to-purple-600 p-6 rounded-lg shadow-md">
|
||||
<div className="flex items-center space-x-3">
|
||||
<SiStripe className="text-white" size={32} />
|
||||
<div className="flex flex-col">
|
||||
|
|
@ -187,7 +187,7 @@ const PaymentsConfigurationPage: React.FC = () => {
|
|||
) : (
|
||||
<Button
|
||||
onClick={enableStripe}
|
||||
className="flex items-center justify-center space-x-2 bg-gradient-to-r p-3 from-indigo-500 to-purple-600 text-white px-6 rounded-lg hover:from-indigo-600 hover:to-purple-700 transition duration-300 shadow-md disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
className="flex items-center justify-center space-x-2 bg-linear-to-r p-3 from-indigo-500 to-purple-600 text-white px-6 rounded-lg hover:from-indigo-600 hover:to-purple-700 transition duration-300 shadow-md disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
disabled={isOnboarding}
|
||||
>
|
||||
{isOnboarding ? (
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ function PaymentsProductPage() {
|
|||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex-grow overflow-hidden">
|
||||
<div className="grow overflow-hidden">
|
||||
<div className={`transition-all duration-300 ease-in-out ${expandedProducts[product.id] ? 'max-h-[1000px]' : 'max-h-24'} overflow-hidden`}>
|
||||
<p className="text-gray-600">
|
||||
{product.description}
|
||||
|
|
@ -194,7 +194,7 @@ function PaymentsProductPage() {
|
|||
<div className="flex justify-center items-center py-10">
|
||||
<button
|
||||
onClick={() => setIsCreateModalOpen(true)}
|
||||
className={`mb-4 flex items-center space-x-2 px-3 py-1.5 rounded-lg bg-gradient-to-bl text-white font-medium from-gray-700 to-gray-900 border border-gray-600 shadow-gray-900/20 nice-shadow transition duration-300 ${isStripeEnabled ? 'hover:from-gray-600 hover:to-gray-800' : 'opacity-50 cursor-not-allowed'
|
||||
className={`mb-4 flex items-center space-x-2 px-3 py-1.5 rounded-lg bg-linear-to-bl text-white font-medium from-gray-700 to-gray-900 border border-gray-600 shadow-gray-900/20 nice-shadow transition duration-300 ${isStripeEnabled ? 'hover:from-gray-600 hover:to-gray-800' : 'opacity-50 cursor-not-allowed'
|
||||
}`}
|
||||
disabled={!isStripeEnabled}
|
||||
>
|
||||
|
|
@ -264,7 +264,7 @@ const EditProductForm = ({ product, onSuccess, onCancel }: { product: any, onSuc
|
|||
</div>
|
||||
|
||||
<div className="flex space-x-2">
|
||||
<div className="flex-grow">
|
||||
<div className="grow">
|
||||
<Label htmlFor="amount">Price</Label>
|
||||
<Field name="amount" as={Input} type="number" placeholder="Price" />
|
||||
<ErrorMessage name="amount" component="div" className="text-red-500 text-sm mt-1" />
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ const CreateProductForm: React.FC<{ onSuccess: () => void }> = ({ onSuccess }) =
|
|||
</div>
|
||||
|
||||
<div className="flex space-x-2">
|
||||
<div className="flex-grow">
|
||||
<div className="grow">
|
||||
<Label htmlFor="amount">
|
||||
{values.price_type === 'fixed_price' ? 'Price' : 'Minimum Amount'}
|
||||
</Label>
|
||||
|
|
|
|||
|
|
@ -43,12 +43,12 @@ const CoursePreview = ({ course, orgslug, onLink, isLinked }: CoursePreviewProps
|
|||
<div className="flex gap-4 p-4 bg-white rounded-lg border border-gray-100 hover:border-gray-200 transition-colors">
|
||||
{/* Thumbnail */}
|
||||
<div
|
||||
className="flex-shrink-0 w-[120px] h-[68px] rounded-md bg-cover bg-center ring-1 ring-inset ring-black/10"
|
||||
className="shrink-0 w-[120px] h-[68px] rounded-md bg-cover bg-center ring-1 ring-inset ring-black/10"
|
||||
style={{ backgroundImage: `url(${thumbnailImage})` }}
|
||||
/>
|
||||
|
||||
{/* Content */}
|
||||
<div className="flex-grow space-y-1">
|
||||
<div className="grow space-y-1">
|
||||
<h3 className="font-medium text-gray-900 line-clamp-1">
|
||||
{course.name}
|
||||
</h3>
|
||||
|
|
@ -58,7 +58,7 @@ const CoursePreview = ({ course, orgslug, onLink, isLinked }: CoursePreviewProps
|
|||
</div>
|
||||
|
||||
{/* Action Button */}
|
||||
<div className="flex-shrink-0 flex items-center">
|
||||
<div className="shrink-0 flex items-center">
|
||||
{isLinked ? (
|
||||
<Button
|
||||
variant="outline"
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ function UserEditGeneral() {
|
|||
toast.success('Profile Updated Successfully', { duration: 4000 })
|
||||
|
||||
// Show message about logging in with new email
|
||||
toast((t) => (
|
||||
toast((t: any) => (
|
||||
<div className="flex items-center gap-2">
|
||||
<span>Please login again with your new email: {newEmail}</span>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ function UserEditPassword() {
|
|||
|
||||
// Show success message and notify about logout
|
||||
toast.success('Password updated successfully', { duration: 4000 })
|
||||
toast((t) => (
|
||||
toast((t: any) => (
|
||||
<div className="flex items-center gap-2">
|
||||
<span>Please login again with your new password</span>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ function OrgAccess() {
|
|||
{!isLoading ? (
|
||||
<>
|
||||
<div className="h-6"></div>
|
||||
<div className="ml-10 mr-10 mx-auto bg-white rounded-xl shadow-sm px-4 py-4 anit ">
|
||||
<div className="ml-10 mr-10 mx-auto bg-white rounded-xl shadow-xs px-4 py-4 anit ">
|
||||
<div className="flex flex-col bg-gray-50 -space-y-1 px-5 py-3 rounded-md mb-3 ">
|
||||
<h1 className="font-bold text-xl text-gray-800">Join method</h1>
|
||||
<h2 className="text-gray-500 text-md">
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ function OrgUserGroups() {
|
|||
return (
|
||||
<>
|
||||
<div className="h-6"></div>
|
||||
<div className="ml-10 mr-10 mx-auto bg-white rounded-xl shadow-sm px-4 py-4">
|
||||
<div className="ml-10 mr-10 mx-auto bg-white rounded-xl shadow-xs px-4 py-4">
|
||||
<div className="flex flex-col bg-gray-50 -space-y-1 px-5 py-3 rounded-md mb-3 ">
|
||||
<h1 className="font-bold text-xl text-gray-800">Manage UserGroups & Users</h1>
|
||||
<h2 className="text-gray-500 text-sm">
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ function OrgUsers() {
|
|||
<>
|
||||
<Toast></Toast>
|
||||
<div className="h-6"></div>
|
||||
<div className="ml-10 mr-10 mx-auto bg-white rounded-xl shadow-sm px-4 py-4 ">
|
||||
<div className="ml-10 mr-10 mx-auto bg-white rounded-xl shadow-xs px-4 py-4 ">
|
||||
<div className="flex flex-col bg-gray-50 -space-y-1 px-5 py-3 rounded-md mb-3 ">
|
||||
<h1 className="font-bold text-xl text-gray-800">Active users</h1>
|
||||
<h2 className="text-gray-500 text-md">
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ function OrgUsersAdd() {
|
|||
{!isLoading ? (
|
||||
<>
|
||||
<div className="h-6"></div>
|
||||
<div className="ml-10 mr-10 mx-auto bg-white rounded-xl shadow-sm px-4 py-4 anit ">
|
||||
<div className="ml-10 mr-10 mx-auto bg-white rounded-xl shadow-xs px-4 py-4 anit ">
|
||||
<div className="flex flex-col bg-gray-50 -space-y-1 px-5 py-3 rounded-md mb-3 ">
|
||||
<h1 className="font-bold text-xl text-gray-800">Invite users to your Organization</h1>
|
||||
<h2 className="text-gray-500 text-md">
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ function LandingCustom({ landing, orgslug }: LandingCustomProps) {
|
|||
<a
|
||||
key={index}
|
||||
href={button.link}
|
||||
className="w-full sm:w-auto px-6 py-2.5 rounded-lg text-sm font-extrabold shadow transition-transform hover:scale-105"
|
||||
className="w-full sm:w-auto px-6 py-2.5 rounded-lg text-sm font-extrabold shadow-sm transition-transform hover:scale-105"
|
||||
style={{
|
||||
backgroundColor: button.background,
|
||||
color: button.color
|
||||
|
|
@ -123,7 +123,7 @@ function LandingCustom({ landing, orgslug }: LandingCustomProps) {
|
|||
<a
|
||||
key={index}
|
||||
href={button.link}
|
||||
className="px-6 py-3 rounded-xl font-medium shadow-sm transition-all duration-200 hover:scale-105"
|
||||
className="px-6 py-3 rounded-xl font-medium shadow-xs transition-all duration-200 hover:scale-105"
|
||||
style={{
|
||||
backgroundColor: button.background,
|
||||
color: button.color
|
||||
|
|
@ -136,7 +136,7 @@ function LandingCustom({ landing, orgslug }: LandingCustomProps) {
|
|||
</div>
|
||||
<div className="flex-1 w-full md:w-auto">
|
||||
<div className="relative w-full max-w-[500px] mx-auto px-4 md:px-8">
|
||||
<div className="relative w-full aspect-[4/3]">
|
||||
<div className="relative w-full aspect-4/3">
|
||||
<img
|
||||
src={section.image.url}
|
||||
alt={section.image.alt}
|
||||
|
|
@ -242,7 +242,7 @@ function LandingCustom({ landing, orgslug }: LandingCustomProps) {
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-between w-full max-w-screen-2xl mx-auto px-4 sm:px-6 lg:px-16 h-full">
|
||||
<div className="flex flex-col items-center justify-between w-full max-w-(--breakpoint-2xl) mx-auto px-4 sm:px-6 lg:px-16 h-full">
|
||||
{landing.sections.map((section) => renderSection(section))}
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -81,8 +81,8 @@ function ActivityChatMessageBox(props: ActivityChatMessageBoxProps) {
|
|||
|
||||
// TODO : come up with a better way to handle this
|
||||
const inputClass = aiChatBotState.isWaitingForResponse
|
||||
? 'ring-1 ring-inset ring-white/10 bg-gray-950/40 w-full rounded-lg outline-none px-4 py-2 text-white text-sm placeholder:text-white/30 opacity-30 '
|
||||
: 'ring-1 ring-inset ring-white/10 bg-gray-950/40 w-full rounded-lg outline-none px-4 py-2 text-white text-sm placeholder:text-white/30'
|
||||
? 'ring-1 ring-inset ring-white/10 bg-gray-950/40 w-full rounded-lg outline-hidden px-4 py-2 text-white text-sm placeholder:text-white/30 opacity-30 '
|
||||
: 'ring-1 ring-inset ring-white/10 bg-gray-950/40 w-full rounded-lg outline-hidden px-4 py-2 text-white text-sm placeholder:text-white/30'
|
||||
|
||||
useEffect(() => {
|
||||
if (aiChatBotState.isModalOpen) {
|
||||
|
|
@ -211,7 +211,7 @@ function ActivityChatMessageBox(props: ActivityChatMessageBoxProps) {
|
|||
background:
|
||||
'linear-gradient(0deg, rgba(0, 0, 0, 0.2) 0%, rgba(0, 0, 0, 0.2) 100%), radial-gradient(105.16% 105.16% at 50% -5.16%, rgba(255, 255, 255, 0.18) 0%, rgba(0, 0, 0, 0) 100%), rgb(2 1 25 / 98%)',
|
||||
}}
|
||||
className="bg-black z-50 rounded-2xl max-w-screen-2xl w-10/12 my-10 mx-auto h-[350px] fixed bottom-0 left-1/2 transform -translate-x-1/2 shadow-lg ring-1 ring-inset ring-white/10 text-white p-4 flex-col-reverse backdrop-blur-md"
|
||||
className="bg-black z-50 rounded-2xl max-w-(--breakpoint-2xl) w-10/12 my-10 mx-auto h-[350px] fixed bottom-0 left-1/2 transform -translate-x-1/2 shadow-lg ring-1 ring-inset ring-white/10 text-white p-4 flex-col-reverse backdrop-blur-md"
|
||||
>
|
||||
<div className="flex flex-row-reverse pb-3 justify-between items-center">
|
||||
<div className="flex space-x-2 items-center">
|
||||
|
|
@ -348,7 +348,7 @@ function AIMessage(props: AIMessageProps) {
|
|||
</div>
|
||||
<div className="w-full">
|
||||
<p
|
||||
className="w-full rounded-lg outline-none px-2 py-1 text-white text-md placeholder:text-white/30"
|
||||
className="w-full rounded-lg outline-hidden px-2 py-1 text-white text-md placeholder:text-white/30"
|
||||
id=""
|
||||
>
|
||||
<AnimatePresence>
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ function AssignmentBoxUI({ type, view, currentPoints, maxPoints, saveFC, submitF
|
|||
{view === 'teacher' &&
|
||||
<div
|
||||
onClick={() => saveFC && saveFC()}
|
||||
className='flex px-2 py-1 cursor-pointer rounded-md space-x-2 items-center bg-gradient-to-bl text-emerald-700 bg-emerald-300/20 hover:bg-emerald-300/10 hover:outline-offset-4 active:outline-offset-1 linear transition-all outline-offset-2 outline-dashed outline-emerald-500/60'>
|
||||
className='flex px-2 py-1 cursor-pointer rounded-md space-x-2 items-center bg-linear-to-bl text-emerald-700 bg-emerald-300/20 hover:bg-emerald-300/10 hover:outline-offset-4 active:outline-offset-1 linear transition-all outline-offset-2 outline-dashed outline-emerald-500/60'>
|
||||
<Save size={14} />
|
||||
<p className='text-xs font-semibold'>Save</p>
|
||||
</div>
|
||||
|
|
@ -86,7 +86,7 @@ function AssignmentBoxUI({ type, view, currentPoints, maxPoints, saveFC, submitF
|
|||
{view === 'student' && isAuthenticated && submission && submission.length <= 0 &&
|
||||
<div
|
||||
onClick={() => submitFC && submitFC()}
|
||||
className='flex px-2 py-1 cursor-pointer rounded-md space-x-2 items-center justify-center mx-auto w-full sm:w-auto bg-gradient-to-bl text-emerald-700 bg-emerald-300/20 hover:bg-emerald-300/10 hover:outline-offset-4 active:outline-offset-1 linear transition-all outline-offset-2 outline-dashed outline-emerald-500/60'>
|
||||
className='flex px-2 py-1 cursor-pointer rounded-md space-x-2 items-center justify-center mx-auto w-full sm:w-auto bg-linear-to-bl text-emerald-700 bg-emerald-300/20 hover:bg-emerald-300/10 hover:outline-offset-4 active:outline-offset-1 linear transition-all outline-offset-2 outline-dashed outline-emerald-500/60'>
|
||||
<Forward size={14} />
|
||||
<p className='text-xs font-semibold'>Save your progress</p>
|
||||
</div>
|
||||
|
|
@ -95,11 +95,11 @@ function AssignmentBoxUI({ type, view, currentPoints, maxPoints, saveFC, submitF
|
|||
{/* Grading button */}
|
||||
{view === 'grading' &&
|
||||
<div
|
||||
className='flex flex-wrap sm:flex-nowrap w-full sm:w-auto px-0.5 py-0.5 cursor-pointer rounded-md gap-2 sm:space-x-2 items-center bg-gradient-to-bl hover:outline-offset-4 active:outline-offset-1 linear transition-all outline-offset-2 outline-dashed outline-orange-500/60'>
|
||||
className='flex flex-wrap sm:flex-nowrap w-full sm:w-auto px-0.5 py-0.5 cursor-pointer rounded-md gap-2 sm:space-x-2 items-center bg-linear-to-bl hover:outline-offset-4 active:outline-offset-1 linear transition-all outline-offset-2 outline-dashed outline-orange-500/60'>
|
||||
<p className='font-semibold px-2 text-xs text-orange-700'>Current points: {currentPoints}</p>
|
||||
<div
|
||||
onClick={() => gradeFC && gradeFC()}
|
||||
className='bg-gradient-to-bl text-orange-700 bg-orange-300/20 hover:bg-orange-300/10 items-center flex rounded-md px-2 py-1 space-x-2 ml-auto'>
|
||||
className='bg-linear-to-bl text-orange-700 bg-orange-300/20 hover:bg-orange-300/10 items-center flex rounded-md px-2 py-1 space-x-2 ml-auto'>
|
||||
<BookPlus size={14} />
|
||||
<p className='text-xs font-semibold'>Grade</p>
|
||||
</div>
|
||||
|
|
@ -109,7 +109,7 @@ function AssignmentBoxUI({ type, view, currentPoints, maxPoints, saveFC, submitF
|
|||
{/* CustomGrading button */}
|
||||
{view === 'custom-grading' && maxPoints &&
|
||||
<div
|
||||
className='flex flex-wrap sm:flex-nowrap w-full sm:w-auto px-0.5 py-0.5 cursor-pointer rounded-md gap-2 sm:space-x-2 items-center bg-gradient-to-bl hover:outline-offset-4 active:outline-offset-1 linear transition-all outline-offset-2 outline-dashed outline-orange-500/60'>
|
||||
className='flex flex-wrap sm:flex-nowrap w-full sm:w-auto px-0.5 py-0.5 cursor-pointer rounded-md gap-2 sm:space-x-2 items-center bg-linear-to-bl hover:outline-offset-4 active:outline-offset-1 linear transition-all outline-offset-2 outline-dashed outline-orange-500/60'>
|
||||
<p className='font-semibold px-2 text-xs text-orange-700 w-full sm:w-auto'>Current points: {currentPoints}</p>
|
||||
<div className='flex items-center gap-2 w-full sm:w-auto'>
|
||||
<input
|
||||
|
|
@ -120,7 +120,7 @@ function AssignmentBoxUI({ type, view, currentPoints, maxPoints, saveFC, submitF
|
|||
/>
|
||||
<div
|
||||
onClick={() => gradeCustomFC && gradeCustomFC(customGrade)}
|
||||
className='bg-gradient-to-bl text-orange-700 bg-orange-300/20 hover:bg-orange-300/10 items-center flex rounded-md px-2 py-1 space-x-2 whitespace-nowrap'>
|
||||
className='bg-linear-to-bl text-orange-700 bg-orange-300/20 hover:bg-orange-300/10 items-center flex rounded-md px-2 py-1 space-x-2 whitespace-nowrap'>
|
||||
<BookPlus size={14} />
|
||||
<p className='text-xs font-semibold'>Grade</p>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -21,16 +21,16 @@ function AssignmentStudentActivity() {
|
|||
<div className='flex flex-col space-y-4 md:space-y-6'>
|
||||
<div className='flex flex-col md:flex-row justify-center md:space-x-3 space-y-3 md:space-y-0 items-center'>
|
||||
<div className='text-xs h-fit flex space-x-3 items-center'>
|
||||
<div className='flex space-x-2 py-2 px-4 md:px-5 h-fit text-sm text-slate-700 bg-slate-100/5 rounded-full nice-shadow'>
|
||||
<Backpack size={16} className="md:size-18" />
|
||||
<div className='flex gap-2 py-2 px-4 md:px-5 h-fit text-sm text-slate-700 bg-slate-100/5 rounded-full nice-shadow items-center'>
|
||||
<Backpack size={14} className="md:size-[14px]" />
|
||||
<p className='font-semibold'>Assignment</p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className='flex space-x-2 items-center'>
|
||||
<div className='flex gap-2 items-center'>
|
||||
<EllipsisVertical className='text-slate-400 hidden md:block' size={18} />
|
||||
<div className='flex space-x-2 items-center'>
|
||||
<div className='flex space-x-1 md:space-x-2 text-xs items-center text-slate-400'>
|
||||
<div className='flex gap-2 items-center'>
|
||||
<div className='flex gap-1 md:space-x-2 text-xs items-center text-slate-400'>
|
||||
<Calendar size={14} />
|
||||
<p className='font-semibold'>Due Date</p>
|
||||
<p className='font-semibold'>{assignments?.assignment_object?.due_date}</p>
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ function VideoActivity({ activity, course }: { activity: any; course: any }) {
|
|||
<>
|
||||
{activity.activity_sub_type === 'SUBTYPE_VIDEO_HOSTED' && (
|
||||
<div className="my-3 md:my-5 w-full">
|
||||
<div className="relative w-full aspect-video rounded-lg overflow-hidden ring-1 ring-gray-300/30 dark:ring-gray-600/30 sm:ring-gray-200/10 sm:dark:ring-gray-700/20 shadow-sm sm:shadow-none">
|
||||
<div className="relative w-full aspect-video rounded-lg overflow-hidden ring-1 ring-gray-300/30 dark:ring-gray-600/30 sm:ring-gray-200/10 sm:dark:ring-gray-700/20 shadow-xs sm:shadow-none">
|
||||
<video
|
||||
className="w-full h-full object-cover"
|
||||
controls
|
||||
|
|
@ -37,7 +37,7 @@ function VideoActivity({ activity, course }: { activity: any; course: any }) {
|
|||
)}
|
||||
{activity.activity_sub_type === 'SUBTYPE_VIDEO_YOUTUBE' && (
|
||||
<div className="my-3 md:my-5 w-full">
|
||||
<div className="relative w-full aspect-video rounded-lg overflow-hidden ring-1 ring-gray-300/30 dark:ring-gray-600/30 sm:ring-gray-200/10 sm:dark:ring-gray-700/20 shadow-sm sm:shadow-none">
|
||||
<div className="relative w-full aspect-video rounded-lg overflow-hidden ring-1 ring-gray-300/30 dark:ring-gray-600/30 sm:ring-gray-200/10 sm:dark:ring-gray-700/20 shadow-xs sm:shadow-none">
|
||||
<YouTube
|
||||
className="w-full h-full"
|
||||
opts={{
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ const CourseActionsMobile = ({ courseuuid, orgslug, course }: CourseActionsMobil
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex-shrink-0">
|
||||
<div className="shrink-0">
|
||||
{linkedProducts.length > 0 ? (
|
||||
hasAccess ? (
|
||||
<button
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ function CoursePaidOptions({ course }: CoursePaidOptionsProps) {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex-grow overflow-hidden">
|
||||
<div className="grow overflow-hidden">
|
||||
<div className={`transition-all duration-300 ease-in-out ${expandedProducts[product.id] ? 'max-h-[1000px]' : 'max-h-24'
|
||||
} overflow-hidden`}>
|
||||
<p className="text-gray-600">
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ function AIEditorToolkit(props: AIEditorToolkitProps) {
|
|||
background:
|
||||
'linear-gradient(0deg, rgba(0, 0, 0, 0.2) 0%, rgba(0, 0, 0, 0.2) 100%), radial-gradient(105.16% 105.16% at 50% -5.16%, rgba(255, 255, 255, 0.18) 0%, rgba(0, 0, 0, 0) 100%), rgb(2 1 25 / 98%)',
|
||||
}}
|
||||
className="z-50 rounded-2xl max-w-screen-2xl my-10 mx-auto w-fit fixed bottom-0 left-1/2 transform -translate-x-1/2 shadow-xl ring-1 ring-inset ring-white/10 text-white p-3 flex-col-reverse backdrop-blur-md"
|
||||
className="z-50 rounded-2xl max-w-(--breakpoint-2xl) my-10 mx-auto w-fit fixed bottom-0 left-1/2 transform -translate-x-1/2 shadow-xl ring-1 ring-inset ring-white/10 text-white p-3 flex-col-reverse backdrop-blur-md"
|
||||
>
|
||||
<div className="flex space-x-2">
|
||||
<div className="pr-1">
|
||||
|
|
@ -447,7 +447,7 @@ const UserFeedbackModal = (props: AIEditorToolkitProps) => {
|
|||
background:
|
||||
'linear-gradient(0deg, rgba(0, 0, 0, 0.2) 0%, rgba(0, 0, 0, 0.2) 100%), radial-gradient(105.16% 105.16% at 50% -5.16%, rgba(255, 255, 255, 0.18) 0%, rgba(0, 0, 0, 0) 100%), rgb(2 1 25 / 95%)',
|
||||
}}
|
||||
className="backdrop-blur-md z-50 rounded-2xl max-w-screen-2xl my-10 mx-auto w-[500px] h-[200px] fixed bottom-16 left-1/2 transform -translate-x-1/2 shadow-xl ring-1 ring-inset ring-white/10 text-white p-3 flex-col-reverse"
|
||||
className="backdrop-blur-md z-50 rounded-2xl max-w-(--breakpoint-2xl) my-10 mx-auto w-[500px] h-[200px] fixed bottom-16 left-1/2 transform -translate-x-1/2 shadow-xl ring-1 ring-inset ring-white/10 text-white p-3 flex-col-reverse"
|
||||
>
|
||||
<div className="flex space-x-2 justify-center">
|
||||
<Image
|
||||
|
|
@ -469,7 +469,7 @@ const UserFeedbackModal = (props: AIEditorToolkitProps) => {
|
|||
value={aiEditorState.chatInputValue}
|
||||
onChange={handleChange}
|
||||
placeholder="Ask AI"
|
||||
className="ring-1 ring-inset ring-white/20 w-full bg-gray-950/20 rounded-lg outline-none px-4 py-2 text-white text-sm placeholder:text-white/30"
|
||||
className="ring-1 ring-inset ring-white/20 w-full bg-gray-950/20 rounded-lg outline-hidden px-4 py-2 text-white text-sm placeholder:text-white/30"
|
||||
></input>
|
||||
<div
|
||||
onClick={() =>
|
||||
|
|
@ -620,7 +620,7 @@ const AiEditorActionScreen = ({
|
|||
value={aiEditorState.chatInputValue}
|
||||
onChange={handleChange}
|
||||
placeholder="Japanese, Arabic, German, etc. "
|
||||
className="ring-1 ring-inset ring-white/20 w-full bg-gray-950/20 rounded-lg outline-none px-4 py- text-white text-sm placeholder:text-white/30"
|
||||
className="ring-1 ring-inset ring-white/20 w-full bg-gray-950/20 rounded-lg outline-hidden px-4 py- text-white text-sm placeholder:text-white/30"
|
||||
></input>
|
||||
</div>
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ function Editor(props: Editor) {
|
|||
}}
|
||||
exit={{ opacity: 0 }}
|
||||
>
|
||||
<EditorTop className="fixed bg-white bg-opacity-95 backdrop-blur backdrop-brightness-125">
|
||||
<EditorTop className="fixed bg-white bg-opacity-95 backdrop-blur-sm backdrop-brightness-125">
|
||||
<EditorDocSection>
|
||||
<EditorInfoWrapper>
|
||||
<Link href="/">
|
||||
|
|
@ -254,7 +254,7 @@ function Editor(props: Editor) {
|
|||
/>
|
||||
<EditorLeftOptionsSection className="space-x-2 ">
|
||||
<div
|
||||
className="bg-sky-600 hover:bg-sky-700 transition-all ease-linear px-3 py-2 font-black text-sm shadow text-teal-100 rounded-lg hover:cursor-pointer"
|
||||
className="bg-sky-600 hover:bg-sky-700 transition-all ease-linear px-3 py-2 font-black text-sm shadow-sm text-teal-100 rounded-lg hover:cursor-pointer"
|
||||
onClick={() => props.setContent(editor.getJSON())}
|
||||
>
|
||||
{' '}
|
||||
|
|
@ -265,7 +265,7 @@ function Editor(props: Editor) {
|
|||
target="_blank"
|
||||
href={`/course/${course_uuid}/activity/${activity_uuid}`}
|
||||
>
|
||||
<div className="flex bg-neutral-600 hover:bg-neutral-700 transition-all ease-linear h-9 px-3 py-2 font-black justify-center items-center text-sm shadow text-neutral-100 rounded-lg hover:cursor-pointer">
|
||||
<div className="flex bg-neutral-600 hover:bg-neutral-700 transition-all ease-linear h-9 px-3 py-2 font-black justify-center items-center text-sm shadow-sm text-neutral-100 rounded-lg hover:cursor-pointer">
|
||||
<Eye className="mx-auto items-center" size={15} />
|
||||
</div>
|
||||
</Link>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
'use client'
|
||||
import { default as React } from 'react'
|
||||
import { default as React, type JSX } from 'react';
|
||||
import Editor from './Editor'
|
||||
import { updateActivity } from '@services/courses/activities'
|
||||
import { toast } from 'react-hot-toast'
|
||||
|
|
@ -7,8 +7,6 @@ import Toast from '@components/Objects/StyledElements/Toast/Toast'
|
|||
import { OrgProvider } from '@components/Contexts/OrgContext'
|
||||
import { useLHSession } from '@components/Contexts/LHSessionContext'
|
||||
|
||||
|
||||
|
||||
interface EditorWrapperProps {
|
||||
content: string
|
||||
activity: any
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ const BadgesExtension: React.FC = (props: any) => {
|
|||
{colors.map((c) => (
|
||||
<button
|
||||
key={c}
|
||||
className={`w-8 h-8 rounded-full ${getBadgeColor(c)} hover:ring-2 hover:ring-opacity-50 focus:outline-none focus:ring-2 focus:ring-opacity-50`}
|
||||
className={`w-8 h-8 rounded-full ${getBadgeColor(c)} hover:ring-2 hover:ring-opacity-50 focus:outline-hidden focus:ring-2 focus:ring-opacity-50`}
|
||||
onClick={() => handleColorSelect(c)}
|
||||
/>
|
||||
))}
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ const ButtonsExtension: React.FC = (props: any) => {
|
|||
{colors.map((c) => (
|
||||
<button
|
||||
key={c}
|
||||
className={`w-6 h-6 rounded-full ${getButtonColor(c)} hover:ring-2 hover:ring-opacity-50 focus:outline-none focus:ring-2 focus:ring-opacity-50`}
|
||||
className={`w-6 h-6 rounded-full ${getButtonColor(c)} hover:ring-2 hover:ring-opacity-50 focus:outline-hidden focus:ring-2 focus:ring-opacity-50`}
|
||||
onClick={() => handleColorSelect(c)}
|
||||
/>
|
||||
))}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ const IconWrapper = styled.div<{ size?: string }>`
|
|||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
shrink: 0;
|
||||
margin-right: 0.5rem;
|
||||
padding-left: 0.5rem;
|
||||
|
||||
|
|
@ -126,7 +126,7 @@ function InfoCalloutComponent(props: any) {
|
|||
<IconWrapper size={options.size}>
|
||||
<AlertCircle />
|
||||
</IconWrapper>
|
||||
<ContentWrapper className="flex-grow">
|
||||
<ContentWrapper className="grow">
|
||||
<NodeViewContent contentEditable={isEditable} className="content" />
|
||||
</ContentWrapper>
|
||||
{options.dismissible && !isEditable && (
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ const IconWrapper = styled.div<{ size?: string }>`
|
|||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
shrink: 0;
|
||||
margin-right: 0.5rem;
|
||||
padding-left: 0.5rem;
|
||||
|
||||
|
|
@ -126,7 +126,7 @@ function WarningCalloutComponent(props: any) {
|
|||
<IconWrapper size={options.size}>
|
||||
<AlertTriangle />
|
||||
</IconWrapper>
|
||||
<ContentWrapper className="flex-grow">
|
||||
<ContentWrapper className="grow">
|
||||
<NodeViewContent contentEditable={isEditable} className="content" />
|
||||
</ContentWrapper>
|
||||
{options.dismissible && !isEditable && (
|
||||
|
|
|
|||
|
|
@ -417,7 +417,7 @@ function EmbedObjectsComponent(props: any) {
|
|||
|
||||
{/* Minimal toolbar for existing embeds */}
|
||||
{isEditable && (
|
||||
<div className="absolute top-2 right-2 flex items-center gap-1.5 bg-white bg-opacity-90 backdrop-blur-sm rounded-lg p-1 shadow-sm transition-opacity opacity-70 hover:opacity-100">
|
||||
<div className="absolute top-2 right-2 flex items-center gap-1.5 bg-white bg-opacity-90 backdrop-blur-xs rounded-lg p-1 shadow-xs transition-opacity opacity-70 hover:opacity-100">
|
||||
<button
|
||||
onClick={() => setActiveInput(embedType)}
|
||||
className="p-1.5 rounded-md hover:bg-gray-100 text-gray-600"
|
||||
|
|
@ -487,7 +487,7 @@ function EmbedObjectsComponent(props: any) {
|
|||
setEmbedType('url');
|
||||
setActiveInput('url');
|
||||
}}
|
||||
className="flex items-center gap-1.5 px-3 py-1.5 bg-white rounded-lg shadow-sm hover:shadow-md transition-all text-sm text-gray-700"
|
||||
className="flex items-center gap-1.5 px-3 py-1.5 bg-white rounded-lg shadow-xs hover:shadow-md transition-all text-sm text-gray-700"
|
||||
>
|
||||
<LinkIcon size={14} />
|
||||
<span>URL</span>
|
||||
|
|
@ -497,7 +497,7 @@ function EmbedObjectsComponent(props: any) {
|
|||
setEmbedType('code');
|
||||
setActiveInput('code');
|
||||
}}
|
||||
className="flex items-center gap-1.5 px-3 py-1.5 bg-white rounded-lg shadow-sm hover:shadow-md transition-all text-sm text-gray-700"
|
||||
className="flex items-center gap-1.5 px-3 py-1.5 bg-white rounded-lg shadow-xs hover:shadow-md transition-all text-sm text-gray-700"
|
||||
>
|
||||
<Code size={14} />
|
||||
<span>Code</span>
|
||||
|
|
@ -509,7 +509,7 @@ function EmbedObjectsComponent(props: any) {
|
|||
|
||||
{/* Inline input UI - appears in place without covering content */}
|
||||
{isEditable && activeInput !== 'none' && (
|
||||
<div className="absolute inset-0 bg-gray-100 bg-opacity-95 backdrop-blur-sm flex items-center justify-center p-4 z-10">
|
||||
<div className="absolute inset-0 bg-gray-100 bg-opacity-95 backdrop-blur-xs flex items-center justify-center p-4 z-10">
|
||||
<form
|
||||
onSubmit={handleInputSubmit}
|
||||
className="w-full max-w-lg bg-white rounded-xl shadow-lg p-4"
|
||||
|
|
@ -554,7 +554,7 @@ function EmbedObjectsComponent(props: any) {
|
|||
type="text"
|
||||
value={embedUrl}
|
||||
onChange={handleUrlChange}
|
||||
className="w-full pl-10 pr-4 py-2.5 bg-gray-50 border border-gray-200 rounded-xl focus:ring-2 focus:ring-blue-500 focus:border-blue-500 focus:outline-none transition-all"
|
||||
className="w-full pl-10 pr-4 py-2.5 bg-gray-50 border border-gray-200 rounded-xl focus:ring-2 focus:ring-blue-500 focus:border-blue-500 focus:outline-hidden transition-all"
|
||||
placeholder={selectedProduct ? `Paste ${selectedProduct.name} embed URL` : "Paste embed URL (YouTube, Spotify, etc.)"}
|
||||
autoFocus
|
||||
/>
|
||||
|
|
@ -586,7 +586,7 @@ function EmbedObjectsComponent(props: any) {
|
|||
ref={codeInputRef}
|
||||
value={embedCode}
|
||||
onChange={handleCodeChange}
|
||||
className="w-full p-3 bg-gray-50 border border-gray-200 rounded-xl h-32 focus:ring-2 focus:ring-blue-500 focus:border-blue-500 focus:outline-none transition-all font-mono text-sm"
|
||||
className="w-full p-3 bg-gray-50 border border-gray-200 rounded-xl h-32 focus:ring-2 focus:ring-blue-500 focus:border-blue-500 focus:outline-hidden transition-all font-mono text-sm"
|
||||
placeholder="Paste embed code (iframe, embed script, etc.)"
|
||||
autoFocus
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ function ImageBlockComponent(props: any) {
|
|||
'imageBlock'
|
||||
)}`}
|
||||
alt=""
|
||||
className="rounded-lg shadow max-w-full h-auto"
|
||||
className="rounded-lg shadow-sm max-w-full h-auto"
|
||||
style={{ width: '100%' }}
|
||||
/>
|
||||
</Resizable>
|
||||
|
|
@ -129,7 +129,7 @@ function ImageBlockComponent(props: any) {
|
|||
'imageBlock'
|
||||
)}`}
|
||||
alt=""
|
||||
className="rounded-lg shadow max-w-full h-auto"
|
||||
className="rounded-lg shadow-sm max-w-full h-auto"
|
||||
style={{ width: imageSize.width, maxWidth: '100%' }}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ function PDFBlockComponent(props: any) {
|
|||
{blockObject && (
|
||||
<BlockPDF>
|
||||
<iframe
|
||||
className="shadow rounded-lg h-96 w-full object-scale-down bg-black"
|
||||
className="shadow-sm rounded-lg h-96 w-full object-scale-down bg-black"
|
||||
src={`${getActivityBlockMediaDirectory(
|
||||
org?.org_uuid,
|
||||
course?.courseStructure.course_uuid,
|
||||
|
|
|
|||
|
|
@ -275,7 +275,7 @@ function QuizBlockComponent(props: any) {
|
|||
<div key={question.question_id} className="pt-3 space-y-2">
|
||||
<div className="question">
|
||||
<div className="flex space-x-2 items-center">
|
||||
<div className="flex-grow">
|
||||
<div className="grow">
|
||||
{isEditable ? (
|
||||
<input
|
||||
value={question.question}
|
||||
|
|
@ -310,7 +310,7 @@ function QuizBlockComponent(props: any) {
|
|||
<div
|
||||
key={answer.answer_id}
|
||||
className={twMerge(
|
||||
'outline outline-2 pr-2 shadow w-full flex items-stretch space-x-2 min-h-[36px] bg-opacity-50 hover:bg-opacity-100 hover:shadow-md rounded-lg bg-white text-sm duration-150 cursor-pointer ease-linear',
|
||||
'outline outline-2 pr-2 shadow-sm w-full flex items-stretch space-x-2 min-h-[36px] bg-opacity-50 hover:bg-opacity-100 hover:shadow-md rounded-lg bg-white text-sm duration-150 cursor-pointer ease-linear',
|
||||
answer.correct && isEditable ? 'outline-lime-300' : 'outline-white',
|
||||
userAnswers.some(
|
||||
(userAnswer: any) =>
|
||||
|
|
@ -335,16 +335,16 @@ function QuizBlockComponent(props: any) {
|
|||
className={twMerge(
|
||||
'font-bold text-base flex items-center justify-center self-stretch w-[40px] rounded-l-md text-slate-800 bg-white',
|
||||
answer.correct && isEditable
|
||||
? 'bg-lime-300 text-lime-800 outline-none'
|
||||
? 'bg-lime-300 text-lime-800 outline-hidden'
|
||||
: 'bg-white',
|
||||
userAnswers.some(
|
||||
(userAnswer: any) =>
|
||||
userAnswer.question_id === question.question_id &&
|
||||
userAnswer.answer_id === answer.answer_id &&
|
||||
!isEditable && !submitted
|
||||
) ? 'bg-blue-400 text-white outline-none' : '',
|
||||
) ? 'bg-blue-400 text-white outline-hidden' : '',
|
||||
submitted && answer.correct
|
||||
? 'bg-lime-300 text-lime-800 outline-none'
|
||||
? 'bg-lime-300 text-lime-800 outline-hidden'
|
||||
: '',
|
||||
submitted &&
|
||||
!answer.correct &&
|
||||
|
|
@ -353,7 +353,7 @@ function QuizBlockComponent(props: any) {
|
|||
userAnswer.question_id === question.question_id &&
|
||||
userAnswer.answer_id === answer.answer_id
|
||||
)
|
||||
? 'bg-red-400 text-red-800 outline-none'
|
||||
? 'bg-red-400 text-red-800 outline-hidden'
|
||||
: ''
|
||||
)}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ function VideoBlockComponents(props: any) {
|
|||
<BlockVideo>
|
||||
<video
|
||||
controls
|
||||
className="rounded-lg shadow h-96 w-full object-scale-down bg-black"
|
||||
className="rounded-lg shadow-sm h-96 w-full object-scale-down bg-black"
|
||||
src={`${getActivityBlockMediaDirectory(
|
||||
org?.org_uuid,
|
||||
course?.courseStructure.course_uuid,
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ export const OrgMenu = (props: any) => {
|
|||
<>
|
||||
<div className="backdrop-blur-lg h-[60px] blur-3xl -z-10"></div>
|
||||
<div className="backdrop-blur-lg bg-white/90 fixed top-0 left-0 right-0 h-[60px] ring-1 ring-inset ring-gray-500/10 shadow-[0px_4px_16px_rgba(0,0,0,0.03)] z-50">
|
||||
<div className="flex items-center justify-between w-full max-w-screen-2xl mx-auto px-4 sm:px-6 lg:px-16 h-full">
|
||||
<div className="flex items-center justify-between w-full max-w-(--breakpoint-2xl) mx-auto px-4 sm:px-6 lg:px-16 h-full">
|
||||
<div className="flex items-center space-x-5 md:w-auto w-full">
|
||||
<div className="logo flex md:w-auto w-full justify-center">
|
||||
<Link href={getUriWithOrg(orgslug, '/')}>
|
||||
|
|
@ -63,7 +63,7 @@ export const OrgMenu = (props: any) => {
|
|||
<HeaderProfileBox />
|
||||
</div>
|
||||
<button
|
||||
className="md:hidden text-gray-600 focus:outline-none"
|
||||
className="md:hidden text-gray-600 focus:outline-hidden"
|
||||
onClick={toggleMenu}
|
||||
>
|
||||
{isMenuOpen ? (
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ function NewActivityModal({
|
|||
return (
|
||||
<>
|
||||
{selectedView === 'home' && (
|
||||
<div className="flex flex-row space-x-2 justify-start mt-2.5 w-full">
|
||||
<div className="grid grid-cols-4 gap-2 mt-2.5 w-full">
|
||||
<ActivityOption
|
||||
onClick={() => {
|
||||
setSelectedView('dynamic')
|
||||
|
|
|
|||
|
|
@ -158,18 +158,18 @@ function CreateCourseModal({ closeModal, orgslug }: any) {
|
|||
label="Course Thumbnail"
|
||||
message={formik.errors.thumbnail}
|
||||
/>
|
||||
<div className="w-auto bg-gray-50 rounded-xl outline outline-1 outline-gray-200 h-[200px] shadow">
|
||||
<div className="w-auto bg-gray-50 rounded-xl outline outline-1 outline-gray-200 h-[200px] shadow-sm">
|
||||
<div className="flex flex-col justify-center items-center h-full">
|
||||
<div className="flex flex-col justify-center items-center">
|
||||
{formik.values.thumbnail ? (
|
||||
<img
|
||||
src={URL.createObjectURL(formik.values.thumbnail)}
|
||||
className={`${isUploading ? 'animate-pulse' : ''} shadow w-[200px] h-[100px] rounded-md`}
|
||||
className={`${isUploading ? 'animate-pulse' : ''} shadow-sm w-[200px] h-[100px] rounded-md`}
|
||||
/>
|
||||
) : (
|
||||
<img
|
||||
src="/empty_thumbnail.png"
|
||||
className="shadow w-[200px] h-[100px] rounded-md bg-gray-200"
|
||||
className="shadow-sm w-[200px] h-[100px] rounded-md bg-gray-200"
|
||||
/>
|
||||
)}
|
||||
<div className="flex justify-center items-center space-x-2">
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ function LinkToUserGroup(props: LinkToUserGroupProps) {
|
|||
<Link className='px-3 text-blue-700 font-bold rounded-full py-1 bg-blue-100 mx-1' target='_blank' href={getUriWithOrg(org.slug, '/dash/users/settings/usergroups')}>Create a UserGroup</Link>
|
||||
</div>}
|
||||
<div className='py-3'>
|
||||
<button onClick={() => { handleLink() }} className='bg-green-700 text-white font-bold px-4 py-2 rounded-md shadow'>Link</button>
|
||||
<button onClick={() => { handleLink() }} className='bg-green-700 text-white font-bold px-4 py-2 rounded-md shadow-sm'>Link</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -253,7 +253,7 @@ const Onboarding: React.FC = () => {
|
|||
/>
|
||||
}
|
||||
dialogTrigger={
|
||||
<div className='fixed pb-10 w-full bottom-0 bg-gradient-to-t from-1% from-gray-950/25 to-transparent'>
|
||||
<div className='fixed pb-10 w-full bottom-0 bg-linear-to-t from-1% from-gray-950/25 to-transparent'>
|
||||
<div className='bg-gray-950 flex space-x-2 font-bold cursor-pointer hover:bg-gray-900 shadow-md items-center text-gray-200 px-5 py-2 w-fit rounded-full mx-auto'>
|
||||
<Sprout size={20} />
|
||||
<p>Onboarding</p>
|
||||
|
|
@ -299,7 +299,7 @@ const OnboardingScreen: React.FC<OnboardingScreenProps> = ({
|
|||
return (
|
||||
<div className='flex flex-col'>
|
||||
<div className='onboarding_screens flex-col px-4 py-4'>
|
||||
<div className='flex-grow rounded-xl'>
|
||||
<div className='grow rounded-xl'>
|
||||
<Image
|
||||
unoptimized
|
||||
className='mx-auto shadow-md shadow-gray-200 rounded-lg w-[730px] h-[330px] object-cover'
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ export const SearchBar: React.FC<SearchBarProps> = ({ orgslug, className = '', i
|
|||
}}
|
||||
onFocus={handleSearchFocus}
|
||||
placeholder="Search courses..."
|
||||
className="w-full h-9 pl-10 pr-4 rounded-lg border border-gray-200 bg-white/50 focus:outline-none focus:ring-2 focus:ring-gray-200 focus:border-transparent text-sm placeholder:text-gray-400"
|
||||
className="w-full h-9 pl-10 pr-4 rounded-lg border border-gray-200 bg-white/50 focus:outline-hidden focus:ring-2 focus:ring-gray-200 focus:border-transparent text-sm placeholder:text-gray-400"
|
||||
/>
|
||||
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400" size={18} />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ const ConfirmationModal = (params: ModalParams) => {
|
|||
<Info size={35} />
|
||||
)}
|
||||
</div>
|
||||
<div className="text pt-1 space-x-0 w-auto flex-grow">
|
||||
<div className="text pt-1 space-x-0 w-auto grow">
|
||||
<div className="text-xl font-bold text-black ">
|
||||
{params.dialogTitle}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ function ErrorUI(params: { message?: string, submessage?: string }) {
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col py-10 mx-auto antialiased items-center space-y-6 bg-gradient-to-b from-rose-100 to-rose-100/5 ">
|
||||
<div className="flex flex-col py-10 mx-auto antialiased items-center space-y-6 bg-linear-to-b from-rose-100 to-rose-100/5 ">
|
||||
<div className="flex flex-row items-center space-x-5 rounded-xl ">
|
||||
<AlertTriangle className="text-rose-700" size={45} />
|
||||
<div className='flex flex-col'>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { styled } from '@stitches/react'
|
|||
import { blackA } from '@radix-ui/colors'
|
||||
import { Info } from 'lucide-react'
|
||||
|
||||
const FormLayout = (props: any, onSubmit: any) => (
|
||||
const FormLayout: React.FC<{ children: React.ReactNode; onSubmit: (e: any) => void }> = (props) => (
|
||||
<FormRoot className="h-fit" onSubmit={props.onSubmit}>
|
||||
{props.children}
|
||||
</FormRoot>
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ const FormTagInput = ({
|
|||
placeholder={placeholder}
|
||||
styleClasses={{
|
||||
inlineTagsContainer:
|
||||
'border-input rounded-lg bg-background shadow-xs transition-shadow focus-within:border-ring/40 focus-within:outline-hidden focus-within:ring-[3px] ring-ring/8 dark:ring-ring/12 p-1 gap-1',
|
||||
'border-input rounded-lg bg-background shadow-2xs transition-shadow focus-within:border-ring/40 focus-within:outline-hidden focus-within:ring-[3px] ring-ring/8 dark:ring-ring/12 p-1 gap-1',
|
||||
input:
|
||||
'w-full min-w-[80px] focus-visible:outline-hidden shadow-none px-2 h-7',
|
||||
tag: {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import React from 'react'
|
|||
|
||||
function InfoUI(params: { message?: string, submessage?: string, cta?: string, href: string }) {
|
||||
return (
|
||||
<div className="flex flex-col py-10 mx-auto antialiased items-center space-y-6 bg-gradient-to-b from-yellow-100 to-yellow-100/5 ">
|
||||
<div className="flex flex-col py-10 mx-auto antialiased items-center space-y-6 bg-linear-to-b from-yellow-100 to-yellow-100/5 ">
|
||||
<div className="flex flex-row items-center space-x-5 rounded-xl ">
|
||||
<Diamond className="text-yellow-700" size={45} />
|
||||
<div className='flex flex-col'>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
function GeneralWrapperStyled({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<div className="max-w-screen-2xl mx-auto px-4 sm:px-6 lg:px-8 py-5 tracking-tight z-50">
|
||||
<div className="max-w-(--breakpoint-2xl) mx-auto px-4 sm:px-6 lg:px-8 py-5 tracking-tight z-50">
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ const CourseThumbnailLanding: React.FC<PropsType> = ({ course, orgslug, customLi
|
|||
: '../empty_thumbnail.png'
|
||||
|
||||
return (
|
||||
<div className="relative flex flex-col bg-white rounded-xl nice-shadow overflow-hidden min-w-[280px] w-full max-w-sm flex-shrink-0 m-2">
|
||||
<div className="relative flex flex-col bg-white rounded-xl nice-shadow overflow-hidden min-w-[280px] w-full max-w-sm shrink-0 m-2">
|
||||
<AdminEditOptions
|
||||
course={course}
|
||||
orgslug={orgslug}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react'
|
||||
import Link from 'next/link'
|
||||
import { Draggable } from 'react-beautiful-dnd'
|
||||
import { Draggable } from '@hello-pangea/dnd'
|
||||
import { getAPIUrl, getUriWithOrg } from '@services/config/config'
|
||||
import {
|
||||
Video,
|
||||
|
|
@ -67,7 +67,7 @@ function Activity(props: any) {
|
|||
>
|
||||
{(provided) => (
|
||||
<div
|
||||
className="flex flex-row py-2 my-2 rounded-md bg-gray-50 text-gray-500 hover:bg-gray-100 hover:scale-102 hover:shadow space-x-1 w-auto items-center ring-1 ring-inset ring-gray-400/10 shadow-sm transition-all delay-100 duration-75 ease-linear"
|
||||
className="flex flex-row py-2 my-2 rounded-md bg-gray-50 text-gray-500 hover:bg-gray-100 hover:scale-102 hover:shadow-sm space-x-1 w-auto items-center ring-1 ring-inset ring-gray-400/10 shadow-xs transition-all delay-100 duration-75 ease-linear"
|
||||
key={props.activity.id}
|
||||
{...provided.draggableProps}
|
||||
{...provided.dragHandleProps}
|
||||
|
|
@ -113,7 +113,7 @@ function Activity(props: any) {
|
|||
<div className="chapter-modification-zone text-[7px] text-gray-600 shadow-inner bg-gray-200/60 py-1 px-4 rounded-lg space-x-3">
|
||||
<input
|
||||
type="text"
|
||||
className="bg-transparent outline-none text-xs text-gray-500"
|
||||
className="bg-transparent outline-hidden text-xs text-gray-500"
|
||||
placeholder="Activity name"
|
||||
value={
|
||||
modifiedActivity
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react'
|
||||
import styled from 'styled-components'
|
||||
import { Droppable, Draggable } from 'react-beautiful-dnd'
|
||||
import { Droppable, Draggable } from '@hello-pangea/dnd'
|
||||
import Activity from './Activity'
|
||||
import { Hexagon, MoreVertical, Pencil, Save, Sparkles, X } from 'lucide-react'
|
||||
import ConfirmationModal from '@components/Objects/StyledElements/ConfirmationModal/ConfirmationModal'
|
||||
|
|
@ -51,7 +51,7 @@ function Chapter(props: any) {
|
|||
{...provided.draggableProps}
|
||||
ref={provided.innerRef}
|
||||
// isDragging={snapshot.isDragging}
|
||||
className="max-w-screen-2xl mx-auto bg-white px-5"
|
||||
className="max-w-(--breakpoint-2xl) mx-auto bg-white px-5"
|
||||
key={props.info.list.chapter.id}
|
||||
>
|
||||
<div className="flex pt-3 pr-3 font-bold text-md items-center space-x-2">
|
||||
|
|
@ -69,7 +69,7 @@ function Chapter(props: any) {
|
|||
<div className="chapter-modification-zone bg-neutral-100 py-1 px-4 rounded-lg space-x-3">
|
||||
<input
|
||||
type="text"
|
||||
className="bg-transparent outline-none text-sm text-neutral-700"
|
||||
className="bg-transparent outline-hidden text-sm text-neutral-700"
|
||||
placeholder="Chapter name"
|
||||
value={
|
||||
modifiedChapter
|
||||
|
|
@ -116,7 +116,7 @@ function Chapter(props: any) {
|
|||
dialogTitle={'Delete ' + props.info.list.chapter.name + ' ?'}
|
||||
dialogTrigger={
|
||||
<div
|
||||
className=" hover:cursor-pointer p-1 px-4 bg-red-600 rounded-md shadow flex space-x-1 items-center text-rose-100 text-sm"
|
||||
className=" hover:cursor-pointer p-1 px-4 bg-red-600 rounded-md shadow-sm flex space-x-1 items-center text-rose-100 text-sm"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<X size={15} className="text-rose-200 font-bold" />
|
||||
|
|
@ -157,7 +157,7 @@ function Chapter(props: any) {
|
|||
onClick={() => {
|
||||
props.openNewActivityModal(props.info.list.chapter.id)
|
||||
}}
|
||||
className="flex space-x-2 items-center py-2 my-3 rounded-md justify-center text-white bg-black hover:cursor-pointer"
|
||||
className="flex space-x-2 items-center py-5 my-3 rounded-md justify-center text-white bg-black hover:cursor-pointer"
|
||||
>
|
||||
<Sparkles className="" size={17} />
|
||||
<div className="text-sm mx-auto my-auto items-center font-bold">
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ function TrailCourseElement(props: TrailCourseElementProps) {
|
|||
}}
|
||||
></div>
|
||||
</Link>
|
||||
<div className="course_meta pl-5 flex-grow space-y-1">
|
||||
<div className="course_meta pl-5 grow space-y-1">
|
||||
<div className="course_top">
|
||||
<div className="course_info flex">
|
||||
<div className="course_basic flex flex-col flex-end -space-y-2">
|
||||
|
|
@ -72,7 +72,7 @@ function TrailCourseElement(props: TrailCourseElementProps) {
|
|||
<h2>{course_progress}%</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div className="course_actions flex-grow flex flex-row-reverse">
|
||||
<div className="course_actions grow flex flex-row-reverse">
|
||||
<button
|
||||
onClick={() => quitCourse(course.course_uuid)}
|
||||
className="bg-red-200 text-red-700 hover:bg-red-300 rounded-full text-xs h-5 px-2 font-bold"
|
||||
|
|
|
|||
|
|
@ -89,5 +89,5 @@ const ProfileArea = styled.div`
|
|||
const UnidentifiedArea = styled.div`
|
||||
display: flex;
|
||||
place-items: stretch;
|
||||
flex-grow: 1;
|
||||
grow: 1;
|
||||
`
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ export default function StyledComponentsRegistry({
|
|||
|
||||
return (
|
||||
<StyleSheetManager sheet={styledComponentsStyleSheet.instance}>
|
||||
{children as React.ReactChild}
|
||||
{children as React.ReactElement<any> | number | string}
|
||||
</StyleSheetManager>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,16 +4,16 @@ import { cva, type VariantProps } from "class-variance-authority"
|
|||
import { cn } from "@/lib/utils"
|
||||
|
||||
const badgeVariants = cva(
|
||||
"inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
||||
"inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default:
|
||||
"border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80",
|
||||
"border-transparent bg-primary text-primary-foreground shadow-sm hover:bg-primary/80",
|
||||
secondary:
|
||||
"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
||||
destructive:
|
||||
"border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80",
|
||||
"border-transparent bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/80",
|
||||
outline: "text-foreground",
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -5,18 +5,18 @@ import { cva, type VariantProps } from "class-variance-authority"
|
|||
import { cn } from "@/lib/utils"
|
||||
|
||||
const buttonVariants = cva(
|
||||
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
||||
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default:
|
||||
"bg-primary text-primary-foreground shadow hover:bg-primary/90",
|
||||
"bg-primary text-primary-foreground shadow-sm hover:bg-primary/90",
|
||||
destructive:
|
||||
"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
|
||||
"bg-destructive text-destructive-foreground shadow-xs hover:bg-destructive/90",
|
||||
outline:
|
||||
"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
|
||||
"border border-input bg-background shadow-xs hover:bg-accent hover:text-accent-foreground",
|
||||
secondary:
|
||||
"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
|
||||
"bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
|
||||
ghost: "hover:bg-accent hover:text-accent-foreground",
|
||||
link: "text-primary underline-offset-4 hover:underline",
|
||||
},
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ const DialogOverlay = React.forwardRef<
|
|||
<DialogPrimitive.Overlay
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"fixed inset-0 z-50 bg-black/50 backdrop-blur-[1px] data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
||||
"fixed inset-0 z-50 bg-black/50 backdrop-blur-[1px] data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
|
|
@ -38,13 +38,14 @@ const DialogContent = React.forwardRef<
|
|||
<DialogPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-5 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-2xl",
|
||||
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 sm:rounded-2xl",
|
||||
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
|
||||
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
|
||||
<Cross2Icon className="h-4 w-4" />
|
||||
<span className="sr-only">Close</span>
|
||||
</DialogPrimitive.Close>
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ const DropdownMenuSubTrigger = React.forwardRef<
|
|||
<DropdownMenuPrimitive.SubTrigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent",
|
||||
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-hidden focus:bg-accent data-[state=open]:bg-accent",
|
||||
inset && "pl-8",
|
||||
className
|
||||
)}
|
||||
|
|
@ -88,7 +88,7 @@ const DropdownMenuItem = React.forwardRef<
|
|||
<DropdownMenuPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0",
|
||||
"relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden transition-colors focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0",
|
||||
inset && "pl-8",
|
||||
className
|
||||
)}
|
||||
|
|
@ -104,7 +104,7 @@ const DropdownMenuCheckboxItem = React.forwardRef<
|
|||
<DropdownMenuPrimitive.CheckboxItem
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-hidden transition-colors focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50",
|
||||
className
|
||||
)}
|
||||
checked={checked}
|
||||
|
|
@ -128,7 +128,7 @@ const DropdownMenuRadioItem = React.forwardRef<
|
|||
<DropdownMenuPrimitive.RadioItem
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-hidden transition-colors focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|||
<input
|
||||
type={type}
|
||||
className={cn(
|
||||
"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
|
||||
"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-xs transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className
|
||||
)}
|
||||
ref={ref}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ const SelectTrigger = React.forwardRef<
|
|||
<SelectPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
|
||||
"flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-xs ring-offset-background placeholder:text-muted-foreground focus:outline-hidden focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
|
|
@ -123,7 +123,7 @@ const SelectItem = React.forwardRef<
|
|||
<SelectPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue