From 85cbb100fe1086329d55c27114eeb71421434c5d Mon Sep 17 00:00:00 2001 From: swve Date: Wed, 26 Feb 2025 17:39:37 +0100 Subject: [PATCH] feat: Improve Assignment UI and File Upload Responsiveness --- .../Subs/TaskTypes/TaskFileObject.tsx | 125 +++++++++++------- .../Activities/Assignment/AssignmentBoxUI.tsx | 67 ++++++---- .../Assignment/AssignmentStudentActivity.tsx | 35 ++--- 3 files changed, 133 insertions(+), 94 deletions(-) diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskFileObject.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskFileObject.tsx index 53c8b4f5..33bf798b 100644 --- a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskFileObject.tsx +++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskFileObject.tsx @@ -44,6 +44,12 @@ export default function TaskFileObject({ view, user_id, assignmentTaskUUID }: Ta }); const handleFileChange = async (event: any) => { + // Check if user is authenticated + if (!access_token) { + setError('Authentication required. Please sign in to upload files.'); + return; + } + const file = event.target.files[0] setLocalUploadFile(file) @@ -69,21 +75,30 @@ export default function TaskFileObject({ view, user_id, assignmentTaskUUID }: Ta setIsLoading(false) setError('') } - } async function getAssignmentTaskSubmissionFromUserUI() { + if (!access_token) { + // Silently fail if not authenticated + return; + } + if (assignmentTaskUUID) { const res = await getAssignmentTaskSubmissionsMe(assignmentTaskUUID, assignment.assignment_object.assignment_uuid, access_token); if (res.success) { setUserSubmissions(res.data.task_submission); setInitialUserSubmissions(res.data.task_submission); } - } } const submitFC = async () => { + // Check if user is authenticated + if (!access_token) { + toast.error('Authentication required. Please sign in to submit your task.'); + return; + } + // Save the quiz to the server const values = { task_submission: userSubmissions, @@ -105,13 +120,17 @@ export default function TaskFileObject({ view, user_id, assignmentTaskUUID }: Ta }; async function getAssignmentTaskUI() { + if (!access_token) { + // Silently fail if not authenticated + return; + } + if (assignmentTaskUUID) { const res = await getAssignmentTask(assignmentTaskUUID, access_token); if (res.success) { setAssignmentTask(res.data); setAssignmentTaskOutsideProvider(res.data); } - } } @@ -129,6 +148,11 @@ export default function TaskFileObject({ view, user_id, assignmentTaskUUID }: Ta /* GRADING VIEW CODE */ const [userSubmissionObject, setUserSubmissionObject] = useState(null); async function getAssignmentTaskSubmissionFromIdentifiedUserUI() { + if (!access_token) { + // Silently fail if not authenticated + return; + } + if (assignmentTaskUUID && user_id) { const res = await getAssignmentTaskSubmissionsUser(assignmentTaskUUID, user_id, assignment.assignment_object.assignment_uuid, access_token); if (res.success) { @@ -136,7 +160,6 @@ export default function TaskFileObject({ view, user_id, assignmentTaskUUID }: Ta setUserSubmissionObject(res.data); setInitialUserSubmissions(res.data.task_submission); } - } } @@ -186,31 +209,29 @@ export default function TaskFileObject({ view, user_id, assignmentTaskUUID }: Ta return ( {view === 'teacher' && ( -
- +
+

User will be able to submit a file for this task, you'll be able to review it in the Submissions Tab

)} {view === 'custom-grading' && ( -
-
- +
+
+

Please download the file and grade it manually, then input the grade above

{userSubmissions.fileUUID && !isLoading && assignmentTaskUUID && ( -
- + 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'> +
+
-
- -
+
+ +
{`${userSubmissions.fileUUID.slice(0, 8)}...${userSubmissions.fileUUID.slice(-4)}`}
@@ -220,66 +241,72 @@ export default function TaskFileObject({ view, user_id, assignmentTaskUUID }: Ta )} {view === 'student' && ( <> -
-
-
-
+
+
+
+
{error && ( -
-
{error}
+
+
{error}
)} -
{localUploadFile && !isLoading && ( -
-
- +
+
+
-
- - -
- {localUploadFile.name} +
+ +
+ {localUploadFile.name.length > 20 + ? `${localUploadFile.name.slice(0, 10)}...${localUploadFile.name.slice(-10)}` + : localUploadFile.name}
)} {userSubmissions.fileUUID && !isLoading && !localUploadFile && ( -
-
- +
+
+
-
- - -
+
+ +
{`${userSubmissions.fileUUID.slice(0, 8)}...${userSubmissions.fileUUID.slice(-4)}`}
)} -
- -

Allowed formats : pdf, docx, mp4, jpg, jpeg, png, pptx, zip

+
+ +

Allowed formats: pdf, docx, mp4, jpg, jpeg, png, pptx, zip

- {isLoading ? ( -
+ {!access_token ? ( +
+
+ +
Please sign in to upload files
+
+
+ ) : isLoading ? ( +
-
- +
+ Loading
) : ( -
+
diff --git a/apps/web/components/Objects/Activities/Assignment/AssignmentBoxUI.tsx b/apps/web/components/Objects/Activities/Assignment/AssignmentBoxUI.tsx index 73070c8a..b7aab009 100644 --- a/apps/web/components/Objects/Activities/Assignment/AssignmentBoxUI.tsx +++ b/apps/web/components/Objects/Activities/Assignment/AssignmentBoxUI.tsx @@ -1,6 +1,7 @@ import { useAssignmentSubmission } from '@components/Contexts/Assignments/AssignmentSubmissionContext' import { BookPlus, BookUser, EllipsisVertical, FileUp, Forward, InfoIcon, ListTodo, Save } from 'lucide-react' import React, { useEffect } from 'react' +import { useLHSession } from '@components/Contexts/LHSessionContext' type AssignmentBoxProps = { type: 'quiz' | 'file' @@ -13,21 +14,25 @@ type AssignmentBoxProps = { gradeCustomFC?: (grade: number) => void showSavingDisclaimer?: boolean children: React.ReactNode - } function AssignmentBoxUI({ type, view, currentPoints, maxPoints, saveFC, submitFC, gradeFC, gradeCustomFC, showSavingDisclaimer, children }: AssignmentBoxProps) { const [customGrade, setCustomGrade] = React.useState(0) const submission = useAssignmentSubmission() as any + const session = useLHSession() as any + useEffect(() => { console.log(submission) - } - , [submission]) + }, [submission]) + + // Check if user is authenticated + const isAuthenticated = session?.status === 'authenticated' return ( -
-
-
+
+
+ {/* Left side with type and badges */} +
{type === 'quiz' &&
@@ -41,26 +46,27 @@ function AssignmentBoxUI({ type, view, currentPoints, maxPoints, saveFC, submitF
}
-
{view === 'teacher' && -
+

Teacher view

} {maxPoints && -
+

{maxPoints} points

}
-
+ + {/* Right side with buttons and actions */} +
{showSavingDisclaimer && -
+

Don't forget to save your progress

@@ -70,17 +76,17 @@ function AssignmentBoxUI({ type, view, currentPoints, maxPoints, saveFC, submitF {view === 'teacher' &&
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-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'>

Save

} - {/* Student button */} - {view === 'student' && submission && submission.length <= 0 && + {/* Student button - only show if authenticated */} + {view === 'student' && isAuthenticated && submission && submission.length <= 0 &&
submitFC && submitFC()} - 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 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'>

Save your progress

@@ -89,11 +95,11 @@ function AssignmentBoxUI({ type, view, currentPoints, maxPoints, saveFC, submitF {/* Grading button */} {view === 'grading' &&
-

Current points : {currentPoints}

+ 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'> +

Current points: {currentPoints}

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'> + 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'>

Grade

@@ -103,16 +109,21 @@ function AssignmentBoxUI({ type, view, currentPoints, maxPoints, saveFC, submitF {/* CustomGrading button */} {view === 'custom-grading' && maxPoints &&
-

Current points : {currentPoints}

- setCustomGrade(parseInt(e.target.value))} - placeholder={maxPoints.toString()} className='w-[100px] light-shadow text-sm py-0.5 outline outline-gray-200 rounded-lg px-2' type="number" /> -
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'> - -

Grade

+ 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'> +

Current points: {currentPoints}

+
+ setCustomGrade(parseInt(e.target.value))} + placeholder={maxPoints.toString()} + className='w-full sm:w-[100px] light-shadow text-sm py-0.5 outline outline-gray-200 rounded-lg px-2' + type="number" + /> +
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'> + +

Grade

+
} diff --git a/apps/web/components/Objects/Activities/Assignment/AssignmentStudentActivity.tsx b/apps/web/components/Objects/Activities/Assignment/AssignmentStudentActivity.tsx index c9eb6d53..5f22f415 100644 --- a/apps/web/components/Objects/Activities/Assignment/AssignmentStudentActivity.tsx +++ b/apps/web/components/Objects/Activities/Assignment/AssignmentStudentActivity.tsx @@ -18,38 +18,39 @@ function AssignmentStudentActivity() { return ( -
-
-
-
- +
+
+
+
+

Assignment

- +
-
+
-

Due Date

-

{assignments?.assignment_object?.due_date}

+

Due Date

+

{assignments?.assignment_object?.due_date}

-
+
+ {assignments && assignments?.assignment_tasks?.sort((a: any, b: any) => a.id - b.id).map((task: any, index: number) => { return (
-
-
+
+

Task {index + 1} :

-

{task.description}

+

{task.description}

-
+
alert(task.hint)} className='px-3 py-1 flex items-center nice-shadow bg-amber-50/40 text-amber-900 rounded-full space-x-2 cursor-pointer'> @@ -67,9 +68,9 @@ function AssignmentStudentActivity() { )} target='_blank' download={true} - className='px-3 py-1 flex items-center nice-shadow bg-cyan-50/40 text-cyan-900 rounded-full space-x-2 cursor-pointer'> + className='px-3 py-1 flex items-center nice-shadow bg-cyan-50/40 text-cyan-900 rounded-full space-x-1 md:space-x-2 cursor-pointer'> -
+
{task.reference_file && ( @@ -80,7 +81,7 @@ function AssignmentStudentActivity() {
-
+
{task.assignment_type === 'QUIZ' && } {task.assignment_type === 'FILE_SUBMISSION' && }