feat: Improve Assignment UI and File Upload Responsiveness

This commit is contained in:
swve 2025-02-26 17:39:37 +01:00
parent df4cc587ba
commit 85cbb100fe
3 changed files with 133 additions and 94 deletions

View file

@ -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<number>(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 (
<div className='flex flex-col px-6 py-4 nice-shadow rounded-md bg-slate-100/30'>
<div className='flex justify-between space-x-2 pb-2 text-slate-400 items-center'>
<div className='flex space-x-1 items-center'>
<div className='flex flex-col px-3 sm:px-6 py-4 nice-shadow rounded-md bg-slate-100/30'>
<div className='flex flex-col sm:flex-row sm:justify-between sm:space-x-2 pb-2 text-slate-400 sm:items-center'>
{/* Left side with type and badges */}
<div className='flex flex-wrap gap-2 items-center mb-2 sm:mb-0'>
<div className='text-lg font-semibold'>
{type === 'quiz' &&
<div className='flex space-x-1.5 items-center'>
@ -41,26 +46,27 @@ function AssignmentBoxUI({ type, view, currentPoints, maxPoints, saveFC, submitF
</div>}
</div>
<div className='flex items-center space-x-1'>
<EllipsisVertical size={15} />
</div>
{view === 'teacher' &&
<div className='flex bg-amber-200/20 text-xs rounded-full space-x-1 px-2 py-0.5 mx-auto font-bold outline items-center text-amber-600 outline-1 outline-amber-300/40'>
<div className='flex bg-amber-200/20 text-xs rounded-full space-x-1 px-2 py-0.5 font-bold outline items-center text-amber-600 outline-1 outline-amber-300/40'>
<BookUser size={12} />
<p>Teacher view</p>
</div>
}
{maxPoints &&
<div className='flex bg-emerald-200/20 text-xs rounded-full space-x-1 px-2 py-0.5 mx-auto font-bold outline items-center text-emerald-600 outline-1 outline-emerald-300/40'>
<div className='flex bg-emerald-200/20 text-xs rounded-full space-x-1 px-2 py-0.5 font-bold outline items-center text-emerald-600 outline-1 outline-emerald-300/40'>
<BookPlus size={12} />
<p>{maxPoints} points</p>
</div>
}
</div>
<div className='flex px-1 py-1 rounded-md items-center'>
{/* Right side with buttons and actions */}
<div className='flex flex-wrap gap-2 items-center'>
{showSavingDisclaimer &&
<div className='flex space-x-2 items-center font-semibold px-3 py-1 outline-dashed outline-red-200 text-red-400 mr-5 rounded-full'>
<div className='flex space-x-2 items-center font-semibold px-3 py-1 outline-dashed outline-red-200 text-red-400 sm:mr-5 rounded-full w-full sm:w-auto mb-2 sm:mb-0'>
<InfoIcon size={14} />
<p className='text-xs'>Don't forget to save your progress</p>
</div>
@ -70,17 +76,17 @@ 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-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 size={14} />
<p className='text-xs font-semibold'>Save</p>
</div>
}
{/* Student button */}
{view === 'student' && submission && submission.length <= 0 &&
{/* Student button - only show if authenticated */}
{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 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'>
<Forward size={14} />
<p className='text-xs font-semibold'>Save your progress</p>
</div>
@ -89,11 +95,11 @@ function AssignmentBoxUI({ type, view, currentPoints, maxPoints, saveFC, submitF
{/* Grading button */}
{view === 'grading' &&
<div
className='flex px-0.5 py-0.5 cursor-pointer rounded-md 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'>
<p className='font-semibold px-2 text-xs text-orange-700'>Current points : {currentPoints}</p>
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'>
<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'>
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'>
<BookPlus size={14} />
<p className='text-xs font-semibold'>Grade</p>
</div>
@ -103,16 +109,21 @@ function AssignmentBoxUI({ type, view, currentPoints, maxPoints, saveFC, submitF
{/* CustomGrading button */}
{view === 'custom-grading' && maxPoints &&
<div
className='flex px-0.5 py-0.5 cursor-pointer rounded-md 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'>
<p className='font-semibold px-2 text-xs text-orange-700'>Current points : {currentPoints}</p>
<input
onChange={(e) => 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" />
<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'>
<BookPlus size={14} />
<p className='text-xs font-semibold'>Grade</p>
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'>
<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
onChange={(e) => 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"
/>
<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'>
<BookPlus size={14} />
<p className='text-xs font-semibold'>Grade</p>
</div>
</div>
</div>
}

View file

@ -18,38 +18,39 @@ function AssignmentStudentActivity() {
return (
<div className='flex flex-col space-y-6'>
<div className='flex flex-row justify-center space-x-3 items-center '>
<div className='text-xs h-fit flex space-x-3 items-center '>
<div className='flex space-x-2 py-2 px-5 h-fit text-sm text-slate-700 bg-slate-100/5 rounded-full nice-shadow'>
<Backpack size={18} />
<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" />
<p className='font-semibold'>Assignment</p>
</div>
</div>
<div>
<div className='flex space-x-2 items-center'>
<EllipsisVertical className='text-slate-400' size={18} />
<EllipsisVertical className='text-slate-400 hidden md:block' size={18} />
<div className='flex space-x-2 items-center'>
<div className='flex space-x-2 text-xs items-center text-slate-400'>
<div className='flex space-x-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>
<p className='font-semibold'>Due Date</p>
<p className='font-semibold'>{assignments?.assignment_object?.due_date}</p>
</div>
</div>
</div>
</div>
</div>
<div className='w-full rounded-full bg-slate-500/5 nice-shadow h-[2px]'></div>
{assignments && assignments?.assignment_tasks?.sort((a: any, b: any) => a.id - b.id).map((task: any, index: number) => {
return (
<div className='flex flex-col space-y-2' key={task.assignment_task_uuid}>
<div className='flex justify-between py-2'>
<div className='flex space-x-2 font-semibold text-slate-800'>
<div className='flex flex-col md:flex-row md:justify-between py-2 space-y-2 md:space-y-0'>
<div className='flex flex-wrap space-x-2 font-semibold text-slate-800'>
<p>Task {index + 1} : </p>
<p className='text-slate-500'>{task.description}</p>
<p className='text-slate-500 break-words'>{task.description}</p>
</div>
<div className='flex space-x-2'>
<div className='flex flex-wrap gap-2'>
<div
onClick={() => 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'>
<Download size={13} />
<div className='flex items-center space-x-2'>
<div className='flex items-center space-x-1 md:space-x-2'>
{task.reference_file && (
<span className='relative'>
<span className='absolute right-0 top-0 block h-2 w-2 rounded-full ring-2 ring-white bg-green-400'></span>
@ -80,7 +81,7 @@ function AssignmentStudentActivity() {
</Link>
</div>
</div>
<div>
<div className='w-full'>
{task.assignment_type === 'QUIZ' && <TaskQuizObject key={task.assignment_task_uuid} view='student' assignmentTaskUUID={task.assignment_task_uuid} />}
{task.assignment_type === 'FILE_SUBMISSION' && <TaskFileObject key={task.assignment_task_uuid} view='student' assignmentTaskUUID={task.assignment_task_uuid} />}
</div>